it-swarm.com.de

UIView mit abgerundeten Ecken und Schlagschatten?

Ich möchte eine benutzerdefinierte UIView...: Ich wollte nur eine leere weiße Ansicht mit abgerundeten Ecken und einem leichten Schlagschatten (ohne Lichteffekt). Ich kann jeden dieser Schritte einzeln ausführen, aber es treten die üblichen clipToBounds/maskToBounds Konflikte auf.

355
Aditya Vaidyam

Das folgende Codefragment fügt v, einem UIView einen Rahmen, einen Rahmenradius und einen Schlagschatten hinzu:

// border radius
[v.layer setCornerRadius:30.0f];

// border
[v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[v.layer setBorderWidth:1.5f];

// drop shadow
[v.layer setShadowColor:[UIColor blackColor].CGColor];
[v.layer setShadowOpacity:0.8];
[v.layer setShadowRadius:3.0];
[v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];

Sie können die Einstellungen an Ihre Bedürfnisse anpassen.

Fügen Sie Ihrem Projekt auch das QuartzCore-Framework hinzu und:

#import <QuartzCore/QuartzCore.h>

Siehe meine andere Antwort bezüglich masksToBounds.


Hinweis

Dies funktioniert möglicherweise nicht in allen Fällen. Wenn Sie feststellen, dass diese Methode andere Zeichenvorgänge beeinträchtigt, die Sie ausführen, lesen Sie diese Antwort .

425
Evan Mulawski

Swift

enter image description here

// corner radius
blueView.layer.cornerRadius = 10

// border
blueView.layer.borderWidth = 1.0
blueView.layer.borderColor = UIColor.black.cgColor

// shadow
blueView.layer.shadowColor = UIColor.black.cgColor
blueView.layer.shadowOffset = CGSize(width: 3, height: 3)
blueView.layer.shadowOpacity = 0.7
blueView.layer.shadowRadius = 4.0

Möglichkeiten ausloten

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

Problem 1: Der Schatten wird abgeschnitten

Was ist, wenn es Unterebenen oder Unteransichten (wie ein Bild) gibt, deren Inhalt wir an die Grenzen unserer Ansicht anpassen möchten?

enter image description here

Wir können dies erreichen mit

blueView.layer.masksToBounds = true

(Alternative, blueView.clipsToBounds = true ergibt gleiches Ergebnis .)

enter image description here

Aber, oh nein ! Der Schatten wurde auch abgeschnitten, weil er außerhalb der Grenzen liegt! Was ist zu tun? Was ist zu tun?

Lösung

Verwenden Sie separate Ansichten für den Schatten und den Rand. Die Basisansicht ist transparent und hat den Schatten. In der Rahmenansicht werden alle anderen Subinhalte an den Rahmen gekürzt.

// add the shadow to the base view
baseView.backgroundColor = UIColor.clear
baseView.layer.shadowColor = UIColor.black.cgColor
baseView.layer.shadowOffset = CGSize(width: 3, height: 3)
baseView.layer.shadowOpacity = 0.7
baseView.layer.shadowRadius = 4.0

// add the border to subview
let borderView = UIView()
borderView.frame = baseView.bounds
borderView.layer.cornerRadius = 10
borderView.layer.borderColor = UIColor.black.cgColor
borderView.layer.borderWidth = 1.0
borderView.layer.masksToBounds = true
baseView.addSubview(borderView)

// add any other subcontent that you want clipped
let otherSubContent = UIImageView()
otherSubContent.image = UIImage(named: "lion")
otherSubContent.frame = borderView.bounds
borderView.addSubview(otherSubContent)

Dies ergibt folgendes Ergebnis:

enter image description here

Problem 2: Schlechte Leistung

Das Hinzufügen von abgerundeten Ecken und Schatten kann ein Leistungstreffer sein. Sie können die Leistung verbessern, indem Sie einen vordefinierten Pfad für den Schatten verwenden und angeben, dass er gerastert werden soll. Der folgende Code kann dem obigen Beispiel hinzugefügt werden.

baseView.layer.shadowPath = UIBezierPath(roundedRect: baseView.bounds, cornerRadius: 10).cgPath
baseView.layer.shouldRasterize = true
baseView.layer.rasterizationScale = UIScreen.main.scale

Siehe dieser Beitrag für weitere Details. Siehe auch hier und hier .

Diese Antwort wurde mit Swift 4 und Xcode 9. getestet

567
Suragch

Eine Möglichkeit, dies zu tun, besteht darin, die Ansicht mit abgerundeten Ecken in eine Ansicht mit dem Schlagschatten zu setzen.

UIView* roundedView = [[UIView alloc] initWithFrame: frame];
roundedView.layer.cornerRadius = 5.0;
roundedView.layer.masksToBounds = YES;

UIView* shadowView = [[UIView alloc] initWithFrame: frame];
shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
shadowView.layer.shadowRadius = 5.0;
shadowView.layer.shadowOffset = CGSizeMake(3.0, 3.0);
shadowView.layer.shadowOpacity = 1.0;
[shadowView addSubview: roundedView];

Dann können Sie die shadowView hinzufügen, wo immer Sie möchten.

76
David C.

Einfache Swift 4 Lösung basierend auf Ades Antwort ohne zusätzliche Subviews, Subclassing oder extra Fiddling:

extension UIView {

    func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {
        layer.masksToBounds = false
        layer.shadowOffset = offset
        layer.shadowColor = color.cgColor
        layer.shadowRadius = radius
        layer.shadowOpacity = opacity

        let backgroundCGColor = backgroundColor?.cgColor
        backgroundColor = nil
        layer.backgroundColor =  backgroundCGColor
    }
}

Beachten Sie, dass Sie Ihre Ansicht mit Eckenradius und anderen Eigenschaften einrichten sollten, bevor Sie addShadow aufrufen .

Das rufen Sie direkt von viewDidLoad wie folgt auf:

btnBottom.addShadow(offset: CGSize.init(width: 0, height: 3), color: UIColor.black, radius: 2.0, opacity: 0.35)

Endergebnis:

result

Super einfach und unkompliziert!

BEARBEITEN: Ich sehe viele Leute, die Probleme mit diesem Beispiel haben, deshalb habe ich ein einfaches Xcode-Projekt erstellt, um zu veranschaulichen, wie es sein sollte gebraucht .

42

Das hat bei mir funktioniert. Der Trick bestand darin, die Hintergrundfarbe aus der Hauptansicht in die Ebene zu verschieben.

CALayer *layer = view.layer;
layer.cornerRadius = 15.0f;
layer.masksToBounds = NO;

layer.shadowOffset = CGSizeMake(0, 3);
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowRadius = 2.0f;
layer.shadowOpacity = 0.35f;
layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:layer.cornerRadius] CGPath];

CGColorRef  bColor = view.backgroundColor.CGColor;
view.backgroundColor = nil;
layer.backgroundColor =  bColor ;
39
Ade

Ich habe das Problem mit dem folgenden Trick gelöst, als ich den Schattenpfad für die Containeransicht zugewiesen habe:

[UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]

Beachten Sie, dass der dem Schatten zugewiesene Pfad ein abgerundetes Rechteck mit demselben Eckenradius wie der Hintergrund ist, den die Zelle enthält:

//this is the border for the UIView that is added to a cell
cell.backgroundView.layer.cornerRadius = 12;
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.borderColor = [UIColor darkGrayColor].CGColor;
cell.backgroundView.layer.borderWidth = 1;

//this is the shadow around the cell itself (cannot have round corners with borders and shadow, need to use two views
cell.layer.shadowRadius = 2;
cell.layer.cornerRadius = 12;
cell.layer.masksToBounds = NO;
[[cell layer] setShadowColor:[[UIColor darkGrayColor] CGColor]];

[[cell layer] setShadowOffset:CGSizeMake(0.0,0.0)];
[[cell layer] setShadowOpacity:1.0];

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12];
[[cell layer] setShadowPath:[path CGPath]];
26
Alex Stone

Wenn Sie wegen der gerundeten corners vs. subviews vs. masksToBounds Probleme haben, versuchen Sie es mit meiner Funktion:

- (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed
    shadowFrame.size.width = 0.f;
    shadowFrame.size.height = 0.f;
    shadowFrame.Origin.x = 0.f;
    shadowFrame.Origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.userInteractionEnabled = NO; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
    [shadow addSubview:view];
    return shadow;
}

nenn es aus deiner sicht. ob Ihre Ansicht abgerundete Ecken hat, egal welche Größe, welche Form - es wird ein netter Schatten gezeichnet.

Behalten Sie einfach den Rückgabewert der Funktion bei, damit Sie darauf verweisen können, wenn Sie die Tabelle entfernen möchten (oder verwenden Sie zum Beispiel insertSubview:aboveView:)

17
daniel.gindi

Unter Verwendung von Swift 4 und Xcode 9 ist dies ein funktionierendes Beispiel für das Runden eines ImageView mit einem Schlagschatten und eine Grenze.

    //set dimensions and position of image (in this case, centered)
    let imageHeight: CGFloat = 150, imageWidth: CGFloat = 150
    let xPosition = (self.view.frame.width / 2) - (imageWidth / 2)
    let yPosition = (self.view.frame.height / 2) - (imageHeight / 2)

    //set desired corner radius
    let cornerRadius: CGFloat = 20

    //create container for the image
    let imageContainer = UIView(frame: CGRect(x: xPosition, y: yPosition, width: imageWidth, height: imageHeight))

    //configure the container
    imageContainer.clipsToBounds = false
    imageContainer.layer.shadowColor = UIColor.black.cgColor
    imageContainer.layer.shadowOpacity = 1
    imageContainer.layer.shadowOffset = CGSize(width: 3.0, height: 3.0)
    imageContainer.layer.shadowRadius = 5
    imageContainer.layer.shadowPath = UIBezierPath(roundedRect: imageContainer.bounds, cornerRadius: cornerRadius).cgPath

    //create imageView
    let imageView = UIImageView(frame: imageContainer.bounds)

    //configure the imageView
    imageView.clipsToBounds = true
    imageView.layer.cornerRadius = cornerRadius
    //add a border (if required)
    imageView.layer.borderColor = UIColor.black.cgColor
    imageView.layer.borderWidth = 1.0
    //set the image
    imageView.image = UIImage(named: "bird")

    //add the views to the superview
    view.addSubview(imageContainer)
    imageContainer.addSubview(imageView)

enter image description here

Wenn Sie möchten, dass das Bild kreisförmig ist: (und ohne Rand angezeigt)

let cornerRadius = imageWidth / 2

enter image description here

10
rbaldwin

Ich habe einen Helfer auf UIView erstellt

@interface UIView (Helper)

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset;
@end

sie können es so nennen

[self.view roundCornerswithRadius:5 andShadowOffset:5];

Hier ist die Implementierung

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset
{
    const float CORNER_RADIUS = cornerRadius;
    const float SHADOW_OFFSET = shadowOffset;
    const float SHADOW_OPACITY = 0.5;
    const float SHADOW_RADIUS = 3.0;

    UIView *superView = self.superview;

    CGRect oldBackgroundFrame = self.frame;
    [self removeFromSuperview];

    CGRect frameForShadowView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
    UIView *shadowView = [[UIView alloc] initWithFrame:frameForShadowView];
    [shadowView.layer setShadowOpacity:SHADOW_OPACITY];
    [shadowView.layer setShadowRadius:SHADOW_RADIUS];
    [shadowView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];

    [self.layer setCornerRadius:CORNER_RADIUS];
    [self.layer setMasksToBounds:YES];

    [shadowView addSubview:self];
    [superView addSubview:shadowView];

}
7
Zayin Krige

Sie müssen shadowView und roundView verwenden

enter image description here

shadowView

  • Must hat Hintergrundfarbe
  • Sollte hinter roundView liegen
  • Der Trick besteht darin, shadowView ein wenig nach innen zu legen, und sein Schatten muss nach außen leuchten. Passen Sie das insets so an, dass shadowView hinter roundView vollständig unsichtbar ist

roundView

  • Teilansichten müssen geschnitten werden

Der Code

addSubviews(shadowView, roundView)
roundView.addSubviews(titleLabel, subtitleLabel, imageView)

// need inset
shadowView.pinEdges(view: self, inset: UIEdgeInsets(constraintInsets: 2))
roundView.pinEdges(view: self)

do {
  shadowView.backgroundColor = .white // need background
  let layer = shadowView.layer
  layer.shadowColor = UIColor.black.cgColor
  layer.shadowRadius = 3
  layer.shadowOffset = CGSize(width: 3, height: 3)
  layer.shadowOpacity = 0.7
  layer.shouldRasterize = true
}

do {
  roundView.backgroundColor = .white
  let layer = roundView.layer
  layer.masksToBounds = true
  layer.cornerRadius = 5
}

Oder Sie können dies einfach unten tun, ohne clipToBounds/maskToBounds

layer.shadowColor = UIColor.gray.cgColor
layer.shadowOffset = CGSize(width: 3, height: 3)
layer.shadowOpacity = 0.8
5
onmyway133

Nach einem ganzen Tag Recherche über die Rundumansicht mit Schatten bin ich froh, hier meine benutzerdefinierte Ansichtsklasse veröffentlichen zu können. Ich hoffe, diese Frage zu beenden:

RoundCornerShadowView.h

#import <UIKit/UIKit.h>

@interface RoundCornerShadowView : UIView

@end

RoundCornerShadowView.m

#import "RoundCornerShadowView.h"

@implementation RoundCornerShadowView

// *** must override this method, not the other method ***
// otherwise, the background corner doesn't disappear....
// @2015/05/29
-(void) layoutSubviews {
    [super layoutSubviews];//is must to ensure rightly layout children view

    //1. first, create Inner layer with content
    CALayer *innerView = [CALayer layer];
    innerView.frame = CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height);
    //instead of: innerView.frame = self.frame;
    innerView.borderWidth = 1.0f;
    innerView.cornerRadius = 6.0f;
    innerView.masksToBounds = YES;
    innerView.borderColor = [[UIColor lightGrayColor] CGColor];
    innerView.backgroundColor = [[UIColor whiteColor] CGColor];
    //put the layer to the BOTTOM of layers is also a MUST step...
    //otherwise this layer will overlay the sub uiviews in current uiview...
    [self.layer insertSublayer:innerView atIndex:0];

    //2. then, create shadow with self layer
    self.layer.masksToBounds = NO;
    self.layer.shadowColor = [[UIColor darkGrayColor] CGColor];
    self.layer.shadowOpacity = 0.4f;
    //shadow length
    self.layer.shadowRadius = 2.0f;
    //no offset
    self.layer.shadowOffset = CGSizeMake(0, 0);
    //right down shadow
    //[self.layer setShadowOffset: CGSizeMake(1.0f, 1.0f)];

    //3. last but important, MUST clear current view background color, or the color will show in the corner!
    self.backgroundColor = [UIColor clearColor];
}

@end

sie müssen also KEINE Unteransicht in der Ansicht oder darunter in der Zielansicht hinzufügen, sondern nur eine Ebene in der aktuellen Ansicht hinzufügen und 3 Schritte ausführen, um die Ansicht fertigzustellen!

schauen Sie sich die Kommentare im Code genau an, es ist hilfreich, die Komponente zu verstehen!

5
lwz7512

Etwas schnell getestet in Swift 4

import UIKit

extension UIView {
    @IBInspectable var dropShadow: Bool {
        set{
            if newValue {
                layer.shadowColor = UIColor.black.cgColor
                layer.shadowOpacity = 0.4
                layer.shadowRadius = 1
                layer.shadowOffset = CGSize.zero
            } else {
                layer.shadowColor = UIColor.clear.cgColor
                layer.shadowOpacity = 0
                layer.shadowRadius = 0
                layer.shadowOffset = CGSize.zero
            }
        }
        get {
            return layer.shadowOpacity > 0
        }
    }
}

Produziert

enter image description here

Wenn Sie es im Inspektor wie folgt aktivieren:

enter image description here

Es wird das benutzerdefinierte Laufzeitattribut hinzugefügt, was zu folgenden Ergebnissen führt:

enter image description here

(Ich habe vorher das cornerRadius = 8)

:)

4
dGambit

Swift 3 & IBInspectable Lösung:
Inspiriert von Ades Lösung

Erstellen Sie zunächst eine UIView-Erweiterung:

//
//  UIView-Extension.Swift
//  

import Foundation
import UIKit

@IBDesignable
extension UIView {
     // Shadow
     @IBInspectable var shadow: Bool {
          get {
               return layer.shadowOpacity > 0.0
          }
          set {
               if newValue == true {
                    self.addShadow()
               }
          }
     }

     fileprivate func addShadow(shadowColor: CGColor = UIColor.black.cgColor, shadowOffset: CGSize = CGSize(width: 3.0, height: 3.0), shadowOpacity: Float = 0.35, shadowRadius: CGFloat = 5.0) {
          let layer = self.layer
          layer.masksToBounds = false

          layer.shadowColor = shadowColor
          layer.shadowOffset = shadowOffset
          layer.shadowRadius = shadowRadius
          layer.shadowOpacity = shadowOpacity
          layer.shadowPath = UIBezierPath(roundedRect: layer.bounds, cornerRadius: layer.cornerRadius).cgPath

          let backgroundColor = self.backgroundColor?.cgColor
          self.backgroundColor = nil
          layer.backgroundColor =  backgroundColor
     }


     // Corner radius
     @IBInspectable var circle: Bool {
          get {
               return layer.cornerRadius == self.bounds.width*0.5
          }
          set {
               if newValue == true {
                    self.cornerRadius = self.bounds.width*0.5
               }
          }
     }

     @IBInspectable var cornerRadius: CGFloat {
          get {
               return self.layer.cornerRadius
          }

          set {
               self.layer.cornerRadius = newValue
          }
     }


     // Borders
     // Border width
     @IBInspectable
     public var borderWidth: CGFloat {
          set {
               layer.borderWidth = newValue
          }

          get {
               return layer.borderWidth
          }
     }

     // Border color
     @IBInspectable
     public var borderColor: UIColor? {
          set {
               layer.borderColor = newValue?.cgColor
          }

          get {
               if let borderColor = layer.borderColor {
                    return UIColor(cgColor: borderColor)
               }
               return nil
          }
     }
}

Wählen Sie dann einfach Ihr UIView in der Interface Builder-Einstellung shadow ON und corner radius , Wie unten:

Selecting your UIView

Setting shadow ON & corner radius

Das Ergebnis!

Result

4
Tom Calmon

Hier ist meine Version in Swift 3 für eine UIView

let corners:UIRectCorner = [.bottomLeft, .topRight]
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()

mask.path = path.cgPath
mask.fillColor = UIColor.white.cgColor

let shadowLayer = CAShapeLayer()
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowOffset = CGSize(width: 0.0, height: 4.0)
shadowLayer.shadowRadius = 6.0
shadowLayer.shadowOpacity = 0.25
shadowLayer.shadowPath = mask.path

self.layer.insertSublayer(shadowLayer, at: 0)
self.layer.insertSublayer(mask, at: 1)
3
Yung Dai

Swift 4: Unterklasse von UIView erstellen

class ShadowView: UIView {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // corner radius
        self.layer.cornerRadius = 10

        // border
        self.layer.borderWidth = 1.0
        self.layer.borderColor = UIColor.black.cgColor

        // shadow
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 3, height: 3)
        self.layer.shadowOpacity = 0.7
        self.layer.shadowRadius = 4.0
    }

}

Verwenden ..

Use Class Shadow View

3
benmore99

Schatten + Rand + Eckenradius enter image description here

    scrollview.backgroundColor = [UIColor whiteColor]; 
    CALayer *ScrlViewLayer = [scrollview layer];
    [ScrlViewLayer setMasksToBounds:NO ];
    [ScrlViewLayer setShadowColor:[[UIColor lightGrayColor] CGColor]];
    [ScrlViewLayer setShadowOpacity:1.0 ];
    [ScrlViewLayer setShadowRadius:6.0 ];
    [ScrlViewLayer setShadowOffset:CGSizeMake( 0 , 0 )];
    [ScrlViewLayer setShouldRasterize:YES];
    [ScrlViewLayer setCornerRadius:5.0];
    [ScrlViewLayer setBorderColor:[UIColor lightGrayColor].CGColor];
    [ScrlViewLayer setBorderWidth:1.0];
    [ScrlViewLayer setShadowPath:[UIBezierPath bezierPathWithRect:scrollview.bounds].CGPath];
3
Darshit Shah

Alter Thread noch aktuell ...

Ich habe die Methode von Daniel Gindi überarbeitet, um sie auch für Schaltflächen usw. verwenden zu können. Wenn jemand abgerundete Ecken benötigt oder abgerundete Ecken und einen Rand kombinieren möchte, muss dies auf der Ebene der Ansicht festgelegt werden, die an diese Methode übergeben wird. Ich habe auch die Rasterung so eingestellt, dass sie etwas schneller wird.

+ (UIView*)putView:(UIView*)view insideShadowWithColor:(CGColorRef)color 
                                 andRadius:(CGFloat)shadowRadius 
                                 andOffset:(CGSize)shadowOffset 
                                 andOpacity:(CGFloat)shadowOpacity
{
    // Must have same position like "view"
    UIView *shadow = [[UIView alloc] initWithFrame:view.frame]; 

    shadow.layer.contentsScale = [UIScreen mainScreen].scale;
    shadow.userInteractionEnabled = YES; // Modify this if needed
    shadow.layer.shadowColor = color;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    shadow.layer.rasterizationScale = [UIScreen mainScreen].scale;
    shadow.layer.shouldRasterize = YES;

    [view.superview insertSubview:shadow belowSubview:view];
    [shadow addSubview:view];

    // Move view to the top left corner inside the shadowview 
    // ---> Buttons etc are working again :)
    view.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);

    return shadow;
}
2
NickBln

Hier ist die Lösung für das Konfliktproblem masksToBounds, sie funktioniert bei mir.

Nachdem Sie corderRadius/borderColor/shadow usw. festgelegt haben, setzen Sie masksToBounds auf NO:

v.layer.masksToBounds = NO;
2
Shaopeng Wang

Das Folgende funktionierte am besten für mich (dieser Code liegt in der UIView-Erweiterung, also bezeichnet self ein UIView, zu dem wir einen Schatten und eine runde Ecke hinzufügen müssen)

- (void)addShadowViewWithCornerRadius:(CGFloat)radius {

UIView *container = self.superview;

if (!container) {
    return;
}

UIView *shadowView = [[UIView alloc] init];
shadowView.translatesAutoresizingMaskIntoConstraints = NO;
shadowView.backgroundColor = [UIColor lightGrayColor];
shadowView.layer.cornerRadius = radius;
shadowView.layer.masksToBounds = YES;

[container addSubview:shadowView];
[container bringSubviewToFront:shadowView];

[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeWidth
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeWidth
                                                     multiplier:1.0
                                                       constant:0.0]];
[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeLeading
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeLeading
                                                     multiplier:1.0
                                                       constant:2.0]];

[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeHeight
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeHeight
                                                     multiplier:1.0
                                                       constant:0.0]];
[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeTop
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeTop
                                                     multiplier:1.0
                                                       constant:2.0]];
[container sendSubviewToBack:shadowView];
}

Der Hauptunterschied zwischen diesem und anderen Codebeispielen besteht darin, dass hierdurch die Schattenansicht als Geschwisteransicht (im Gegensatz zum Hinzufügen der aktuellen Ansicht als Unteransicht der Schattenansicht) hinzugefügt wird, sodass die vorhandene Ansicht nicht mehr geändert werden muss Hierarchie in irgendeiner Weise.

2
Mehul Parmar

Nun, wenn Sie Ihre Schreibfedern nicht ändern und die Hierarchie nicht wie von David C. vorgeschlagen anzeigen möchten, erledigt diese Methode dies für Sie. Um Ihrem UIImageView abgerundete Ecken und Schatten hinzuzufügen, verwenden Sie einfach diese Methode, zum Beispiel:

[Utils roundCornersForImageView:myImageView withCornerRadius:6.0 
andShadowOffset:2.0];

(!) Aus Performancegründen halte ich es nicht für eine gute Idee, diesen Code in UITableView zu verwenden, da dieser Code die Ansichtshierarchie ändert. Daher werde ich vorschlagen, Ihre Schreibfeder zu ändern und eine Containeransicht für den Schatteneffekt hinzuzufügen und Davic C.-Code zu verwenden.

+ (void)roundCornersForImageView:(UIImageView *)imageView 
withCornerRadius:(float)cornerRadius andShadowOffset:(float)shadowOffset
{
    const float CORNER_RADIUS = cornerRadius;
    const float BORDER_WIDTH = 1.0; 
    const float SHADOW_OFFSET = shadowOffset;
    const float SHADOW_OPACITY = 0.8;
    const float SHADOW_RADIUS = 3.0;

    //Our old image now is just background image view with shadow
    UIImageView *backgroundImageView = imageView;
    UIView *superView = backgroundImageView.superview;

    //Make wider actual visible rect taking into account shadow
    //offset
    CGRect oldBackgroundFrame = backgroundImageView.frame;
    CGRect newBackgroundFrame = CGRectMake(oldBackgroundFrame.Origin.x, oldBackgroundFrame.Origin.y, oldBackgroundFrame.size.width + SHADOW_OFFSET, oldBackgroundFrame.size.height + SHADOW_OFFSET);
    [backgroundImageView removeFromSuperview];
    backgroundImageView.frame = newBackgroundFrame;        

    //Make new UIImageView with rounded corners and put our old image
    CGRect frameForRoundedImageView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
    UIImageView *roundedImageView = [[UIImageView alloc]initWithFrame:frameForRoundedImageView];
    roundedImageView.image = imageView.image;
    [roundedImageView.layer setCornerRadius:CORNER_RADIUS];
    [roundedImageView.layer setBorderColor:[UIColor lightGrayColor].CGColor];        
    [roundedImageView.layer setBorderWidth:BORDER_WIDTH]; 
    [roundedImageView.layer setMasksToBounds:YES];

    //Set shadow preferences
    [backgroundImageView setImage:nil];
    [backgroundImageView.layer setShadowColor:[UIColor blackColor].CGColor];
    [backgroundImageView.layer setShadowOpacity:SHADOW_OPACITY];
    [backgroundImageView.layer setShadowRadius:SHADOW_RADIUS];
    [backgroundImageView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];   

    //Add out two image views back to the view hierarchy.
    [backgroundImageView addSubview:roundedImageView];
    [superView addSubview:backgroundImageView];   
}    
2
Roman Minenok

Ich habe so viele Lösungen aus diesem Beitrag ausprobiert und am Ende die folgende Lösung gefunden. Dies ist vollständiger Beweis Lösung es sei denn, Sie müssen Schatten auf eine klare Farbansicht werfen.

- (void)addShadowWithRadius:(CGFloat)shadowRadius withOpacity:(CGFloat)shadowOpacity withOffset:(CGSize)shadowOffset withColor:(UIColor *)shadowColor withCornerradius:(CGFloat)cornerRadius
{
    UIView *viewShadow = [[UIView alloc]initWithFrame:self.frame];
    viewShadow.backgroundColor = [UIColor whiteColor];
    viewShadow.layer.shadowColor = shadowColor.CGColor;
    viewShadow.layer.shadowOffset = shadowOffset;
    viewShadow.layer.shadowRadius = shadowRadius;
    viewShadow.layer.shadowOpacity = shadowOpacity;
    viewShadow.layer.cornerRadius = cornerRadius;
    viewShadow.layer.masksToBounds = NO;
    [self.superview insertSubview:viewShadow belowSubview:self];

    [viewShadow setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:viewShadow attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:viewShadow attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];
    [self layoutIfNeeded];

    self.layer.cornerRadius = cornerRadius;
    self.layer.masksToBounds = YES;
}
1
Mahesh Agrawal

Sie müssen zwei UIViews verwenden, um dies zu erreichen. Ein UIView funktioniert wie ein Schatten und ein anderes für einen abgerundeten Rand.

Hier ist ein Code-Schnipsel ein Class Method mit Hilfe eines protocol:

@implementation UIMethods

+ (UIView *)genComposeButton:(UIViewController <UIComposeButtonDelegate> *)observer;
{
    UIView *shadow = [[UIView alloc]init];
    shadow.layer.cornerRadius = 5.0;
    shadow.layer.shadowColor = [[UIColor blackColor] CGColor];
    shadow.layer.shadowOpacity = 1.0;
    shadow.layer.shadowRadius = 10.0;
    shadow.layer.shadowOffset = CGSizeMake(0.0f, -0.5f);

    UIButton *btnCompose = [[UIButton alloc]initWithFrame:CGRectMake(0, 0,60, 60)];
    [btnCompose setUserInteractionEnabled:YES];
    btnCompose.layer.cornerRadius = 30;
    btnCompose.layer.masksToBounds = YES;
    [btnCompose setImage:[UIImage imageNamed:@"60x60"] forState:UIControlStateNormal];
    [btnCompose addTarget:observer action:@selector(btnCompose_click:) forControlEvents:UIControlEventTouchUpInside];
    [shadow addSubview:btnCompose];
    return shadow;
}

Im obigen Code btnCompose_click: wird ein @required Methode delegieren, die beim Klicken auf die Schaltfläche ausgelöst wird.

Und hier habe ich meinem UIViewController eine Schaltfläche hinzugefügt:

UIView *btnCompose = [UIMethods genComposeButton:self];
btnCompose.frame = CGRectMake(self.view.frame.size.width - 75,
                          self.view.frame.size.height - 75,
                          60, 60);
[self.view addSubview:btnCompose];

Das Ergebnis sieht dann so aus:

enter image description here

1
Vaibhav Saran

die Antwort von daniel.gindi hat den Trick für mich getan! (+1 daniel) Ich musste jedoch geringfügige Anpassungen vornehmen. Ändern Sie die shadowFrame-Größe so, dass sie mit der Frame-Größe der Ansicht übereinstimmt, und aktivieren Sie die Benutzerinteraktion. Hier ist der aktualisierte Code:

+ (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed

    // Modified this line
    shadowFrame.size = CGSizeMake(view.frame.size.width, view.frame.size.height);

    shadowFrame.Origin.x = 0.f;
    shadowFrame.Origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];

    // Modified this line
    shadow.userInteractionEnabled = YES;
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;

    [shadow addSubview:view];
    return shadow;
}

Ich möchte hinzufügen, dass ich in meinem Fall versucht habe, dies einem Ansichtscontroller eines Drittanbieters hinzuzufügen, d. H. Ich hatte keine direkte Kontrolle über den Code. So habe ich die obige Funktion verwendet:

UIView *shadow = [self putView:vc.view 
         insideShadowWithColor:[UIColor blackColor]
                     andRadius:5.0 
                     andOffset:CGSizeMake(0.0, 0.0) 
                    andOpacity:1.0];
vc.view = shadow;
vc.view.layer.cornerRadius = 5.0;
vc.view.layer.masksToBounds = YES;
1
Digitrance

Ich ändere den Code von daniel.gindi

Das ist alles was Sie brauchen, um es zum Laufen zu bringen.

+ (void)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andBlur:         (CGFloat)blur andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame = view.frame;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.backgroundColor = [UIColor redColor];
    shadow.userInteractionEnabled = YES; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = blur;
    shadow.layer.cornerRadius = view.layer.cornerRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
}
1
Carlos López

Sie müssen masksToBounds = true Für die Kombination von corderRadiusshadowRadius hinzufügen.

button.layer.masksToBounds = false;
extension UIView {
    func dropRoundedShadowForAllSides() {
        let backgroundView = UIView(frame:self.frame)
        let radius = frame.height/2
        backgroundView.layer.masksToBounds = false
        self.layer.masksToBounds = true
        backgroundView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
        backgroundView.layer.shadowRadius = 4
        backgroundView.layer.shadowOpacity = 0.4

        let path = UIBezierPath()

        // Start at the Top Left Corner + radius distance
        path.move(to: CGPoint(x: 2*radius, y: 0.0))

        // Move to the Top Right Corner - radius distance
        path.addLine(to: CGPoint(x: backgroundView.frame.size.width - radius, y: 0.0))

        // Move to top right corner + radius down as curve
        let centerPoint1 = CGPoint(x:backgroundView.frame.size.width - radius,y:radius)
        path.addArc(withCenter: centerPoint1, radius: radius, startAngle: 3*(.pi/2), endAngle: 0, clockwise: true)

        // Move to the Bottom Right Corner - radius
        path.addLine(to: CGPoint(x: backgroundView.frame.size.width, y: backgroundView.frame.size.height - radius))

        // Move to top right corner + radius left as curve
        let centerPoint2 = CGPoint(x:backgroundView.frame.size.width - radius,y:backgroundView.frame.size.height - radius)
        path.addArc(withCenter: centerPoint2, radius: radius, startAngle: 0, endAngle: .pi/2, clockwise: true)

        // Move to the Bottom Left Corner - radius
        path.addLine(to: CGPoint(x: radius, y: backgroundView.frame.size.height))

        // Move to left right corner - radius up as curve
        let centerPoint3 = CGPoint(x:radius,y:backgroundView.frame.size.height - radius)
        path.addArc(withCenter: centerPoint3, radius: radius, startAngle: .pi/2, endAngle: .pi, clockwise: true)

        // Move to the top Left Corner - radius
        path.addLine(to: CGPoint(x: 0, y: radius))

        // Move to top right corner + radius down as curve
        let centerPoint4 = CGPoint(x:radius,y:radius)
        path.addArc(withCenter: centerPoint4, radius: radius, startAngle: .pi, endAngle: 3 * (.pi/2), clockwise: true)

        path.close()

        backgroundView.layer.shadowPath = path.cgPath
        if let superView = self.superview {
            superView.addSubview(backgroundView)
            superView.sendSubview(toBack: backgroundView)
            superView.bringSubview(toFront: self)
        }

    }
}
0
jeevan eashwar

So machen Sie es mit abgerundeten Ecken und gerundeten Schatten, ohne sich um Pfade zu kümmern.

//Inner view with content
[imageView.layer setBorderColor:[[UIColor lightGrayColor] CGColor]];
[imageView.layer setBorderWidth:1.0f];
[imageView.layer setCornerRadius:8.0f];
[imageView.layer setMasksToBounds:YES];

//Outer view with shadow
UIView* shadowContainer = [[UIView alloc] initWithFrame:imageView.frame];
[shadowContainer.layer setMasksToBounds:NO];
[shadowContainer.layer setShadowColor:[[UIColor blackColor] CGColor]];
[shadowContainer.layer setShadowOpacity:0.6f];
[shadowContainer.layer setShadowRadius:2.0f];
[shadowContainer.layer setShadowOffset: CGSizeMake(0.0f, 2.0f)];

[shadowContainer addSubview:imageView];

Die Ansicht mit Inhalt, in meinem Fall eine UIImageView, hat einen Eckenradius und muss daher an Grenzen maskiert werden.

Wir erstellen eine weitere Ansicht gleicher Größe für die Schatten, setzen maskToBounds auf NO und fügen dann die Inhaltsansicht der Containeransicht hinzu (z. B. shadowContainer).

0
Ford Davis

Ich schreibe diese UIView-Kategoriemethode, um dieses Problem zu lösen. Dabei werden separate Ansichten für den Schatten und den Eckenradius verwendet.

-(UIView *)shadowedWrapViewWithBounds:(CGRect)bounds {
UIView *baseView = [[UIView alloc] init];
baseView.bounds = bounds;
baseView.backgroundColor = [UIColor clearColor];
baseView.layer.shadowColor = [UIColor blackColor].CGColor;
baseView.layer.shadowOffset = CGSizeMake(0, 0);
baseView.layer.shadowOpacity = 0.7;
baseView.layer.shadowRadius = 4.0;

// improve performance
baseView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:baseView.bounds cornerRadius:4].CGPath;
baseView.layer.shouldRasterize = YES;
baseView.layer.rasterizationScale = [UIScreen mainScreen].scale;

[baseView addSubview:self];
//use Masonry autolayout, self can set corner radius
[self makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(baseView);
}];

return baseView;
}
0
Liu Chao

Swift 4 Lösung, um UICollectionViewCell zu runden und hinzuzufügen Schatten , ohne Erweiterungen und Komplikationen :)

Hinweis: Für einfache Ansichten, z. B. Schaltflächen. Siehe die Antwort von @ suragch in diesem Beitrag. https://stackoverflow.com/a/34984063/7698092 . Wurde erfolgreich auf Schaltflächen getestet

Falls noch jemand versucht zu runde Ecken und addiere Schatten gleichzeitig. Obwohl diese Lösung mit UICollectionViewCell funktioniert, kann sie auf jede Ansicht verallgemeinert werden.

Diese Technik funktionierte für mich ohne irgendwelche Erweiterungen und all die komplizierten Sachen. Ich arbeite mit storyBoard.

Technik

Sie müssen eine UIView (sagen wir "containerView") in Ihre UICollectionViewCell in storyBoard einfügen und alle erforderlichen Ansichten (Schaltflächen, Bilder usw.) in diese containerView einfügen. Siehe den Screenshot. Structure of Cell

Schließen Sie die Steckdose für containerView an. Fügen Sie die folgenden Codezeilen in die CellforItemAtIndexPath-Delegatfunktion ein.

//adds shadow to the layer of cell

cell.layer.cornerRadius = 3.0
    cell.layer.masksToBounds = false
    cell.layer.shadowColor = UIColor.black.cgColor
    cell.layer.shadowOffset = CGSize(width: 0, height: 0)
    cell.layer.shadowOpacity = 0.6

//makes the cell round 

let containerView = cell.containerView!
    containerView.layer.cornerRadius = 8
    containerView.clipsToBounds = true

Ausgabe

Siehe den Simulator Screenshot Rounded corners with Shadows (UICollectionViewCell)

0
Awais Fayyaz

Die Antwort von Evan Mulawski wird perfekt funktionieren. Der Haken ist, dass Sie die Hintergrundfarbe für die Ansicht auf clearColor und die Eigenschaft masksToBounds auf NO setzen müssen.

Sie können festlegen, welche Farbe Sie für die Ansicht wünschen, und wie diese eingestellt werden soll

v.layer.backgroundColor = your color;

Hoffe das hilft..

0
Abdur Rahman