UIView with rounded corners and drop shadow?

前端 未结 30 2539
一整个雨季
一整个雨季 2020-11-22 08:00

I’ve been working on an application for a couple of years and received a simple design request: Round the corners on a UIView and add a drop shadow.To do as given below.

相关标签:
30条回答
  • 2020-11-22 08:25

    Something swifty tested in swift 4

    import UIKit
    
    extension UIView {
        @IBInspectable var dropShadow: Bool {
            set{
                if newValue {
                    layer.shadowColor = UIColor.black.cgColor
                    layer.shadowOpacity = 0.4
                    layer.shadowRadius = 1
                    layer.shadowOffset = CGSize.zero
                } else {
                    layer.shadowColor = UIColor.clear.cgColor
                    layer.shadowOpacity = 0
                    layer.shadowRadius = 0
                    layer.shadowOffset = CGSize.zero
                }
            }
            get {
                return layer.shadowOpacity > 0
            }
        }
    }
    

    Produces

    If you enable it in the Inspector like this:

    It will add the User Defined Runtime Attribute, resulting in:

    (I added previously the cornerRadius = 8)

    :)

    0 讨论(0)
  • 2020-11-22 08:26

    Swift

    // corner radius
    blueView.layer.cornerRadius = 10
    
    // border
    blueView.layer.borderWidth = 1.0
    blueView.layer.borderColor = UIColor.black.cgColor
    
    // shadow
    blueView.layer.shadowColor = UIColor.black.cgColor
    blueView.layer.shadowOffset = CGSize(width: 3, height: 3)
    blueView.layer.shadowOpacity = 0.7
    blueView.layer.shadowRadius = 4.0
    

    Exploring the options

    Problem 1: Shadow gets clipped off

    What if there are sublayers or subviews (like an image) whose content we want to clip to the bounds of our view?

    We can accomplish this with

    blueView.layer.masksToBounds = true
    

    (Alternatively, blueView.clipsToBounds = true gives the same result.)

    But, oh no! The shadow was also clipped off because it's outside of the bounds! What to do? What to do?

    Solution

    Use separate views for the shadow and the border. The base view is transparent and has the shadow. The border view clips any other subcontent that it has to its borders.

    // add the shadow to the base view
    baseView.backgroundColor = UIColor.clear
    baseView.layer.shadowColor = UIColor.black.cgColor
    baseView.layer.shadowOffset = CGSize(width: 3, height: 3)
    baseView.layer.shadowOpacity = 0.7
    baseView.layer.shadowRadius = 4.0
    
    // add the border to subview
    let borderView = UIView()
    borderView.frame = baseView.bounds
    borderView.layer.cornerRadius = 10
    borderView.layer.borderColor = UIColor.black.cgColor
    borderView.layer.borderWidth = 1.0
    borderView.layer.masksToBounds = true
    baseView.addSubview(borderView)
    
    // add any other subcontent that you want clipped
    let otherSubContent = UIImageView()
    otherSubContent.image = UIImage(named: "lion")
    otherSubContent.frame = borderView.bounds
    borderView.addSubview(otherSubContent)
    

    This gives the following result:

    Problem 2: Poor performance

    Adding rounded corners and shadows can be a performance hit. You can improve performance by using a predefined path for the shadow and also specifying that it be rasterized. The following code can be added to the example above.

    baseView.layer.shadowPath = UIBezierPath(roundedRect: baseView.bounds, cornerRadius: 10).cgPath
    baseView.layer.shouldRasterize = true
    baseView.layer.rasterizationScale = UIScreen.main.scale
    

    See this post for more details. See here and here also.

    This answer was tested with Swift 4 and Xcode 9.

    0 讨论(0)
  • 2020-11-22 08:26

    Check out the example project on GitHub to make sure you use the component correctly.

    Simple Swift 5 solution without any additional subviews or subclassing:

    extension UIView {
    
        func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {
            layer.masksToBounds = false
            layer.shadowOffset = offset
            layer.shadowColor = color.cgColor
            layer.shadowRadius = radius
            layer.shadowOpacity = opacity
    
            let backgroundCGColor = backgroundColor?.cgColor
            backgroundColor = nil
            layer.backgroundColor =  backgroundCGColor
        }
    }
    

    Note that you should set up your view with corner radius and other properties before calling addShadow.

    After that, just call this from viewDidLoad like this:

    button.addShadow(offset: CGSize.init(width: 0, height: 3), color: UIColor.black, radius: 2.0, opacity: 0.35)
    

    Final result:

    Super easy and simple!

    0 讨论(0)
  • 2020-11-22 08:27

    The following code snippet adds a border, border radius, and drop shadow to v, a UIView:

    // border radius
    [v.layer setCornerRadius:30.0f];
    
    // border
    [v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
    [v.layer setBorderWidth:1.5f];
    
    // drop shadow
    [v.layer setShadowColor:[UIColor blackColor].CGColor];
    [v.layer setShadowOpacity:0.8];
    [v.layer setShadowRadius:3.0];
    [v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];
    

    You can adjust the settings to suit your needs.

    Also, add the QuartzCore framework to your project and:

    #import <QuartzCore/QuartzCore.h>
    

    See my other answer regarding masksToBounds.


    Note

    This may not work in all cases. If you find that this method interferes with other drawing operations that you are performing, please see this answer.

    0 讨论(0)
  • 2020-11-22 08:27

    If you are struggling because of the rounded corners vs. subviews vs. masksToBounds, then try using my function:

    - (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
    {
        CGRect shadowFrame; // Modify this if needed
        shadowFrame.size.width = 0.f;
        shadowFrame.size.height = 0.f;
        shadowFrame.origin.x = 0.f;
        shadowFrame.origin.y = 0.f;
        UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
        shadow.userInteractionEnabled = NO; // Modify this if needed
        shadow.layer.shadowColor = color.CGColor;
        shadow.layer.shadowOffset = shadowOffset;
        shadow.layer.shadowRadius = shadowRadius;
        shadow.layer.masksToBounds = NO;
        shadow.clipsToBounds = NO;
        shadow.layer.shadowOpacity = shadowOpacity;
        [view.superview insertSubview:shadow belowSubview:view];
        [shadow addSubview:view];
        return shadow;
    }
    

    call it on your view. whether your view has rounded corners, no matter its size, its shape - a nice shadow will be drawn.

    Just keep the return value of the function so you can refer to it when you want to remove the table (or for example use insertSubview:aboveView:)

    0 讨论(0)
  • 2020-11-22 08:27

    Swift 4 Solution for making UICollectionViewCell round and adding Shadows, without any extensions and complications :)

    Note: For simple views e.g Buttons. See the @suragch's Answer in this post. https://stackoverflow.com/a/34984063/7698092. Tested successfully for buttons

    In case if any one still struggling to round the corners and add shadows at the same time. Although this solution works with UICollectionViewCell, it can be generalized to any view.

    This technique worked for me without making any extensions and all the complicated stuff. I am working with storyBoard.

    Technique

    You must add a UIView (lets say it "containerView") inside your UICollectionViewCell in storyBoard and add all the required views (buttons, images etc) inside this containerView. See the Screenshot.

    Connect the outlet for containerView. Add following lines of code in CellforItemAtIndexPath delegate function.

    //adds shadow to the layer of cell
    
    cell.layer.cornerRadius = 3.0
        cell.layer.masksToBounds = false
        cell.layer.shadowColor = UIColor.black.cgColor
        cell.layer.shadowOffset = CGSize(width: 0, height: 0)
        cell.layer.shadowOpacity = 0.6
    
    //makes the cell round 
    
    let containerView = cell.containerView!
        containerView.layer.cornerRadius = 8
        containerView.clipsToBounds = true
    

    Output

    See the simulator Screenshot

    0 讨论(0)
提交回复
热议问题