UIView with shadow, rounded corners and custom drawRect

前端 未结 16 1283
南旧
南旧 2020-12-02 05:22

I have to create a custom UIView that will have round corners, a border, a shadow and its drawRect() method is overridden to provide custom drawing

相关标签:
16条回答
  • 2020-12-02 06:10

    The solution seems much easier than the problem might suggest. I had this with one of my views and used the core part of @Hodit's answer to get it to work. This is all you need actually:

    - (void) drawRect:(CGRect)rect {
        // make sure the background is set to a transparent color using IB or code
        // e.g.: self.backgroundColor = [UIColor clearColor]; 
    
        // draw a rounded rect in the view
        [[UIColor whiteColor] setFill];
        [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:5.0] fill];
    
        // apply shadow if you haven't already
        self.layer.masksToBounds = NO;
        self.layer.shadowColor = [[UIColor blackColor] CGColor];
        self.layer.shadowOffset = CGSizeMake(0.0,3.0);
        self.layer.shadowRadius= 1.0;
        self.layer.shadowOpacity = 0.1;
    
        // more code here
    
    }
    

    Note that this doesn't clip subviews. Anything positioned at 0,0 in the view will overlap the visible top left rounded corner.

    0 讨论(0)
  • 2020-12-02 06:10

    In addition to the Frederic Adda's solution, don't forget to position the view that has shadow with a padding to the superview, where the shadow can be drawn. Otherwise the shadow will be clipped off. I made this mistake in my custom cell, and thought the solution was wrong until I added a padding of 8px all around.

    0 讨论(0)
  • 2020-12-02 06:11

    This is a tricky one. UIView's clipsToBounds is necessary to get the rounded corners. But CALayer's masksToBounds has to be false so the shadow is visible. Somehow, everything works if drawRect is not overridden, but actually it shouldn't.

    The solution is to create a superview to provide the shadow (in the demonstration below this is the shadowView). You can test the following in Playground:

    class MyView : UIView {
        override func drawRect(rect: CGRect) {
            let c = UIGraphicsGetCurrentContext()
            CGContextAddRect(c, CGRectMake(10, 10, 80, 80))
            CGContextSetStrokeColorWithColor(c , UIColor.redColor().CGColor)
            CGContextStrokePath(c)
        }
    }
    
    let superview = UIView(frame: CGRectMake(0, 0, 200, 200))
    
    let shadowView = UIView(frame: CGRectMake(50, 50, 100, 100))
    shadowView.layer.shadowColor = UIColor.blackColor().CGColor
    shadowView.layer.shadowOffset = CGSizeZero
    shadowView.layer.shadowOpacity = 0.5
    shadowView.layer.shadowRadius = 5
    
    let view = MyView(frame: shadowView.bounds)
    view.backgroundColor = UIColor.whiteColor()
    view.layer.cornerRadius = 10.0
    view.layer.borderColor = UIColor.grayColor().CGColor
    view.layer.borderWidth = 0.5
    view.clipsToBounds = true
    
    shadowView.addSubview(view)
    superview.addSubview(shadowView)
    

    Result:

    enter image description here

    0 讨论(0)
  • 2020-12-02 06:13

    Here's the swift3 version of Hodit's answer, I had to use it and found it over here and did general corrections for XCode 8. Works like charm!

    @IBDesignable class RoundRectView: UIView {
    
    @IBInspectable var cornerRadius: CGFloat = 0.0
    @IBInspectable var borderColor: UIColor = UIColor.black
    @IBInspectable var borderWidth: CGFloat = 0.5
    private var customBackgroundColor = UIColor.white
    override var backgroundColor: UIColor?{
        didSet {
            customBackgroundColor = backgroundColor!
            super.backgroundColor = UIColor.clear
        }
    }
    
    func setup() {
        layer.shadowColor = UIColor.black.cgColor;
        layer.shadowOffset = CGSize.zero
        layer.shadowRadius = 5.0;
        layer.shadowOpacity = 0.5;
        super.backgroundColor = UIColor.clear
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }
    
    override func draw(_ rect: CGRect) {
        customBackgroundColor.setFill()
        UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius ?? 0).fill()
    
        let borderRect = bounds.insetBy(dx: borderWidth/2, dy: borderWidth/2)
        let borderPath = UIBezierPath(roundedRect: borderRect, cornerRadius: cornerRadius - borderWidth/2)
        borderColor.setStroke()
        borderPath.lineWidth = borderWidth
        borderPath.stroke()
    
        // whatever else you need drawn
    }
    }
    
    0 讨论(0)
提交回复
热议问题