Szybki - problemy z promieniem narożnika i cieniem

85

Próbuję stworzyć przycisk z zaokrąglonymi rogami i cieniem . Bez względu na to, jak się włączę, przycisk nie będzie wyświetlał się poprawnie. Próbowałem masksToBounds = falsei masksToBounds = true, ale albo promień narożnika działa i cień nie działa, albo cień działa, a promień narożnika nie przycina rogów przycisku.

import UIKit
import QuartzCore

@IBDesignable
class Button : UIButton
{
    @IBInspectable var masksToBounds: Bool    = false                {didSet{updateLayerProperties()}}
    @IBInspectable var cornerRadius : CGFloat = 0                    {didSet{updateLayerProperties()}}
    @IBInspectable var borderWidth  : CGFloat = 0                    {didSet{updateLayerProperties()}}
    @IBInspectable var borderColor  : UIColor = UIColor.clearColor() {didSet{updateLayerProperties()}}
    @IBInspectable var shadowColor  : UIColor = UIColor.clearColor() {didSet{updateLayerProperties()}}
    @IBInspectable var shadowOpacity: CGFloat = 0                    {didSet{updateLayerProperties()}}
    @IBInspectable var shadowRadius : CGFloat = 0                    {didSet{updateLayerProperties()}}
    @IBInspectable var shadowOffset : CGSize  = CGSizeMake(0, 0)     {didSet{updateLayerProperties()}}

    override func drawRect(rect: CGRect)
    {
        updateLayerProperties()
    }

    func updateLayerProperties()
    {
        self.layer.masksToBounds = masksToBounds
        self.layer.cornerRadius = cornerRadius
        self.layer.borderWidth = borderWidth
        self.layer.borderColor = borderColor.CGColor
        self.layer.shadowColor = shadowColor.CGColor
        self.layer.shadowOpacity = CFloat(shadowOpacity)
        self.layer.shadowRadius = shadowRadius
        self.layer.shadowOffset = shadowOffset
    }
}
Jake
źródło
Będziesz chciał umieścić cień i przycinanie na różnych warstwach. A ustawienie właściwości warstwy w programie drawRectnie jest dobrym pomysłem. Lepiej je włożyć initWithCoder.
David Berry,
Tylko dla każdego, kto tu szuka w Google, jak to często bywa w przypadku bardzo starych pytań, najlepsza odpowiedź tutaj, chociaż ogólnie poprawna, zawiera teraz kilka krytycznych błędów . (Wstawiam poprawioną odpowiedź.) Większość ludzi, a szczególnie ja, ślepo kopiuje i wkleja od góry. TAK - bądź ostrożny, jeśli jest to bardzo stara QA! (Teraz jest rok 2020 - za 5 lat ktoś będzie musiał zastąpić moją odpowiedź!)
Fattie

Odpowiedzi:

144

Poniższy kod Swift 5 / iOS 12 pokazuje, jak ustawić podklasę, UIButtonktóra pozwala tworzyć instancje z zaokrąglonymi narożnikami i cieniem dookoła:

import UIKit

final class CustomButton: UIButton {

    private var shadowLayer: CAShapeLayer!

    override func layoutSubviews() {
        super.layoutSubviews()

        if shadowLayer == nil {
            shadowLayer = CAShapeLayer()
            shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 12).cgPath
            shadowLayer.fillColor = UIColor.white.cgColor

            shadowLayer.shadowColor = UIColor.darkGray.cgColor
            shadowLayer.shadowPath = shadowLayer.path
            shadowLayer.shadowOffset = CGSize(width: 2.0, height: 2.0)
            shadowLayer.shadowOpacity = 0.8
            shadowLayer.shadowRadius = 2

            layer.insertSublayer(shadowLayer, at: 0)
            //layer.insertSublayer(shadowLayer, below: nil) // also works
        }        
    }

}

W zależności od potrzeb możesz dodać do UIButtonswojego Storyboardu i ustawić jego klasę na CustomButtonlub możesz CustomButtonprogramowo utworzyć wystąpienie . Poniższa UIViewControllerimplementacja pokazuje, jak CustomButtonprogramowo tworzyć instancję i używać jej :

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = CustomButton(type: .system)
        button.setTitle("Button", for: .normal)
        view.addSubview(button)

        button.translatesAutoresizingMaskIntoConstraints = false
        let horizontalConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        let verticalConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor)        
        let widthConstraint = button.widthAnchor.constraint(equalToConstant: 100)
        let heightConstraint = button.heightAnchor.constraint(equalToConstant: 100)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
    }

}

Poprzedni kod tworzy poniższy obraz w symulatorze iPhone'a:

wprowadź opis obrazu tutaj

Imanou Petit
źródło
z iOS miałem problemy ze starą implementacją, teraz działa. Dziękuję Ci!
carlodonz
1
Jak wywołujesz klasę z głównego kontrolera widoku @POB?
Led
1
Czy istnieje sposób na przycięcie warstwy cienia, zachowując tylko widoczną część?
Johan Tingbacke,
4
Ponieważ warstwa masksToBounds = YEScienia jest podwarstwą warstwy przycisku, która musi mieć zaokrąglone rogi, czy cień również nie zostanie odcięty?
mattsson
3
To działa ostatecznie, ale nie mogę już zmienić tła przycisku. Dzieje się tak prawdopodobnie z powodu shadowLayer.fillColor. Co sugerujesz? Dzięki !
GrayFox
34

Mój zwyczaj przycisk z jakimś cieniem i zaokrąglonymi narożnikami , używam go bezpośrednio w obrębie Storyboardbez konieczności dotknąć go programowo.

Szybki 4

class RoundedButtonWithShadow: UIButton {
    override func awakeFromNib() {
        super.awakeFromNib()
        self.layer.masksToBounds = false
        self.layer.cornerRadius = self.frame.height/2
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath
        self.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
        self.layer.shadowOpacity = 0.5
        self.layer.shadowRadius = 1.0
    }
}

wprowadź opis obrazu tutaj

zakres
źródło
Szybko i łatwo.
Devbot10
1
Dla mnie załatwiło sprawę, kiedy ponownie umieściłem kod layoutSubviews().
Yash Bedi,
14

Aby rozwinąć post Imanou, możliwe jest programowe dodanie warstwy cienia w niestandardowej klasie przycisku

@IBDesignable class CustomButton: UIButton {
    var shadowAdded: Bool = false

    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)

        if shadowAdded { return }
        shadowAdded = true

        let shadowLayer = UIView(frame: self.frame)
        shadowLayer.backgroundColor = UIColor.clearColor()
        shadowLayer.layer.shadowColor = UIColor.darkGrayColor().CGColor
        shadowLayer.layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: self.cornerRadius).CGPath
        shadowLayer.layer.shadowOffset = CGSize(width: 1.0, height: 1.0)
        shadowLayer.layer.shadowOpacity = 0.5
        shadowLayer.layer.shadowRadius = 1
        shadowLayer.layer.masksToBounds = true
        shadowLayer.clipsToBounds = false

        self.superview?.addSubview(shadowLayer)
        self.superview?.bringSubviewToFront(self)
    }
}
Matt Pinkston
źródło
2
Maskujesz cień warstwy i naprawdę nie polecałbym umieszczania widoku cienia na nadzorze przycisku.
mattsson
13

Alternatywny sposób na uzyskanie bardziej użytecznego i spójnego przycisku.

Swift 2:

func getImageWithColor(color: UIColor, size: CGSize, cornerRadius:CGFloat) -> UIImage {
    let rect = CGRectMake(0, 0, size.width, size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 1)
    UIBezierPath(
        roundedRect: rect,
        cornerRadius: cornerRadius
        ).addClip()
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

let button = UIButton(type: .Custom)
button.frame = CGRectMake(20, 20, 200, 50)
button.setTitle("My Button", forState: UIControlState.Normal)
button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
self.addSubview(button)

let image = getImageWithColor(UIColor.whiteColor(), size: button.frame.size, cornerRadius: 5)
button.setBackgroundImage(image, forState: UIControlState.Normal)

button.layer.shadowRadius = 5
button.layer.shadowColor = UIColor.blackColor().CGColor
button.layer.shadowOpacity = 0.5
button.layer.shadowOffset = CGSizeMake(0, 1)
button.layer.masksToBounds = false

Swift 3:

func getImageWithColor(_ color: UIColor, size: CGSize, cornerRadius:CGFloat) -> UIImage? {
    let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image
}

let button = UIButton(type: .custom)
button.frame = CGRect(x:20, y:20, width:200, height:50)
button.setTitle("My Button", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
self.addSubview(button)

if let image = getImageWithColor(UIColor.white, size: button.frame.size, cornerRadius: 5) {
    button.setBackgroundImage(image, for: .normal)
}

button.layer.shadowRadius = 5
button.layer.shadowColor = UIColor.black.cgColor
button.layer.shadowOpacity = 0.5
button.layer.shadowOffset = CGSize(width:0, height:1)
button.layer.masksToBounds = false
aytek
źródło
1
Ta metoda jest najlepsza, ponieważ można mieć inny kolor tła dla .Normal i podświetlone
Ryan Heitner
1
Ładny. Wypróbowałem wiele różnych metod uzyskiwania koloru tła, promienia narożników i cieni działających na moich przyciskach, ale to był jedyny sposób, który działał! Dzięki!
Harry Bloom,
To idealne rozwiązanie, dzięki za to! Jedna uwaga, jeśli używasz UIButton wewnątrz UITableViewCell, programowo, to musi być umieszczone wewnątrz layoutSubviews ().
biustonosz. Scena
4

Zmieniono to, aby wspierać dowolny widok. Podklasuj swój widok z tego i powinien mieć zaokrąglone rogi. Jeśli dodasz coś takiego jak UIVisualEffectView jako podwidok do tego widoku, prawdopodobnie będziesz musiał użyć tych samych zaokrąglonych rogów w tym UIVisualEffectView lub nie będzie miał zaokrąglonych rogów.

Zaokrąglone rogi z cieniem dla UIView - zrzut ekranu również używa rozmycia, które jest normalnym UIVisualEffectView, który również ma zaokrąglone rogi

/// Inspiration: https://stackoverflow.com/a/25475536/129202
class ViewWithRoundedcornersAndShadow: UIView {
    private var theShadowLayer: CAShapeLayer?

    override func layoutSubviews() {
        super.layoutSubviews()

        if self.theShadowLayer == nil {
            let rounding = CGFloat.init(22.0)

            let shadowLayer = CAShapeLayer.init()
            self.theShadowLayer = shadowLayer
            shadowLayer.path = UIBezierPath.init(roundedRect: bounds, cornerRadius: rounding).cgPath
            shadowLayer.fillColor = UIColor.clear.cgColor

            shadowLayer.shadowPath = shadowLayer.path
            shadowLayer.shadowColor = UIColor.black.cgColor
            shadowLayer.shadowRadius = CGFloat.init(3.0)
            shadowLayer.shadowOpacity = Float.init(0.2)
            shadowLayer.shadowOffset = CGSize.init(width: 0.0, height: 4.0)

            self.layer.insertSublayer(shadowLayer, at: 0)
        }
    }
}
Jonny
źródło
4

Swift 5 i nie ma potrzeby „UIBezierPath”

    view.layer.cornerRadius = 15
    view.clipsToBounds = true
    view.layer.masksToBounds = false
    view.layer.shadowRadius = 7
    view.layer.shadowOpacity = 0.6
    view.layer.shadowOffset = CGSize(width: 0, height: 5)
    view.layer.shadowColor = UIColor.red.cgColor
Hari R Krishna
źródło
1
Nigdy nie dodaje żadnego promienia narożnika do widoku, a powodem, dla którego UIBezierPathjest to potrzebne, są względy wydajnościowe na wypadek, gdyby trzeba było ponownie użyć tego konkretnego widoku.
Sharkes Monken
@SharkesMonken "NIGDY" naprawdę !!!! ? Sprawdź jeszcze raz. Używam tej metody w całym moim projekcie. A jeśli masz jakiekolwiek wątpliwości, obejrzyj ten film youtu.be/5qdF5ocDU7w
Hari R Krishna
Nie działa; cornerRadius nie ma efektu
Amr Angry
proszę sprawdzić wideo
Hari R Krishna
2

Aby poprawić odpowiedź PiterPan i pokazać prawdziwy cień (nie tylko tło bez rozmycia) za pomocą okrągłego przycisku w Swift 3:

override func viewDidLoad() {
    super.viewDidLoad()
    myButton.layer.masksToBounds = false
    myButton.layer.cornerRadius = myButton.frame.height/2
    myButton.clipsToBounds = true
}

override func viewDidLayoutSubviews() {
    addShadowForRoundedButton(view: self.view, button: myButton, opacity: 0.5)
}

func addShadowForRoundedButton(view: UIView, button: UIButton, opacity: Float = 1) {
    let shadowView = UIView()
    shadowView.backgroundColor = UIColor.black
    shadowView.layer.opacity = opacity
    shadowView.layer.shadowRadius = 5
    shadowView.layer.shadowOpacity = 0.35
    shadowView.layer.shadowOffset = CGSize(width: 0, height: 0)
    shadowView.layer.cornerRadius = button.bounds.size.width / 2
    shadowView.frame = CGRect(origin: CGPoint(x: button.frame.origin.x, y: button.frame.origin.y), size: CGSize(width: button.bounds.width, height: button.bounds.height))
    self.view.addSubview(shadowView)
    view.bringSubview(toFront: button)
}
hardanger
źródło
1

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


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

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

Na koniec, aby zastosować cień z wywołaniem promienia narożnika, jak poniżej:

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

Obraz wynikowy

wprowadź opis obrazu tutaj

AKTUALIZACJA : Jeśli nie widzisz oczekiwanego wyniku, spróbuj wywołać metodę rozszerzenia z głównego wątku , to na pewno zadziała!

DispatchQueue.main.async {
    viewRounded.applyShadowWithCornerRadius(color: .gray, opacity: 1, radius: 15, edge: AIEdge.All, shadowSpace: 15)
}
Dhaval H. Nena
źródło
0

Jeśli ktoś potrzebuje dodać cienie zaokrąglonych przycisków w Swift 3.0, oto dobra metoda, aby to zrobić.

func addShadowForRoundedButton(view: UIView, button: UIButton, shadowColor: UIColor, shadowOffset: CGSize, opacity: Float = 1) {
    let shadowView = UIView()
    shadowView.backgroundColor = shadowColor
    shadowView.layer.opacity = opacity
    shadowView.layer.cornerRadius = button.bounds.size.width / 2
    shadowView.frame = CGRect(origin: CGPoint(x: button.frame.origin.x + shadowOffset.width, y: button.frame.origin.y + shadowOffset.height), size: CGSize(width: button.bouds.width, height: button.bounds.height))
    self.view.addSubview(shadowView)
    view.bringSubview(toFront: button)
}

Użyj tej metody w następujący func viewDidLayoutSubviews()sposób:

override func viewDidLayoutSubviews() {
    addShadowForRoundedButton(view: self.view, button: button, shadowColor: .black, shadowOffset: CGSize(width: 2, height: 2), opacity: 0.5)
}

Efektem tej metody jest: wprowadź opis obrazu tutaj

PiterPan
źródło
0

Rozszerzenie do cienia i promienia narożnika

extension UIView {

func dropShadow(color: UIColor, opacity: Float = 0.5, offSet: CGSize, shadowRadius: CGFloat = 1, scale: Bool = true, cornerRadius: CGFloat) {
    let shadowLayer = CAShapeLayer()
    shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
    shadowLayer.fillColor = UIColor.white.cgColor
    shadowLayer.shadowColor = color.cgColor
    shadowLayer.shadowPath = shadowLayer.path
    shadowLayer.shadowOffset = offSet
    shadowLayer.shadowOpacity = opacity
    shadowLayer.shadowRadius = shadowRadius
    layer.insertSublayer(shadowLayer, at: 0)
}

}
Angi
źródło
0

Dokładne rozwiązanie dla składni 2020

import UIKit
class ColorAndShadowButton: UIButton {
    override init(frame: CGRect) { super.init(frame: frame), common() }
    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder), common() }
    private func common() {
        // UIButton is tricky: you MUST set the clear bg in bringup;  NOT in layout
        backgroundColor = .clear
        clipsToBounds = false
        self.layer.insertSublayer(backgroundAndShadow, below: layer)
    }
    
   lazy var colorAndShadow: CAShapeLayer = {
        let s = CAShapeLayer()
        // set your button color HERE (NOT on storyboard)
        s.fillColor = UIColor.black.cgColor
        // now set your shadow color/values
        s.shadowColor = UIColor.red.cgColor
        s.shadowOffset = CGSize(width: 0, height: 10)
        s.shadowOpacity = 1
        s.shadowRadius = 10
        // now add the shadow
        layer.insertSublayer(s, at: 0)
        return s
    }()
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // you MUST layout these two EVERY layout cycle:
        colorAndShadow = bounds
        colorAndShadow = UIBezierPath(roundedRect: bounds, cornerRadius: 12).cgPath
    }
}

wprowadź opis obrazu tutaj

  • Zwróć uwagę, że bardzo stara odpowiedź jest poprawna, ale zawiera błąd krytyczny

Zauważ, że UIButtonjest to niestety zupełnie inne niż UIVieww iOS.

  • Ze względu na dziwne zachowanie w iOS musisz ustawić kolor tła (który oczywiście musi być w tym przypadku wyraźny) podczas inicjalizacji, a nie w układzie . Możesz po prostu ustawić to wyraźnie w scenorysie (ale zwykle klikasz go, aby uzyskać jednolity kolor, aby można go było zobaczyć podczas pracy w scenorysie).

Ogólnie rzecz biorąc, kombinacje cieni / zaokrąglenia są prawdziwym problemem w iOS. Podobne rozwiązania:

https://stackoverflow.com/a/57465440/294884 - obraz + zaokrąglone + cienie
https://stackoverflow.com/a/41553784/294884 - problem z dwoma rogami
https://stackoverflow.com/a/59092828/294884 - problem „cienie + dziura” lub „blask”
https://stackoverflow.com/a/57400842/294884 - problem „obramowanie i przerwa”
https://stackoverflow.com/a/57514286/294884 - podstawowe „dodawanie” beziers

Fattie
źródło
-1

Możesz utworzyć protokół i dostosować go do siebie UIView, UIButton, Cell lub cokolwiek chcesz w ten sposób:

protocol RoundedShadowable: class {
    var shadowLayer: CAShapeLayer? { get set }
    var layer: CALayer { get }
    var bounds: CGRect { get }
}
​
extension RoundedShadowable {
    func applyShadowOnce(withCornerRadius cornerRadius: CGFloat, andFillColor fillColor: UIColor) {
        if self.shadowLayer == nil {
            let shadowLayer = CAShapeLayer()
            shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
            shadowLayer.fillColor = fillColor.cgColor
            shadowLayer.shadowColor = UIColor.black.cgColor
            shadowLayer.shadowPath = shadowLayer.path
            shadowLayer.shadowOffset = CGSize(width: 0.0, height: 2.0)
            shadowLayer.shadowOpacity = 0.2
            shadowLayer.shadowRadius = 3
            self.layer.insertSublayer(shadowLayer, at: 0)
            self.shadowLayer = shadowLayer
        }
    }
}
​
class RoundShadowView: UIView, RoundedShadowable {

    var shadowLayer: CAShapeLayer?
    private let cornerRadius: CGFloat
    private let fillColor: UIColor

    init(cornerRadius: CGFloat, fillColor: UIColor) {
        self.cornerRadius = cornerRadius
        self.fillColor = fillColor
        super.init(frame: .zero)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        self.applyShadowOnce(withCornerRadius: self.cornerRadius, andFillColor: self.fillColor)
    }
}
​
class RoundShadowButton: UIButton, RoundedShadowable {

    var shadowLayer: CAShapeLayer?
    private let cornerRadius: CGFloat
    private let fillColor: UIColor

    init(cornerRadius: CGFloat, fillColor: UIColor) {
        self.cornerRadius = cornerRadius
        self.fillColor = fillColor
        super.init(frame: .zero)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        self.applyShadowOnce(withCornerRadius: self.cornerRadius, andFillColor: self.fillColor)
    }
}
Adam Smaka
źródło
-1

Używając CAShapeLayer i UIBezierPath możemy łatwo dodać cień i promień narożnika do UIView i klasy pochodnej, takiej jak UIButton, UIImageView, UILabel itp.

Dodamy rozszerzenie UIView, a dobrą rzeczą jest to, że wystarczy napisać tylko jedną linię kodu, aby to osiągnąć.

Możesz również zaokrąglić określony róg Po prostu dodaj poniżej rozszerzenie UIView w swoim projekcie:

 extension UIView {

  func addShadow(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: 
  CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {

    let shadowLayer = CAShapeLayer()
    let size = CGSize(width: cornerRadius, height: cornerRadius)
    let cgPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
    shadowLayer.path = cgPath //2
    shadowLayer.fillColor = fillColor.cgColor //3
    shadowLayer.shadowColor = shadowColor.cgColor //4
    shadowLayer.shadowPath = cgPath
    shadowLayer.shadowOffset = offSet //5
    shadowLayer.shadowOpacity = opacity
    shadowLayer.shadowRadius = shadowRadius
    self.layer.addSublayer(shadowLayer)
  }
}

Teraz po prostu napisz poniższy kod, aby dodać cień i promień narożnika

  self.myView.addShadow(shadowColor: .black, offSet: CGSize(width: 2.6, height: 2.6), 
  opacity: 0.8, shadowRadius: 5.0, cornerRadius: 20.0, corners: [.topRight, .topLeft], 
  fillColor: .red)
Paresh Mangukiya
źródło
-1

Promień narożnika z cieniem

Krótki i prosty sposób !!!!!

extension CALayer {
    func applyCornerRadiusShadow(
        color: UIColor = .black,
        alpha: Float = 0.5,
        x: CGFloat = 0,
        y: CGFloat = 2,
        blur: CGFloat = 4,
        spread: CGFloat = 0,
        cornerRadiusValue: CGFloat = 0)
    {
        cornerRadius = cornerRadiusValue
        shadowColor = color.cgColor
        shadowOpacity = alpha
        shadowOffset = CGSize(width: x, height: y)
        shadowRadius = blur / 2.0
        if spread == 0 {
            shadowPath = nil
        } else {
            let dx = -spread
            let rect = bounds.insetBy(dx: dx, dy: dx)
            shadowPath = UIBezierPath(rect: rect).cgPath
        }
    }

Korzystanie z kodu

btn.layer.applyCornerRadiusShadow(color: .black, 
                            alpha: 0.38, 
                            x: 0, y: 3, 
                            blur: 10, 
                            spread: 0, 
                            cornerRadiusValue: 24)

Nie ma potrzeby maskToBound

Sprawdź, czy clipsToBounds jest fałszywe.

WYNIK

wprowadź opis obrazu tutaj

Pankaj Bhalala
źródło
Dziękuję za kod, ale dla mnie nie działa, dlaczego? Proszę sprawdzić zdjęcie: imgur.com/dY5M3BL
Mc.Lover
@ Mc.Lover Czy użyłeś maskToBound? lub clipsToBounds?
Pankaj Bhalala