UIView 阴影和 InterfaceBuilder

发布于 2024-12-05 18:47:00 字数 410 浏览 2 评论 0原文

我想使用 CALayer 添加阴影到 UI(Image)View。 以下代码通常工作正常

previewImage.layer.shadowColor = [[UIColor blackColor] CGColor];
previewImage.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
previewImage.layer.shadowOpacity = 1.0f;
previewImage.layer.shadowRadius = 8.0f;

但是,只有当我以编程方式创建该视图并将其作为子视图添加到我的主视图中时,这才有效。当该视图在 InterfaceBuilder 中设置并定义为 IBOutlet UIImageView 时,这不起作用。没有影子出现。 那么我在这里缺少什么?

I want to add a drop shadow using CALayer to a UI(Image)View.
The following code works generally fine

previewImage.layer.shadowColor = [[UIColor blackColor] CGColor];
previewImage.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
previewImage.layer.shadowOpacity = 1.0f;
previewImage.layer.shadowRadius = 8.0f;

However, this only works if I create that view programmatically and add it as a subview to my main view. When that view is set up in InterfaceBuilder and defined as an IBOutlet UIImageView this does NOT work. No shadow appears.
So what am I missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绿萝 2024-12-12 18:47:00

在您的项目中添加一个名为 UIView.swift 的文件(或将其粘贴到任何文件中):

import UIKit

@IBDesignable extension UIView {

    /* The color of the shadow. Defaults to opaque black. Colors created
    * from patterns are currently NOT supported. Animatable. */
    @IBInspectable var shadowColor: UIColor? {
        set {
            layer.shadowColor = newValue!.CGColor
        }
        get {
            if let color = layer.shadowColor {
                return UIColor(CGColor:color)
            }
            else {
                return nil
            }
        }
    }

    /* The opacity of the shadow. Defaults to 0. Specifying a value outside the
    * [0,1] range will give undefined results. Animatable. */
    @IBInspectable var shadowOpacity: Float {
        set {
            layer.shadowOpacity = newValue
        }
        get {
            return layer.shadowOpacity
        }
    }

    /* The shadow offset. Defaults to (0, -3). Animatable. */
    @IBInspectable var shadowOffset: CGPoint {
        set {
            layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
        }
        get {
            return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
        }
    }

    /* The blur radius used to create the shadow. Defaults to 3. Animatable. */
    @IBInspectable var shadowRadius: CGFloat {
        set {
            layer.shadowRadius = newValue
        }
        get {
            return layer.shadowRadius
        }
    }
}

然后,这将在 Interface Builder 中为 Utilities Panel > 中的每个视图提供。属性检查器:

实用工具面板< /a>

您现在可以轻松设置阴影。

备注:
- 阴影只会在运行时出现。
- clipsToBounds 应该为 false(默认情况下为 false)

Add a file named UIView.swift in your project (or just paste this in any file) :

import UIKit

@IBDesignable extension UIView {

    /* The color of the shadow. Defaults to opaque black. Colors created
    * from patterns are currently NOT supported. Animatable. */
    @IBInspectable var shadowColor: UIColor? {
        set {
            layer.shadowColor = newValue!.CGColor
        }
        get {
            if let color = layer.shadowColor {
                return UIColor(CGColor:color)
            }
            else {
                return nil
            }
        }
    }

    /* The opacity of the shadow. Defaults to 0. Specifying a value outside the
    * [0,1] range will give undefined results. Animatable. */
    @IBInspectable var shadowOpacity: Float {
        set {
            layer.shadowOpacity = newValue
        }
        get {
            return layer.shadowOpacity
        }
    }

    /* The shadow offset. Defaults to (0, -3). Animatable. */
    @IBInspectable var shadowOffset: CGPoint {
        set {
            layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
        }
        get {
            return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
        }
    }

    /* The blur radius used to create the shadow. Defaults to 3. Animatable. */
    @IBInspectable var shadowRadius: CGFloat {
        set {
            layer.shadowRadius = newValue
        }
        get {
            return layer.shadowRadius
        }
    }
}

Then this will be available in Interface Builder for every view in the Utilities Panel > Attributes Inspector :

Utilities Panel

You can easily set the shadow now.

Notes:
- The shadow will only appear at runtime.
- clipsToBounds should be false (by default it is)

以酷 2024-12-12 18:47:00

我知道这个问题已经很久了,但最近我遇到了类似的情况,所以我决定为那些处于这种情况的人提供我的答案。

我希望能够通过 Interface Builder 在 UIView 上设置 borderColorshadowColor,但是图层的 borderColor 的类型 属性是 CGColor (就像 shadowColor),它不是用户定义的运行时属性功能中允许更改的类型之一。

因此,我为 CALayer 做了扩展,并添加了两个名为 borderColorIB 和 ShadowColorIB 的 UIColor 类型属性:

RuntimeAttributes.h

@import QuartzCore;

@interface CALayer (IBConfiguration)

@property(nonatomic, assign) UIColor* borderColorIB;
@property(nonatomic, assign) UIColor* shadowColorIB;

@end

RuntimeAttributes.m

#import <UIKit/UIKit.h>
#import "RuntimeAttributes.h"

@implementation CALayer (IBConfiguration)

-(void)setBorderColorIB:(UIColor*)color
{
    self.borderColor = color.CGColor;
}

-(UIColor*)borderColorIB
{
    return [UIColor colorWithCGColor:self.borderColor];
}

-(void)setShadowColorIB:(UIColor*)color
{
    self.shadowColor = color.CGColor;
}

-(UIColor*)shadowColorIB
{
    return [UIColor colorWithCGColor:self.shadowColor];
}

@end

现在我已经能够通过 Interface Builder 设置这两个属性,如下所示:

  1. 在“用户定义的运行时属性”部分(身份检查器)
  2. 确保选择了 UIView,并添加以下运行时属性:

    • layer.borderWidth,数字,1
    • layer.borderColorIB, Color, someColor <- 我用于设置 borderColor 的自定义属性
    • layer.shadowColorIB, Color, someColor <- 我用于设置shadowColor的自定义属性
    • layer.shadowOpacity,数字,0.8
    • layer.shadowOffset,大小,{5,5}
    • layer.cornerRadius,数字,5

这里有一张图片向您展示我是如何做的:

在此处输入图像描述

... 结果将是在运行时明显,而不是在 Xcode 中:

在此处输入图像描述

我希望这可以帮助一些人!

I know this question has long, but recently i was in a similar situation so i decided to put my answer for those who are in a situation like this.

I wanted to be able to set the borderColor and shadowColor on an UIView through the Interface Builder, but the type of a layer’s borderColor property is CGColor (just like shadowColor) which is not one of the types allowed to be changed in the user-defined runtime attributes feature.

So i made an extension for CALayerand i added two properties called borderColorIB and shadowColorIB that are of type UIColor:

RuntimeAttributes.h

@import QuartzCore;

@interface CALayer (IBConfiguration)

@property(nonatomic, assign) UIColor* borderColorIB;
@property(nonatomic, assign) UIColor* shadowColorIB;

@end

RuntimeAttributes.m

#import <UIKit/UIKit.h>
#import "RuntimeAttributes.h"

@implementation CALayer (IBConfiguration)

-(void)setBorderColorIB:(UIColor*)color
{
    self.borderColor = color.CGColor;
}

-(UIColor*)borderColorIB
{
    return [UIColor colorWithCGColor:self.borderColor];
}

-(void)setShadowColorIB:(UIColor*)color
{
    self.shadowColor = color.CGColor;
}

-(UIColor*)shadowColorIB
{
    return [UIColor colorWithCGColor:self.shadowColor];
}

@end

Now i alredy be able to set this two properties through Interface Builder like this:

  1. In the 'user-defined runtime attributes' section (Identity inspector)
  2. Make sure the UIView is selected, and add the following runtime attributes:

    • layer.borderWidth, Number, 1
    • layer.borderColorIB, Color, someColor <- my custom property to set the borderColor
    • layer.shadowColorIB, Color, someColor <- my custom property to set the shadowColor
    • layer.shadowOpacity, Number, 0.8
    • layer.shadowOffset, size, {5,5}
    • layer.cornerRadius, Number, 5

Here is an image to show you how i did:

enter image description here

... and The result will be apparent during runtime, not in Xcode:

enter image description here

i hope this can help some people out there!

拥醉 2024-12-12 18:47:00

我不确定问题是什么 - 确保您的 UIImageViewclipsToBounds 属性设置为 NO。从 nib 文件加载后,您可以通过引用 IBOutlet 在 viewDidLoad 中执行此操作。您不需要将其包装在另一个视图中。

编辑

鉴于您需要使用宽高比填充来缩放图像,您可以使用 UIImageView 底层的 contentsRect 属性来“模拟”内容剪辑的效果。 contentsRect 是图层内容(在本例中为图像)的单位坐标空间中的矩形,它定义了应绘制的内容的子矩形。

通过一点数学知识,我们可以通过比较图像视图大小与图像大小(考虑宽高比填充缩放)来找到这个矩形:

CGSize imageViewSize = previewImage.size;
CGSize imageSize = previewImage.image.size;

// Find the scaling required for the image to fit the image view (as for aspect fill).
CGFloat imageWidthScale = fabsf(imageViewSize.width / imageSize.width);
CGFloat imageHeightScale = fabsf(imageViewSize.height / imageSize.height);
CGFloat imageScale = (imageWidthScale > imageHeightScale) ? imageWidthScale : imageHeightScale;

// Determine the new image size, after scaling.
CGSize scaledImageSize = CGSizeApplyAffineTransform(imageSize, CGAffineTransformMakeScale(imageScale, imageScale));

// Set the layer's contentsRect property in order to 'clip' the image to the image view's bounds.
previewImage.layer.contentsRect = CGRectMake(((scaledImageSize.width - imageViewSize.width) / 2.0f) / scaledImageSize.width,
                                             ((scaledImageSize.height - imageViewSize.height) / 2.0f) / scaledImageSize.height,
                                             imageViewSize.width / scaledImageSize.width,
                                             imageViewSize.height / scaledImageSize.height);

这样做,您可以将 clipsToBounds 设置为 对于您的图像视图,NO,但图像仍然会被剪切。如果您需要更改图像视图大小,则将此代码包装到采用 UIImageView 作为参数的方法中可能会很方便。

我希望这有帮助。

I'm not sure what the issue is - ensure your UIImageView's clipsToBounds property is set to NO. You can do this in viewDidLoad after loading from the nib file by referencing your IBOutlet. You shouldn't need to wrap it in another view.

Edit

In light of you needing your image to be scaled using aspect fill, you can use the contentsRect property of the UIImageView's underlying layer to 'simulate' the effect of the contents clipping. contentsRect is rectangle in the unit coordinate space of the layer's content (in this case your image) that defines a sub-rectangle of the contents that should be drawn.

With a little bit of maths, we can find this rectangle by comparing the image view size with the image size (accounting for the aspect fill scaling):

CGSize imageViewSize = previewImage.size;
CGSize imageSize = previewImage.image.size;

// Find the scaling required for the image to fit the image view (as for aspect fill).
CGFloat imageWidthScale = fabsf(imageViewSize.width / imageSize.width);
CGFloat imageHeightScale = fabsf(imageViewSize.height / imageSize.height);
CGFloat imageScale = (imageWidthScale > imageHeightScale) ? imageWidthScale : imageHeightScale;

// Determine the new image size, after scaling.
CGSize scaledImageSize = CGSizeApplyAffineTransform(imageSize, CGAffineTransformMakeScale(imageScale, imageScale));

// Set the layer's contentsRect property in order to 'clip' the image to the image view's bounds.
previewImage.layer.contentsRect = CGRectMake(((scaledImageSize.width - imageViewSize.width) / 2.0f) / scaledImageSize.width,
                                             ((scaledImageSize.height - imageViewSize.height) / 2.0f) / scaledImageSize.height,
                                             imageViewSize.width / scaledImageSize.width,
                                             imageViewSize.height / scaledImageSize.height);

Doing this, you can leave clipsToBounds set to NO for your image view, but the image will still appear clipped. If you need to change the image view size at all, it might be convenient to wrap this code up into a method that takes a UIImageView as a parameter.

I hope this helps.

美人如玉 2024-12-12 18:47:00

mauricioconde 的答案的 Swift 5 Xcode 11.3.1 版本。请注意,如果没有@IBInspectable,它将无法工作。

import UIKit
import QuartzCore

extension CALayer {

    @IBInspectable
    var shadowUIColor: UIColor? {
        get { shadowColor != nil ? UIColor(cgColor: shadowColor!) : nil }
        set { shadowColor = newValue?.cgColor }
    }
}

输入图片此处描述

Swift 5 Xcode 11.3.1 version of mauricioconde's answer. Note that without @IBInspectable it wouldn't work.

import UIKit
import QuartzCore

extension CALayer {

    @IBInspectable
    var shadowUIColor: UIColor? {
        get { shadowColor != nil ? UIColor(cgColor: shadowColor!) : nil }
        set { shadowColor = newValue?.cgColor }
    }
}

enter image description here

温暖的光 2024-12-12 18:47:00

带圆角半径的 UIView 阴影 + 界面生成器 - swift4

    extension UIView {

        @IBInspectable
        var cornerRadius: CGFloat {
            get {
                return layer.cornerRadius
            }
            set {
                layer.cornerRadius = newValue
                if shadowOpacity > 0.0 {
                    layer.masksToBounds = false
                }
                else {
                    layer.masksToBounds = true
                }
            }
        }
      @IBInspectable
        var borderWidth: CGFloat {
            get {
                return layer.borderWidth
            }
            set {
                layer.borderWidth = newValue
            }
        }
    @IBInspectable
        var borderColor: UIColor? {
            get {
                if let color = layer.borderColor {
                    return UIColor(cgColor: color)
                }
                return nil
            }
            set {
                if let color = newValue {
                    layer.borderColor = color.cgColor
                } else {
                    layer.borderColor = nil
                }
            }
      @IBInspectable var shadowColor: UIColor? {
            set {
                layer.shadowColor = newValue!.cgColor
            }
            get {
                if let color = layer.shadowColor {
                    return UIColor(cgColor: color)
                }
                else {
                    return nil
                }
            }
        }
       @IBInspectable var shadowOpacity: Float {
            set {
                layer.shadowOpacity = newValue
            }
            get {
                return layer.shadowOpacity
            }
        }
     @IBInspectable var shadowOffset: CGPoint {
            set {
                layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
            }
            get {
                return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
            }
        }
     @IBInspectable var shadowRadius: CGFloat {
            set {
                layer.shadowRadius = newValue
            }
            get {
                return layer.shadowRadius
            }
        }
}

UIView shadow with corner radius + interface builder - swift4

    extension UIView {

        @IBInspectable
        var cornerRadius: CGFloat {
            get {
                return layer.cornerRadius
            }
            set {
                layer.cornerRadius = newValue
                if shadowOpacity > 0.0 {
                    layer.masksToBounds = false
                }
                else {
                    layer.masksToBounds = true
                }
            }
        }
      @IBInspectable
        var borderWidth: CGFloat {
            get {
                return layer.borderWidth
            }
            set {
                layer.borderWidth = newValue
            }
        }
    @IBInspectable
        var borderColor: UIColor? {
            get {
                if let color = layer.borderColor {
                    return UIColor(cgColor: color)
                }
                return nil
            }
            set {
                if let color = newValue {
                    layer.borderColor = color.cgColor
                } else {
                    layer.borderColor = nil
                }
            }
      @IBInspectable var shadowColor: UIColor? {
            set {
                layer.shadowColor = newValue!.cgColor
            }
            get {
                if let color = layer.shadowColor {
                    return UIColor(cgColor: color)
                }
                else {
                    return nil
                }
            }
        }
       @IBInspectable var shadowOpacity: Float {
            set {
                layer.shadowOpacity = newValue
            }
            get {
                return layer.shadowOpacity
            }
        }
     @IBInspectable var shadowOffset: CGPoint {
            set {
                layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
            }
            get {
                return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
            }
        }
     @IBInspectable var shadowRadius: CGFloat {
            set {
                layer.shadowRadius = newValue
            }
            get {
                return layer.shadowRadius
            }
        }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文