108

重ねて表示されているビューにドロップシャドウを追加しようとしています。ビューが折りたたまれて、他のビューのコンテンツが表示されるようになります。このview.clipsToBoundsように、ビューが折りたたまれたときにコンテンツがクリップされるように、オンのままにしておきます。

clipsToBoundsこれにより、オンにするとシャドウもクリップされるため、レイヤーにドロップシャドウを追加するのが難しくなったようです。

フレームにドロップシャドウを追加するために操作しようとしview.frameましview.boundsたが、境界を十分に大きくしてそれを囲むことができましたが、これはうまくいきませんでした。

これが私がシャドウを追加するために使用しているコードです(これはclipsToBounds示されているようにOFFでのみ機能します)

view.clipsToBounds = NO;
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowOffset = CGSizeMake(0,5);
view.layer.shadowOpacity = 0.5;

これは、一番上の最も明るい灰色のレイヤーに適用されている影のスクリーンショットです。clipsToBoundsうまくいけば、これにより、オフの場合にコンテンツがどのようにオーバーラップするかがわかります。

シャドウアプリケーション。

UIViewシャドウを追加してコンテンツをクリップしたままにするにはどうすればよいですか?

編集:シャドウをオンにした背景画像を使用して遊んだことも追加したかったのですが、これはうまく機能しますが、これに最適なコード化されたソリューションを知りたいと思います。

4

7 に答える 7

282

これを試して:

UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:view.bounds];
view.layer.masksToBounds = NO;
view.layer.shadowColor = [UIColor blackColor].CGColor;
view.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
view.layer.shadowOpacity = 0.5f;
view.layer.shadowPath = shadowPath.CGPath;

まず第一にUIBezierPath使用されるのshadowPathは非常に重要です。使用しない場合、最初は違いに気付かないかもしれませんが、鋭い目は、デバイスの回転などのイベント中に発生する特定のラグを観察します。これは重要なパフォーマンスの調整です。

特にあなたの問題に関して:重要な行はview.layer.masksToBounds = NOです。ビューの境界を超えて拡張するビューのレイヤーのサブレイヤーのクリッピングを無効にします。

masksToBounds(レイヤー上で)ビュー自体のプロパティとの違いが何であるか疑問に思っている人のためにclipToBounds:実際には何もありません。一方を切り替えると、もう一方にも影響があります。抽象化のレベルが異なります。


Swift 2.2:

override func layoutSubviews()
{
    super.layoutSubviews()

    let shadowPath = UIBezierPath(rect: bounds)
    layer.masksToBounds = false
    layer.shadowColor = UIColor.blackColor().CGColor
    layer.shadowOffset = CGSizeMake(0.0, 5.0)
    layer.shadowOpacity = 0.5
    layer.shadowPath = shadowPath.CGPath
}

スウィフト3:

override func layoutSubviews()
{
    super.layoutSubviews()

    let shadowPath = UIBezierPath(rect: bounds)
    layer.masksToBounds = false
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
    layer.shadowOpacity = 0.5
    layer.shadowPath = shadowPath.cgPath
}
于 2012-03-18T19:06:57.393 に答える
66

Swift 2.3でのWasabiiの答え:

let shadowPath = UIBezierPath(rect: view.bounds)
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.blackColor().CGColor
view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
view.layer.shadowOpacity = 0.2
view.layer.shadowPath = shadowPath.CGPath

そしてSwift3/4/5では:

let shadowPath = UIBezierPath(rect: view.bounds)
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
view.layer.shadowOpacity = 0.2
view.layer.shadowPath = shadowPath.cgPath

AutoLayoutを使用している場合は、このコードをlayoutSubviews()に配置します。

SwiftUIでは、これはすべてはるかに簡単です。

Color.yellow  // or whatever your view
    .shadow(radius: 3)
    .frame(width: 200, height: 100)
于 2014-12-12T13:45:39.027 に答える
13

秘訣はmasksToBounds、ビューのレイヤーのプロパティを適切に定義することです。

view.layer.masksToBounds = NO;

そしてそれは動作するはずです。

出典

于 2012-03-18T19:07:04.523 に答える
13

UIViewの拡張機能を作成して、デザインエディターでこれらの値にアクセスできます

デザインエディタのシャドウオプション

extension UIView{

    @IBInspectable var shadowOffset: CGSize{
        get{
            return self.layer.shadowOffset
        }
        set{
            self.layer.shadowOffset = newValue
        }
    }

    @IBInspectable var shadowColor: UIColor{
        get{
            return UIColor(cgColor: self.layer.shadowColor!)
        }
        set{
            self.layer.shadowColor = newValue.cgColor
        }
    }

    @IBInspectable var shadowRadius: CGFloat{
        get{
            return self.layer.shadowRadius
        }
        set{
            self.layer.shadowRadius = newValue
        }
    }

    @IBInspectable var shadowOpacity: Float{
        get{
            return self.layer.shadowOpacity
        }
        set{
            self.layer.shadowOpacity = newValue
        }
    }
}
于 2017-04-06T15:41:46.713 に答える
8

ストーリーボードからのビューにシャドウを設定することもできます

ここに画像の説明を入力してください

于 2018-03-22T07:12:16.627 に答える
2

viewWillLayoutSubviewsの場合:

override func viewWillLayoutSubviews() {
    sampleView.layer.masksToBounds =  false
    sampleView.layer.shadowColor = UIColor.darkGrayColor().CGColor;
    sampleView.layer.shadowOffset = CGSizeMake(2.0, 2.0)
    sampleView.layer.shadowOpacity = 1.0
}

UIViewの拡張機能の使用:

extension UIView {

    func addDropShadowToView(targetView:UIView? ){
        targetView!.layer.masksToBounds =  false
        targetView!.layer.shadowColor = UIColor.darkGrayColor().CGColor;
        targetView!.layer.shadowOffset = CGSizeMake(2.0, 2.0)
        targetView!.layer.shadowOpacity = 1.0
    }
}

使用法:

sampleView.addDropShadowToView(sampleView)
于 2016-04-13T07:12:46.690 に答える
0

そうです、パフォーマンスのためにshadowPathプロパティを優先する必要がありますが、次のことも行う必要があります。CALayer.shadowPathのヘッダーファイルから

このプロパティを使用してパスを明示的に指定すると、通常はレンダリングパフォーマンスが向上し、複数のレイヤー間で同じパス参照を共有するようになります。

あまり知られていないトリックは、複数のレイヤー間で同じ参照を共有することです。もちろん、同じ形状を使用する必要がありますが、これはテーブル/コレクションビューセルで一般的です。

インスタンスを共有するとなぜ速くなるのかわかりません。シャドウのレンダリングをキャッシュし、ビュー内の他のインスタンスに再利用できると思います。これはもっと速いのだろうか

于 2019-05-03T23:39:36.293 に答える