UIView z zaokrąglonymi narożnikami i cieniem?


389

Chcę niestandardowego UIView...: Chciałem tylko pusty biały widok z zaokrąglonymi narożnikami i jasnym cieniem (bez efektu świetlnego). Mogę zrobić każdy z tych jeden po drugim, ale zwykle clipToBounds/ maskToBoundswystępują konflikty.


1
Skoro w poniższym komentarzu powiedziałeś, że działasz przy użyciu CoreGraphics, czy mógłbyś podzielić się odpowiedzią ze społecznością, abyś mógł pomóc innym w tej samej sytuacji, gdy próbowali ci pomóc?
lnafziger

Przepraszam, to było dość dawno temu i nie mam już źródła. To, co zrobiłem, to przesłonięcie -drawRect: i użyj UIBezierPath, aby narysować prostokąt, i zastosuj cień do warstwy podkładającej widok ... jeśli dobrze pamiętam. :)
Aditya Vaidyam

5
Akceptowana odpowiedź nie działa!
onmyway133,

1
Możliwy duplikat

1
@Sachavijay Przed skomentowaniem należy zweryfikować daty obu postów.
Aditya Vaidyam

Odpowiedzi:


444

Poniższy fragment kodu dodaje obramowanie, promień granicy i cień do v, o UIView:

// 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)];

Możesz dostosować ustawienia do swoich potrzeb.

Dodaj także szkielet QuartzCore do swojego projektu i:

#import <QuartzCore/QuartzCore.h>

Zobacz moją drugą odpowiedź dotyczącą masksToBounds.


Uwaga

To może nie działać we wszystkich przypadkach. Jeśli okaże się, że ta metoda zakłóca inne wykonywane operacje rysowania, zapoznaj się z tą odpowiedzią .


83
Problem polega na tym, że kiedy ustawiam promień narożnika, ustawia maskToBounds: TAK, podczas gdy cień wymaga clipToBounds: NIE (gdzie clipToBounds robi to samo, co maskToBounds)
Aditya Vaidyam

15
mam ten sam problem. Jeśli mam kolor tła, chcę go przyciąć do zaokrąglonych rogów. Aby to zrobić, muszę użyć maskToBounds = PRAWDA, ale potem cień
znika

3
Dla początkujących jak ja: musiałem zaimportować platformę QuartzCore do mojego projektu, aby wywołać metody na obiekcie warstwy.
SilithCrowe

38
Sposób, aby uzyskać to do pracy we właściwy sposób jest użycie widok wewnętrzny pojemnik, który pomieści swoją granicę i kolor tła, zarówno z promieniem narożnika. Ten widok zostanie przycięty do granic! Drugi, zewnętrzny widok pojemnika pomieści pierwszy, ma tę samą ramę, tylko cień. Zrobiłem to kilka razy, aby połączyć ramkę, cień i promień narożnika. To naprawdę denerwujące, ale działa naprawdę dobrze.
Kpmurphy91

23
Nie działa Nie mam pojęcia, dlaczego jest tyle głosów. Czy dotyczyło to starszych wersji?
Yarneo

627

Szybki

wprowadź opis zdjęcia tutaj

// 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

Odkrywanie opcji

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Problem 1: Cień zostaje odcięty

Co się stanie, jeśli istnieją podwarstwy lub podviewy (takie jak obraz), których treść chcemy przyciąć do granic naszego widoku?

wprowadź opis zdjęcia tutaj

Możemy to osiągnąć za pomocą

blueView.layer.masksToBounds = true

(Alternatywnie blueView.clipsToBounds = truedaje ten sam wynik .)

wprowadź opis zdjęcia tutaj

Ale nie! Cień również został odcięty, ponieważ znajduje się poza granicami! Co robić? Co robić?

Rozwiązanie

Użyj osobnych widoków dla cienia i ramki. Widok podstawowy jest przezroczysty i ma cień. Widok granicy przycina każdy inny subkontynent do swoich granic.

// 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)

Daje to następujący wynik:

wprowadź opis zdjęcia tutaj

Problem 2: Niska wydajność

Dodanie zaokrąglonych narożników i cieni może być hitem wydajności. Możesz poprawić wydajność, korzystając ze wstępnie zdefiniowanej ścieżki dla cienia, a także określając, że będzie on rasteryzowany. Poniższy kod można dodać do powyższego przykładu.

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

Zobacz ten post, aby uzyskać więcej informacji. Zobacz tutaj i tutaj również.

Ta odpowiedź została przetestowana w Swift 4 i Xcode 9.


1
@ EICaptainv2.0, Jeśli chcesz tylko obramowanie (i / lub promień narożnika), nie potrzebujesz osobnego widoku. Oddzielny widok dotyczy sytuacji, w której potrzebujesz okrągłych narożników i cienia .
Suragch

2
To nie działa dla mnie. Kiedy ustawiam kolor tła na czysty w bazie, cień nie jest już wyświetlany. Co ja robię źle?
Rutger Huijsmans

3
Nie działa, ustawienie baseView.backgroundColor = UIColor.clearusuwa cień. Tylko wtedy, gdy ustawisz kolor tła, zobaczysz go.
Aleksander

2
NIE DZIAŁA DLA MNIE.
Markus

4
Do twojej wiadomości Początkowo widziałem ten sam problem, co inni komentatorzy widzieli, gdzie cień baseView nie wyświetla się, gdy jego kolor tła jest wyraźny. Problem polegał na tym, że uruchomiłem tylko pierwszą część kodu (rzeczy baseView). Po dodaniu borderView jako widoku podrzędnego cień zaczął się wyświetlać. Wydaje się, że aby cień mógł się wyświetlić, musi istnieć co najmniej jedna widoczna ramka (lub tło) w jego hierarchii widoku. Więc upewnij się, że masz borderView.layer.borderWidth> = 0 z nieprzezroczystym borderView.layer.borderColor (lub nieprzezroczystym kolorem tła)
Mike Vosseller

79

Jednym ze sposobów jest umieszczenie widoku z zaokrąglonymi narożnikami w widoku z cieniem.

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];

Następnie możesz dodać shadowView w dowolnym miejscu.


5
Amit, musisz ustawić maskToBounds / clipToBounds = TAK dla * tylko zaokrąglonego widoku *. NIE ustawiaj na shadowView. Nie wypróbowałem powyższego kodu, ale wiem na pewno, że to rozwiązanie zdecydowanie działa, choć nie jest idealne. Wyższy cień Radius zajmuje się obszarami o promieniu narożnika. Ustaw shadowRadius na 0 lub 1, a zauważysz, co próbuję powiedzieć.
Deepak GM,

2
Coś jak shadowView.layer.shadowOpacity = 0.6; brakuje
Bo.

3
„shadowView.layer.opacity = 1.0” powinno mieć postać „shadowView.layer.shadowOpacity = 1.0”
Chris

Działa na iOS 9, jeśli używasz shadowView.layer.shadowOpacity = 1.0
Mansurov Ruslan

Naprawiono kod dla shadowOpacity
Softlion

63

Sprawdź przykładowy projekt na GitHub, aby upewnić się, że używasz składnika poprawnie.

Proste rozwiązanie Swift 5 bez żadnych dodatkowych widoków podrzędnych lub podklas:

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
    }
}

Pamiętaj, że przed wywołaniem należy skonfigurować widok z promieniem narożnika i innymi właściwościami addShadow.

Następnie po prostu wywołaj to w viewDidLoadten sposób:

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

Ostateczny wynik:

wynik

Super łatwe i proste!


Czy to działa na przyciskach? Ponieważ to nie działa z mojej strony.
Cesare

Próbowałem wykonać dokładnie te kroki, które zasugerowałeś. Ale wciąż nie ma szczęścia. Byłoby wspaniale, gdybyś udostępnił próbkę (na Github), aby zobaczyć, jak sobie poradziłeś, co wydaje się niemożliwe dla mnie i innych osób.
Hemang

Udało się, aby działało tylko poprzez usunięcie tej linii layer.shadowPath = UIBezierPath.init(roundedRect: layer.bounds, cornerRadius: layer.cornerRadius).cgPath. Nie mogę wyjaśnić, dlaczego, czy ktoś ma na to wytłumaczenie?
trupin

@ Wybitny zachęcamy do zapoznania się ze zaktualizowaną odpowiedzią na przykładzie projektu Xcode. Nie może nie działać :)
Sergey Grischyov

3
To również działało dla mnie, wystarczy jeszcze jedno: wyczyścić wszystkie tła podviewów w kolorze, aby tylko widok pojemnika miał widoczne tło i to rozwiązało mój problem. Dzięki!! @SergeyGrischyov
Rishabh

42

To zadziałało dla mnie. Sztuczka polegała na przeniesieniu koloru tła z widoku głównego na warstwę.

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 ;

Chociaż wszystkie pozostałe rozwiązania działają i być może są one bardziej ogólne, jest to zdecydowanie najlepsze rozwiązanie problemu. Dodanie widoków podrzędnych lub podwarstw tworzy świat lub utrudnia próbę utrzymania rozmiarów ramek, aw najlepszym wypadku może powodować problemy z wydajnością.
emem

To powinna być odpowiedź. Czysty i elegancki.
Axy,

Najlepsze rozwiązanie i zdecydowanie elegancki!
Roberto Ferraz,

Wow, to faktycznie działa. Nie rozumiem, dlaczego powinien działać - można by pomyśleć, że tło backgroundColor widoku poprawnie odwzorowałoby bezpośrednio na właściwość layer.backgroundColor w iOS - ale DZIAŁA. (Xcode 8, Swift 3.) Dobra robota i dzięki. To powinna być zaakceptowana odpowiedź.
Womble

Stworzyłem twoją wersję Swift 3.1, używając UIView extensiontutaj - stackoverflow.com/a/43295741/1313939 dzięki za inspirację!
Sergey Grischyov,

26

Rozwiązałem problem przy użyciu następującej sztuczki podczas przypisywania ścieżki cienia do widoku kontenera:

[UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]

Zauważ, że ścieżka podana do cienia jest zaokrąglonym prostokątem o tym samym promieniu narożnika, co tło, które zawiera komórka:

//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]];

Najlepsza odpowiedź, ponieważ wyjaśnia właściwy sposób dodawania cienia do zaokrąglonego narożnego widoku. Dzięki @Alex Stone
programista

17

Jeśli walczysz z powodu zaokrąglenia cornersvs. subviewsvs. masksToBounds, spróbuj użyć mojej funkcji:

- (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;
}

nazwij to swoim zdaniem. czy Twój widok ma zaokrąglone rogi, bez względu na jego rozmiar, kształt - zostanie narysowany ładny cień.

Zachowaj tylko wartość zwracaną przez funkcję, aby móc się do niej odwoływać, gdy chcesz usunąć tabelę (lub na przykład użyć insertSubview:aboveView:)


to działa dobrze. Ale jeśli widok ma rozpoznawanie gestów, to nie będzie działać. jak możemy to rozwiązać?
manujmv

@manujmv Czy widzisz linie, w których podano „// Zmodyfikuj to, jeśli to konieczne”? Właśnie tego potrzebujesz. shadow.userInteractionEnabled = TAK;
daniel.gindi

@manujmv, to powinieneś przetestować ramki widoku i podglądu, aby zobaczyć dlaczego. coś prawdopodobnie nie jest tutaj. ten dokładny kod działa dla mnie w niektórych bardzo fajnych aplikacjach
daniel.gindi

2
To rozwiązanie doskonale sprawdza się w przypadku UITableView z zaokrąglonymi narożnikami. Chciałbym móc oddać więcej głosów. Dzięki!
Chris Hart

@ CarlosEduardoLópez Czy widzisz shadow.userInteractionEnabled = NO; // Modify this if neededlinię? Tak jest w razie potrzeby. userInteractionEnabledjest podstawową i popularną własnością, którą powinieneś już znać :-)
daniel.gindi

12

Używając Swift 4 i Xcode 9 , jest to praktyczny przykład zaokrąglania za ImageViewpomocą cienia i obramowania.

    //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)

wprowadź opis zdjęcia tutaj

Jeśli chcesz, aby obraz był okrągły: (i wyświetlany bez obramowania)

let cornerRadius = imageWidth / 2

wprowadź opis zdjęcia tutaj


7

Stworzyłem pomocnika na UIView

@interface UIView (Helper)

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

możesz to tak nazwać

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

Oto implementacja

- (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];

}

2
To dobre, eleganckie rozwiązanie. Przed użyciem upewnij się, że widok został dodany do jego podglądu. Dodałem kilka parametrów, aby dać mi większą kontrolę nad cieniem, ale ogólnie działa idealnie. Dzięki!
Aaron Vegh

To miłe rozwiązanie, ale nie działa z automatycznym układem: widok zostanie narysowany na początku 0,0
gderaco

5

Po całodniowym badaniu widoku okrągłego rogu z cieniem, cieszę się, że mogę tutaj zamieścić moją niestandardową klasę uiview, mam nadzieję zakończyć to pytanie:

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

więc NIE trzeba dodawać widoku podrzędnego w widoku ani poniżej w widoku docelowym, wystarczy dodać jedną warstwę w bieżącym widoku i wykonać 3 kroki, aby go ukończyć!

przyjrzyj się komentarzom w kodzie, pomocne jest zrozumienie komponentu!


5

Coś sprawnego przetestowane w 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
        }
    }
}

Produkuje

wprowadź opis zdjęcia tutaj

Jeśli włączysz to w Inspektorze w następujący sposób:

wprowadź opis zdjęcia tutaj

Dodanie atrybutu środowiska wykonawczego zdefiniowanego przez użytkownika, co spowoduje:

wprowadź opis zdjęcia tutaj

(Wcześniej dodałem cornerRadius = 8)

:)


5

Musisz użyć użycia shadowViewiroundView

wprowadź opis zdjęcia tutaj

shadowView

  • Musi mieć kolor tła
  • Powinien leżeć z tyłu roundView
  • Sztuka polega na tym, żeby shadowViewtrochę rozłożyć w środku, a cień musi się rozjaśnić. Ustaw insetstak, aby shadowViewbył całkowicie niewidoczny z tyłuroundView

roundView

  • Musi przycinać widoki podrzędne

Kod

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
}

Lub możesz po prostu zrobić poniżej bez określania clipToBounds/maskToBounds

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

4

Swift 3 i IB Rozwiązanie sprawdzalne:
Zainspirowane rozwiązaniem Ade

Najpierw utwórz rozszerzenie UIView:

//
//  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
          }
     }
}

Następnie po prostu wybierz UIView w kreatorze interfejsów, ustawiając cień na i promień narożnika , jak poniżej:

Wybieranie UIView

Włączanie cienia i promienia narożnika

Wynik!

Wynik


Jak każde inne „rozwiązanie” w tym wątku, po prostu nie działa, przynajmniej nie w iOS 11.0 / Swift 4.1.
inccitus

Czy czytałeś „Swift 3” na początku wątku? Oznacza to, że jest to rozwiązanie Swift 3, nie testowałem go w Swift 4.1, ponieważ już go nie potrzebuję. Edytuj odpowiedź i podaj rozwiązanie. ;) Cheers
Thomás Calmon

3

Oto rozwiązanie problemu konfliktu masksToBounds, działa dla mnie.

Po ustawieniu corderRadius / borderColor / shadow itd. Ustaw masksToBounds jako NIE:

v.layer.masksToBounds = NO;

To zadziałało dla mnie !! omg Prawie zrobiłem wszystkie sztuczki nad tobą odpowiedzi! dzięki Shaopeng.
MontDeska,

3

Shadow + Border + Corner Radius wprowadź opis zdjęcia tutaj

    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

Oto moja wersja w Swift 3 dla 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

Swift 4: Utwórz podklasę UIView

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
    }

}

Za pomocą..

Użyj klasowego widoku cienia


2

Cóż, jeśli nie chcesz zmieniać końcówek i wyświetlać hierarchii zgodnie z sugestią Davida C., ta metoda zrobi to za Ciebie. Aby dodać zaokrąglone rogi i cień do swojego UIImageView, po prostu użyj tej metody, na przykład:

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

(!) Ze względu na wydajność nie sądzę, że dobrym pomysłem jest używanie tego kodu w czegoś takiego jak UITableView, ponieważ ten kod zmienia hierarchię widoku. Zasugeruję więc zmianę końcówki i dodanie widoku kontenera dla efektu cienia i użycie kodu Davica C.

+ (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

Stary wątek wciąż aktualny ...

Zredagowałem metodę Daniela Gindi, aby umożliwić jej użycie również z przyciskami itp. Jeśli ktoś potrzebuje zaokrąglonych rogów lub chce połączyć zaokrąglone rogi z ramką, należy ustawić je na warstwie widoku, która jest przekazywana do tej metody. Ustawiłem także rasteryzację, aby nieco ją przyspieszyć.

+ (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

Poniższe działało dla mnie najlepiej (ten kod znajduje się w rozszerzeniu UIView, więc self oznacza niektóre UIView, do których musimy dodać cień i okrągły narożnik)

- (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];
}

Główną różnicą między tym a innymi przykładami kodu jest to, że dodaje widok cienia jako widok rodzeństwa (w porównaniu z dodawaniem bieżącego widoku jako widoku podrzędnego widoku cienia), eliminując w ten sposób potrzebę modyfikacji istniejącej hierarchii widoku w jakikolwiek sposób.


1

Powyższa odpowiedź daniel.gindi załatwiła sprawę! (+1 Daniel) Jednak musiałem dokonać drobnych korekt - zmień rozmiar shadowFrame, aby był taki sam jak rozmiar ramki widoku, i włącz interakcję użytkownika. Oto zaktualizowany kod:

+ (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;
}

Chciałbym dodać, że w moim przypadku próbowałem dodać to do kontrolera widoku innej firmy, tj. Nie miałem bezpośredniej kontroli nad kodem. Oto jak użyłem powyższej funkcji:

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

Wprowadzam pewne zmiany w kodzie daniel.gindi

To wszystko, czego potrzebujesz, aby działało.

+ (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

Aby UIViewsto osiągnąć, musisz użyć dwóch . Jeden UIViewbędzie działał jak cień, a drugi będzie działał dla zaokrąglonej granicy.

Oto fragment kodu a Class Methodz pomocą 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;
}

W powyższym kodzie btnCompose_click:stanie się @requiredmetodą delegowaną, która zostanie uruchomiona po kliknięciu przycisku.

I tutaj dodałem przycisk do mojego w UIViewControllerten sposób:

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];

Wynik będzie wyglądał następująco:

wprowadź opis zdjęcia tutaj


1

Próbowałem tak wielu rozwiązań z tego postu i skończyłem z poniższym rozwiązaniem. Jest to w pełni sprawdzone rozwiązanie, chyba że musisz rzucić cień na czysty widok kolorów .

- (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;
}

Wyrażenie to „głupi dowód”. :)
Ben Thomas

Właśnie poprawiałem angielski. :) Rozwiązanie działa.
Ben Thomas

1

Oto rozwiązanie, które na pewno zadziała!

Utworzyłem rozszerzenie UIView z wymaganymi krawędziami, aby zastosować cień jak poniżej


enum AIEdge:Int {
    case
    Top,
    Left,
    Bottom,
    Right,
    Top_Left,
    Top_Right,
    Bottom_Left,
    Bottom_Right,
    All,
    None
}

extension UIView {

    func applyShadowWithCornerRadius(color:UIColor, opacity:Float, radius: CGFloat, edge:AIEdge, shadowSpace:CGFloat)    {

        var sizeOffset:CGSize = CGSize.zero

        switch edge {
        case .Top:
            sizeOffset = CGSize(width: 0, height: -shadowSpace)
        case .Left:
            sizeOffset = CGSize(width: -shadowSpace, height: 0)
        case .Bottom:
            sizeOffset = CGSize(width: 0, height: shadowSpace)
        case .Right:
            sizeOffset = CGSize(width: shadowSpace, height: 0)


        case .Top_Left:
            sizeOffset = CGSize(width: -shadowSpace, height: -shadowSpace)
        case .Top_Right:
            sizeOffset = CGSize(width: shadowSpace, height: -shadowSpace)
        case .Bottom_Left:
            sizeOffset = CGSize(width: -shadowSpace, height: shadowSpace)
        case .Bottom_Right:
            sizeOffset = CGSize(width: shadowSpace, height: shadowSpace)


        case .All:
            sizeOffset = CGSize(width: 0, height: 0)
        case .None:
            sizeOffset = CGSize.zero
        }

        self.layer.cornerRadius = self.frame.size.height / 2
        self.layer.masksToBounds = true;

        self.layer.shadowColor = color.cgColor
        self.layer.shadowOpacity = opacity
        self.layer.shadowOffset = sizeOffset
        self.layer.shadowRadius = radius
        self.layer.masksToBounds = false

        self.layer.shadowPath = UIBezierPath(roundedRect:self.bounds, cornerRadius:self.layer.cornerRadius).cgPath
    }
}

Na koniec możesz wywołać funkcję cienia, jak poniżej, dla dowolnej podklasy UIView, możesz także określić krawędź, dla której chcesz zastosować cień, wypróbować różne warianty, w zależności od potrzeb zmieniając parametry poniższego wywołania metody.

viewRoundedToBeShadowedAsWell.applyShadowWithCornerRadius(color: .gray, opacity: 1, radius: 15, edge: AIEdge.All, shadowSpace: 15)

Obraz wynikowy

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj


0

Odpowiedź udzielona przez Evana Mulawskiego będzie działać idealnie. Problem polega na tym, że musisz ustawić kolor tła dla widoku clearColor, a właściwość masksToBounds na NO.

Możesz ustawić dowolny kolor widoku, ustawić go w podobny sposób

v.layer.backgroundColor = your color;

Mam nadzieję że to pomoże..


0

W ten sposób robisz to z zaokrąglonymi narożnikami i zaokrąglonymi cieniami bez zawracania sobie głowy ścieżkami.

//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];

Widok z zawartością, w moim przypadku UIImageView, ma promień narożnika i dlatego musi być maskowany do granic.

Tworzymy kolejny równy widok dla cieni, ustawiamy jego maskToBounds na NIE, a następnie dodajemy widok zawartości do widoku kontenera (np. ShadowContainer).


0

Piszę tę metodę kategorii UIView, aby rozwiązać ten problem, używa osobnych widoków dla cienia i promienia narożnika.

-(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

Swift 4 Rozwiązanie do tworzenia okrągłego UICollectionViewCell i dodawania cieni , bez żadnych rozszerzeń i komplikacji :)

Uwaga: W przypadku prostych widoków, np. Przyciski. Zobacz odpowiedź @ suragch w tym poście. https://stackoverflow.com/a/34984063/7698092 . Przetestowano pomyślnie pod kątem przycisków

W przypadku, jeśli ktoś nadal zmaga się zaokrąglić narożniki i dodać cienie w tym samym czasie. Chociaż to rozwiązanie działa z UICollectionViewCell, można je uogólnić na dowolny widok.

Ta technika działała dla mnie bez żadnych rozszerzeń i wszystkich skomplikowanych rzeczy. Pracuję z storyBoard.

Technika

Musisz dodać UIView (powiedzmy, że jest to „containerView”) w UICollectionViewCell w storyBoard i dodać wszystkie wymagane widoki (przyciski, obrazy itp.) Wewnątrz tego pojemnikaViewView. Zobacz zrzut ekranu. Struktura komórki

Podłącz wylot do pojemnikaViewView. Dodaj następujące wiersze kodu w funkcji delegowania CellforItemAtIndexPath.

//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

Wynik

Zobacz zrzut ekranu symulatora Zaokrąglone rogi z cieniami (UICollectionViewCell)


0
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)
        }

    }
}

Cześć, dziękuję za odpowiedź, powinieneś dodać kilka uwag do swojego kodu, aby wyjaśnić trochę zgodnie z opisem w Jak odpowiedzieć .
Baptiste Mille-Mathias
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.