web-dev-qa-db-ja.com

コーナー半径と影を追加できません

画像に影と角の半径を描画しようとしています。別々に追加することはできますが、両方のエフェクトを同時に追加する方法がありません。私は影を追加しています:

[layer setShadowOffset:CGSizeMake(0, 3)];
[layer setShadowOpacity:0.4];
[layer setShadowRadius:3.0f];
[layer setShouldRasterize:YES];

ここで、layerはUIViewサブクラスのCALayerです。だからこれは私が設定するたびに機能します

[layer setMasksToBounds:NO];

次に、コーナー半径を追加します。これを行います。

[layer setCornerRadius:7.0f];

ただし、これを機能させるには、MasksToBoundsをYESに設定する必要があります。

[layer setMasksToBounds:YES];

とにかく、これらの両方の効果を追加することができますか?

御時間ありがとうございます、

デニス

33
Denis

はい、あります...

コーナー半径とドロップシャドウの両方が必要な場合は、-masksToBoundsをオンにするのではなく、コーナー半径を設定してベジェパスを設定します。丸みを帯びた長方形の影の。 2つの半径を同じに保ちます。

[layer setShadowOffset:CGSizeMake(0, 3)];
[layer setShadowOpacity:0.4];
[layer setShadowRadius:3.0f];
[layer setShouldRasterize:YES];

[layer setCornerRadius:12.0f];
[layer setShadowPath:
                   [[UIBezierPath bezierPathWithRoundedRect:[self bounds]
                                               cornerRadius:12.0f] CGPath]];

シャドウパスを設定したら、-shouldRasterizeパラメーターを設定せずにパフォーマンスを確認することをお勧めします。シャドウパスを設定すると、描画パフォーマンスが非常に良くなる傾向があります。

[〜#〜] update [〜#〜]

この問題についてはしばらく調べていませんでしたが、これを機能させるためにshadowPathを設定する必要がなくなったようです。 cornerRadiusshadowOpacityを設定するだけで機能するようになりました。私が知る限り、これはiOS5以降のケースだと思います。これらのパラメータの設定は「正常に機能する」ため、この更新を提供する必要はおそらくありませんが、後世のために提供します。要約すると、これで必要なのはこれだけです。

[layer setShadowOpacity:0.4];
[layer setCornerRadius:12.0f];

それでもパフォーマンスを向上させる必要がある場合は、先に進んでshouldRasterizeパラメーターを設定することもできます。

[layer setShouldRasterize:YES];

また、パフォーマンスについて言えば、アニメーションの速度が遅いことに気付いた場合は、結局、シャドウパスを設定する手法を使用する必要があることに注意してください。この更新は、実際には、コーナー半径とシャドウの両方を同時に表示する効果を実現するためにパスを設定する必要がなくなったことを指摘するためのものでした。ただし、パフォーマンスを優先する場合は、パスを使用してください。

更新2

場合によってはこれを機能させるのに問題があるように思われるので、私が作成したサンプルプロジェクトからより完全なコードスニペットをここに投稿します。

- (void)viewDidLoad
{
  [super viewDidLoad];

  CALayer *layer = [CALayer layer];
  [layer setBounds:CGRectMake(0.0f, 0.0f, 100.0f, 200.0f)];
  [layer setPosition:[[self view] center]];
  [layer setBackgroundColor:[[UIColor lightGrayColor] CGColor]];
  [layer setShadowOpacity:0.55f];
  [layer setCornerRadius:8.0f];
  [layer setBorderWidth:1.0f];

  [[[self view] layer] addSublayer:layer];

  [[[self testView] layer] setShadowOpacity:0.55f];
  [[[self testView] layer] setShadowRadius:15.0f];
  [[[self testView] layer] setCornerRadius:8.0f];
  [[[self testView] layer] setBorderWidth:1.0f];
}

testViewは、Interface Builderで追加し、アウトレットを設定したUIViewです。これは、明示的に追加した両方のレイヤーとサブビュー内のレイヤーで同じように機能することを確認するためです。

IOS5からiOS6.1のシミュレーターでこれをテストしました。それはそれらのそれぞれで私にこの結果を与えます:

enter image description here

59
Matt Long

次のSwift 3コードは、CAShapeLayerCALayerを使用して画像に影と角の半径を描画する方法を示しています。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // constants
        let radius: CGFloat = 20, offset = 8
        let rect = CGRect(x: 0, y: 0, width: 200, height: 200)

        // roundedView
        let roundedView = UIView()
        view.addSubview(roundedView)

        // shadow layer
        let shadowLayer = CALayer()
        shadowLayer.shadowColor = UIColor.darkGray.cgColor
        shadowLayer.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath
        shadowLayer.shadowOffset = CGSize(width: offset, height: offset)
        shadowLayer.shadowOpacity = 0.8
        shadowLayer.shadowRadius = 2
        roundedView.layer.addSublayer(shadowLayer)

        // mask layer
        let maskLayer = CAShapeLayer()
        maskLayer.path = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath

        // image layer
        let imageLayer = CALayer()
        imageLayer.mask = maskLayer
        imageLayer.frame = rect
        imageLayer.contentsGravity = kCAGravityResizeAspectFill
        imageLayer.contents = UIImage(named: "image")?.cgImage
        roundedView.layer.addSublayer(imageLayer)

        // auto layout
        roundedView.translatesAutoresizingMaskIntoConstraints = false
        roundedView.widthAnchor.constraint(equalToConstant: rect.width).isActive = true
        roundedView.heightAnchor.constraint(equalToConstant: rect.height).isActive = true
        roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }

}

このコードは、次の表示を生成します。

enter image description here


前のコードは、次のSwiftファイルにリファクタリングできます:

CustomView.Swift

import UIKit

class CustomView: UIView {

    var imageLayer: CALayer!
    var image: UIImage? {
        didSet { refreshImage() }
    }

    override var intrinsicContentSize:


        CGSize {
        return CGSize(width: 200, height: 200)
    }

    func refreshImage() {
        if let imageLayer = imageLayer, let image = image {
            imageLayer.contents = image.cgImage
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        if imageLayer == nil {
            let radius: CGFloat = 20, offset: CGFloat = 8

            let shadowLayer = CALayer()
            shadowLayer.shadowColor = UIColor.darkGray.cgColor
            shadowLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
            shadowLayer.shadowOffset = CGSize(width: offset, height: offset)
            shadowLayer.shadowOpacity = 0.8
            shadowLayer.shadowRadius = 2
            layer.addSublayer(shadowLayer)

            let maskLayer = CAShapeLayer()
            maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath

            imageLayer = CALayer()
            imageLayer.mask = maskLayer
            imageLayer.frame = bounds
            imageLayer.backgroundColor = UIColor.red.cgColor
            imageLayer.contentsGravity = kCAGravityResizeAspectFill
            layer.addSublayer(imageLayer)
        }


        refreshImage()
    }

}

ViewController.Swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let roundedView = CustomView()
        roundedView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(roundedView)

        // auto layout
        let horizontalConstraint = roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        let verticalConstraint = roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])

        roundedView.image = UIImage(named: "image")
    }

}

これで、画像を丸みを帯びた角と影と組み合わせる他の方法を見つけることができます Githubリポジトリ

3
Imanou Petit

背景画像でUIButtonを使用しているため、これらの回答はどれもうまくいきませんでした。ボタンに影がないか、丸いエッジがありません。

私のシナリオで最も簡単な方法は、ボタンの後ろに別のビューを追加し、次のようにシャドウを追加することでした。

button.clipsToBounds=YES;
button.layer.cornerRadius = 25;

UIView *shadowView = [[UIView alloc]initWithFrame:button.frame];

shadowView.backgroundColor = [UIColor whiteColor];//needs this to cast shadow
shadowView.layer.cornerRadius = 25;
shadowView.clipsToBounds = YES;
shadowView.layer.masksToBounds = NO;
shadowView.layer.shadowOffset = CGSizeMake(0, 2);
shadowView.layer.shadowRadius = 1;
shadowView.layer.shadowOpacity = 0.2;


[[button superview]addSubview:shadowView];
[[button superview]bringSubviewToFront:button];
3
Dirk de Boer