UIView with rounded corners and drop shadow?

前端 未结 30 2537
一整个雨季
一整个雨季 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:14
    extension UIView {
        func dropRoundedShadowForAllSides() {
            let backgroundView = UIView(frame:self.frame)
            let radius = frame.height/2
            backgroundView.layer.masksToBounds = false
            self.layer.masksToBounds = true
            backgroundView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
            backgroundView.layer.shadowRadius = 4
            backgroundView.layer.shadowOpacity = 0.4
    
            let path = UIBezierPath()
    
            // Start at the Top Left Corner + radius distance
            path.move(to: CGPoint(x: 2*radius, y: 0.0))
    
            // Move to the Top Right Corner - radius distance
            path.addLine(to: CGPoint(x: backgroundView.frame.size.width - radius, y: 0.0))
    
            // Move to top right corner + radius down as curve
            let centerPoint1 = CGPoint(x:backgroundView.frame.size.width - radius,y:radius)
            path.addArc(withCenter: centerPoint1, radius: radius, startAngle: 3*(.pi/2), endAngle: 0, clockwise: true)
    
            // Move to the Bottom Right Corner - radius
            path.addLine(to: CGPoint(x: backgroundView.frame.size.width, y: backgroundView.frame.size.height - radius))
    
            // Move to top right corner + radius left as curve
            let centerPoint2 = CGPoint(x:backgroundView.frame.size.width - radius,y:backgroundView.frame.size.height - radius)
            path.addArc(withCenter: centerPoint2, radius: radius, startAngle: 0, endAngle: .pi/2, clockwise: true)
    
            // Move to the Bottom Left Corner - radius
            path.addLine(to: CGPoint(x: radius, y: backgroundView.frame.size.height))
    
            // Move to left right corner - radius up as curve
            let centerPoint3 = CGPoint(x:radius,y:backgroundView.frame.size.height - radius)
            path.addArc(withCenter: centerPoint3, radius: radius, startAngle: .pi/2, endAngle: .pi, clockwise: true)
    
            // Move to the top Left Corner - radius
            path.addLine(to: CGPoint(x: 0, y: radius))
    
            // Move to top right corner + radius down as curve
            let centerPoint4 = CGPoint(x:radius,y:radius)
            path.addArc(withCenter: centerPoint4, radius: radius, startAngle: .pi, endAngle: 3 * (.pi/2), clockwise: true)
    
            path.close()
    
            backgroundView.layer.shadowPath = path.cgPath
            if let superView = self.superview {
                superView.addSubview(backgroundView)
                superView.sendSubview(toBack: backgroundView)
                superView.bringSubview(toFront: self)
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-11-22 08:15

    I write this UIView category method to solve this problem, uses separate views for the shadow and the corner radius.

    -(UIView *)shadowedWrapViewWithBounds:(CGRect)bounds {
    UIView *baseView = [[UIView alloc] init];
    baseView.bounds = bounds;
    baseView.backgroundColor = [UIColor clearColor];
    baseView.layer.shadowColor = [UIColor blackColor].CGColor;
    baseView.layer.shadowOffset = CGSizeMake(0, 0);
    baseView.layer.shadowOpacity = 0.7;
    baseView.layer.shadowRadius = 4.0;
    
    // improve performance
    baseView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:baseView.bounds cornerRadius:4].CGPath;
    baseView.layer.shouldRasterize = YES;
    baseView.layer.rasterizationScale = [UIScreen mainScreen].scale;
    
    [baseView addSubview:self];
    //use Masonry autolayout, self can set corner radius
    [self makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(baseView);
    }];
    
    return baseView;
    }
    
    0 讨论(0)
  • 2020-11-22 08:16

    This worked for me. Trick was to move the background color from the main view to the layer.

    CALayer *layer = view.layer;
    layer.cornerRadius = 15.0f;
    layer.masksToBounds = NO;
    
    layer.shadowOffset = CGSizeMake(0, 3);
    layer.shadowColor = [[UIColor blackColor] CGColor];
    layer.shadowRadius = 2.0f;
    layer.shadowOpacity = 0.35f;
    layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:layer.cornerRadius] CGPath];
    
    CGColorRef  bColor = view.backgroundColor.CGColor;
    view.backgroundColor = nil;
    layer.backgroundColor =  bColor ;
    
    0 讨论(0)
  • 2020-11-22 08:17

    I solved the problem using the following trick when assigning shadow path for the container view :

    [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]
    

    Notice that the path given to the shadow is a rounded rectangle with the same corner radius as the background that the cell contains:

    //this is the border for the UIView that is added to a cell
    cell.backgroundView.layer.cornerRadius = 12;
    cell.backgroundView.layer.masksToBounds = YES;
    cell.backgroundView.layer.borderColor = [UIColor darkGrayColor].CGColor;
    cell.backgroundView.layer.borderWidth = 1;
    
    //this is the shadow around the cell itself (cannot have round corners with borders and shadow, need to use two views
    cell.layer.shadowRadius = 2;
    cell.layer.cornerRadius = 12;
    cell.layer.masksToBounds = NO;
    [[cell layer] setShadowColor:[[UIColor darkGrayColor] CGColor]];
    
    [[cell layer] setShadowOffset:CGSizeMake(0.0,0.0)];
    [[cell layer] setShadowOpacity:1.0];
    
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12];
    [[cell layer] setShadowPath:[path CGPath]];
    
    0 讨论(0)
  • 2020-11-22 08:17

    This is how you do it, with rounded corners and rounded shadows without bothering with paths.

    //Inner view with content
    [imageView.layer setBorderColor:[[UIColor lightGrayColor] CGColor]];
    [imageView.layer setBorderWidth:1.0f];
    [imageView.layer setCornerRadius:8.0f];
    [imageView.layer setMasksToBounds:YES];
    
    //Outer view with shadow
    UIView* shadowContainer = [[UIView alloc] initWithFrame:imageView.frame];
    [shadowContainer.layer setMasksToBounds:NO];
    [shadowContainer.layer setShadowColor:[[UIColor blackColor] CGColor]];
    [shadowContainer.layer setShadowOpacity:0.6f];
    [shadowContainer.layer setShadowRadius:2.0f];
    [shadowContainer.layer setShadowOffset: CGSizeMake(0.0f, 2.0f)];
    
    [shadowContainer addSubview:imageView];
    

    The view with content, in my case a UIImageView, has a corner radius and therefore has to mask to bounds.

    We create another equally sized view for the shadows, set it's maskToBounds to NO and then add the content view to the container view (e.g. shadowContainer).

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

    daniel.gindi's answer above did the trick for me! (+1 daniel) However, I had to make minor adjustments - change the shadowFrame size to be same as view's frame size, and enable user interaction. Here's the updated code:

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

    I would like to add that in my case, I was trying to add this to a 3rd party view controller, i.e. I did not have direct control over the code. So, here's how I used the function above:

    UIView *shadow = [self putView:vc.view 
             insideShadowWithColor:[UIColor blackColor]
                         andRadius:5.0 
                         andOffset:CGSizeMake(0.0, 0.0) 
                        andOpacity:1.0];
    vc.view = shadow;
    vc.view.layer.cornerRadius = 5.0;
    vc.view.layer.masksToBounds = YES;
    
    0 讨论(0)
提交回复
热议问题