Gölge yayılması ve bulanıklığı nasıl kontrol edilir?


113

UI öğelerini eskizde tasarladım ve bunlardan birinde bulanıklık 1 ve yayılma 0 olan bir gölge var. Görünümler katmanı özelliği için belgeye baktım ve katmanda spread veya blur adında bir şey veya eşdeğer herhangi bir şey yok (tek kontrol, sadece shadowOpacity) Bulanıklaştırma ve yayılma gibi şeyleri nasıl kontrol edebilirim?

DÜZENLE:

İşte Sketch'teki ayarlarım: İşte gölgemin nasıl görünmesini istediğim:Eskiz gölge ayarları


Gölge aranıyor




Ve şu anda göründüğü gibi: Not, gölgeyi gerçekten görmek için resme tıklamanız gerekir.

Mevcut gölge

Kodum aşağıdaki gibidir:

func setupLayer(){
    view.layer.cornerRadius = 2
    view.layer.shadowColor = Colors.Shadow.CGColor
    view.layer.shadowOffset = CGSize(width: 0, height: 1)
    view.layer.shadowOpacity = 0.9
    view.layer.shadowRadius = 5
}

İos (platform), tasarım (Sketch yazılımının kullanımı) ve Core-Graphics (gölgeyi çizmek için bir UIBezierPath kullanmak mümkündür, ancak alakalı olabilir) etiketlerinin hepsi alakalı, neden olması gerektiğini anlamıyorum kaldırılabilir.
Quantaliinuxite

sadece o beyaz görünüm için gölge istiyorsun değil mi?
O-mkar

5
Görünüşe göre Sketch ve CoreAnimation çerçevesinin farklı ölçümleri var çünkü iOS'ta ve Sketch'te aynı parametrelerle her zaman farklı görünüyor.
Timur Bernikovich

Ah. İOS'un çalışma şekline çok az benzeyen veya hiç benzemeyen araçlar kullanan tasarımcılarla çalışmanın zevkleri. Sketch yerine PaintCode gibi bir şeye geçerseniz, yalnızca iOS çalıştığı gibi çalışmayacak, aynı zamanda ihtiyacınız olan kodu da verecektir. :-)
Fogmeister

Ya hem yarıçapı hem de bulanıklığı eskizde ayarladıysanız?
Vladimir

Yanıtlar:


259

İşte 6 Sketch gölge özelliğini bir UIView katmanına neredeyse mükemmel bir doğrulukla nasıl uygulayacağınız:

extension CALayer {
  func applySketchShadow(
    color: UIColor = .black,
    alpha: Float = 0.5,
    x: CGFloat = 0,
    y: CGFloat = 2,
    blur: CGFloat = 4,
    spread: CGFloat = 0)
  {
    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
    }
  }
}

Aşağıdakileri temsil etmek istediğimizi varsayalım:

görüntü açıklamasını buraya girin

Bunu şu yolla kolayca yapabilirsiniz:

myView.layer.applySketchShadow(
  color: .black, 
  alpha: 0.5, 
  x: 0, 
  y: 0, 
  blur: 4, 
  spread: 0)

veya daha kısaca:

myView.layer.applySketchShadow(y: 0)

Misal:

görüntü açıklamasını buraya girin

Sol: iPhone 8 UIView ekran görüntüsü; sağ: Dikdörtgen çizin.

Not:

  • Sıfır olmayan bir kullanıldığında , CALayer'a spreaddayalı bir yolu sabit boundskodlar. Katmanın sınırları değişirse, applySketchShadow()yöntemi tekrar çağırmak istersiniz .

Hm. Sketch'te, forma uygularsanız, gölgenin bulanıklığının / gradyanının başladığı yerde 'dışarı taşınır'. Bunun anlamı - bulanıklık başlayana kadar sabit gölge renginde kalır. Ancak shadowLayer'ı hareket ettirirsek, gölge sadece bu katmandan başlar, değil mi? (Yayılmanın 10 olduğunu söyleyin, gölge yalnızca 10'luk bir ofsetten sonra başlayacaktır; burada Sketch'te olduğu gibi, bulanıklık / gradyan 10'luk bir ofsetten sonra başlayacaktır). Yani gerçekten eşleşmiyorlar, değil mi?
Stephan

1
@Senseful Bu formüle nasıl ulaştığınızı merak ediyorum ?!
Hashem Aboonajmi

2
Ayarlamayı unuttun maskToBounds = false.
ScottyBlades

1
Yukarıda ScottyBlades tarafından belirtildiği gibi, bu olmadan işe yaramaz maskToBounds = false. Başarısız olacağı bir örnek, bu gölgeyi bir UIButton.
José

5
Bu shadowRadius = blur / UIScreen.main.scale, sabit kodlamanın tersi blur / 2.0mi olmalı ? Yoksa 2'ye bölmek için başka bir neden var mı? @matchifang Bunu çözdün mü?
JWK

59

Bunu deneyebilirsiniz .... değerlerle oynayabilirsiniz. shadowRadiusDikte bulanıklık miktarı. shadowOffsetgölgenin nereye gittiğini belirler.

Swift 2.0

let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
//Change 2.1 to amount of spread you need and for height replace the code for height

demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.blackColor().CGColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds =  false
demoView.layer.shadowPath = shadowPath.CGPath

Swift 3.0

let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height 
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height)) 
//Change 2.1 to amount of spread you need and for height replace the code for height

demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.black.cgColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds =  false
demoView.layer.shadowPath = shadowPath.cgPath

Forma ile örnek

Forma ile örnek

Temel bir gölge oluşturmak için

    demoView.layer.cornerRadius = 2
    demoView.layer.shadowColor = UIColor.blackColor().CGColor
    demoView.layer.shadowOffset = CGSizeMake(0.5, 4.0); //Here your control your spread
    demoView.layer.shadowOpacity = 0.5 
    demoView.layer.shadowRadius = 5.0 //Here your control your blur

Swift 2.0'da Temel Gölge örneği

ÇIKTI


2
Bilgi yanlış, ofset yayılmanın kontrolü değil, x ve y'nin kontrolü.
Quantaliinuxite

Yanıtları güncellediğim yorumları yanlışlıkla değiştirdim @Quantaliinuxite
O-mkar

Doğru, şimdi sorumun özü geliyor: Yayılmayı nasıl kontrol ederim?
Quantaliinuxite

@Quantaliinuxite Güncellenen kod artık 2.1'i ihtiyacınız olan spread miktarına değiştirin
O-mkar 20'16

Cevap için teşekkürler. Burada shadowOpacity'yi (neden kullanıldığını) anlayamıyorum.
Sunita

11

Swift 4'te IBDesignable ve IBInspectable Kullanarak Gölge Çizimi

YAN YAN ÇİZİM VE XCODE

Gölge Örneği

KOD

@IBDesignable class ShadowView: UIView {

    @IBInspectable var shadowColor: UIColor? {
        get {
            if let color = layer.shadowColor {
                return UIColor(cgColor: color)
            }
            return nil
        }
        set {
            if let color = newValue {
                layer.shadowColor = color.cgColor
            } else {
                layer.shadowColor = nil
            }
        }
    }

    @IBInspectable var shadowOpacity: Float {
        get {
            return layer.shadowOpacity
        }
        set {
            layer.shadowOpacity = newValue
        }
    }

    @IBInspectable var shadowOffset: CGPoint {
        get {
            return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
        }
        set {
            layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
        }

     }

    @IBInspectable var shadowBlur: CGFloat {
        get {
            return layer.shadowRadius
        }
        set {
            layer.shadowRadius = newValue / 2.0
        }
    }

    @IBInspectable var shadowSpread: CGFloat = 0 {
        didSet {
            if shadowSpread == 0 {
                layer.shadowPath = nil
            } else {
                let dx = -shadowSpread
                let rect = bounds.insetBy(dx: dx, dy: dx)
                layer.shadowPath = UIBezierPath(rect: rect).cgPath
            }
        }
    }
}

ÇIKTI

DEMO ÇIKIŞI

BU NASIL KULLANILIR

DEMO


layer.shadowRadius * 2ShadowBlur getter için geri dönmemeli
berkuqo

7

Bu kod benim için çok iyi çalıştı:

yourView.layer.shadowOpacity = 0.2 // opacity, 20%
yourView.layer.shadowColor = UIColor.black.cgColor
yourView.layer.shadowRadius = 2 // HALF of blur
yourView.layer.shadowOffset = CGSize(width: 0, height: 2) // Spread x, y
yourView.layer.masksToBounds = false

Sketch'teki bulanıklık değeri, Core Animation'ın gölge yarıçapıyla eşleşmiyor .
CIFilter

Bizim için yeterince yakın çalışmaya son veren şey, Sketch for Core Animation'ın gölge yarıçapındaki bulanıklık değerini yarıya indirdi.
CIFilter

2

Önceden tanımlanmış bir yola gölge uygulamaya çalışanlar için (örneğin, dairesel bir görünüm için olduğu gibi), işte şunu buldum:

extension CALayer {
    func applyShadow(color: UIColor = .black,
                     alpha: Float = 0.5,
                     x: CGFloat = 0,
                     y: CGFloat = 2,
                     blur: CGFloat = 4,
                     spread: CGFloat = 0,
                     path: UIBezierPath? = nil) {
        shadowColor = color.cgColor
        shadowOpacity = alpha
        shadowRadius = blur / 2
        if let path = path {
            if spread == 0 {
                shadowOffset = CGSize(width: x, height: y)
            } else {
                let scaleX = (path.bounds.width + (spread * 2)) / path.bounds.width
                let scaleY = (path.bounds.height + (spread * 2)) / path.bounds.height

                path.apply(CGAffineTransform(translationX: x + -spread, y: y + -spread).scaledBy(x: scaleX, y: scaleY))
                shadowPath = path.cgPath
            }
        } else {
            shadowOffset = CGSize(width: x, height: y)
            if spread == 0 {
                shadowPath = nil
            } else {
                let dx = -spread
                let rect = bounds.insetBy(dx: dx, dy: dx)
                shadowPath = UIBezierPath(rect: rect).cgPath
            }
        }
        shouldRasterize = true
        rasterizationScale = UIScreen.main.scale
    }
}

Bazı örnekleri daha sonra yayınlayacağım, ancak bu benim için dairesel görünümler için yerinde çalıştı.


"Neredeyse" çalışır ancak bir yayılmasını kullandığınızda yayılması yanlıştır Bu 1ile xve y 0 shapeLayer.applyShadow(color: .black, alpha: 1, x: 0, y: 0, blur: 0, spread: 1, path: path). Bu durumda gölgenin bir ofseti vardır ve olmaması gerekir. İşte üçgen her yöne gölge yayılmış 1px olmalıdır ibb.co/YjwRb9B
Jan

1

Bu gönderiye dayanan çözümüm yanıt veriyor: (Swift 3)

let shadowPath = UIBezierPath(rect: CGRect(x: -1,
                                           y: -2,
                                           width: target.frame.width + 2,
                                           height: target.frame.height + 2))

target.layer.shadowColor = UIColor(hexString: shadowColor).cgColor
target.layer.shadowOffset = CGSize(width: CGFloat(shadowOffsetX), height: CGFloat(shadowOffsetY))
target.layer.masksToBounds = false
target.layer.shadowOpacity = Float(shadowOpacity)
target.layer.shadowPath = shadowPath.cgPath

0

Burada yayınlanan cevabı ve yorumlardaki önerileri gerçekten beğendim . Bu çözümü şu şekilde değiştirdim:

extension UIView {
  func applyShadow(color: UIColor, alpha: Float, x: CGFloat, y: CGFloat, blur: CGFloat, spread: CGFloat) {
    layer.masksToBounds = false
    layer.shadowColor = color.cgColor
    layer.shadowOpacity = alpha
    layer.shadowOffset = CGSize(width: x, height: y)
    layer.shadowRadius = blur / UIScreen.main.scale
    if spread == 0 {
      layer.shadowPath = nil
    } else {
      let dx = -spread
      let rect = bounds.insetBy(dx: dx, dy: dx)
      layer.shadowPath = UIBezierPath(rect: rect).cgPath
    }
  }
}

KULLANIM:

myButton.applyShadow(color: .black, alpha: 0.2, x: 0, y: 1, blur: 2, spread: 0)

-1

Tarihte küçük bir kazma olabilir, ama belki bazılarında aynı sorun vardı. Kabul edilen cevaptan kod örneği kullandım. Ancak efektler oldukça farklıdır: - y değeri eskizdeki aynı değere kıyasla yarı yarıya olmalı - Gezinme çubuğuna gölge uygulamaya çalıştım ve efekt çok farklı - çizimin sahip olduğu aynı değerleri kullanırken neredeyse hiç görünmüyor.

Dolayısıyla, yöntem tamamen taslak parametrelerini yansıtmıyor gibi görünüyor. Herhangi bir ipucu?


Bu bir cevap değil - yorumlar yorumlara giriyor!
Dave Y
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.