iOS: Rounded rectangle with border bleeds color

£可爱£侵袭症+ 提交于 2019-12-28 13:05:30

问题


I'm drawing round avatar pics, by just applying cornerRadius to a UIImageView's layer, and also adding a border via borderWith and borderColor. Like so:

self.layer.masksToBounds = YES;
self.layer.cornerRadius = imageDimension / 2.f;
self.layer.borderWidth = 1.f;
self.layer.borderColor = borderColor.CGColor;

That works great, except for this tiny, but noticeable bleeding of content outside the border, like this:

Is there a way to just outset the border by a few 1/10 points, or inset the content more than the border?


Solution

Thanks to FelixLam, I came up with a nice solution and will leave it here for the afterworld:

@interface MMRoundImageViewWithBorder : UIView

- (id)initWithImage:(UIImage *)image borderWidth:(CGFloat)borderWidth;

@property (strong, nonatomic) UIImageView *imageView;
@property (assign, nonatomic) CGFloat borderWidth;
@property (strong, nonatomic) UIColor *borderColor;

@end

@implementation MMRoundImageViewWithBorder

- (id)initWithImage:(UIImage *)image borderWidth:(CGFloat)borderWidth {
    if (self = [super init]) {
        self.borderWidth = borderWidth;
        self.borderColor = UIColor.whiteColor;

        self.imageView = [[UIImageView alloc] initWithImage:image];
        [self addSubview:self.imageView];

        self.imageView.layer.masksToBounds = YES;
        self.layer.masksToBounds = YES;
    }
    return self;
}

- (void)setBorderColor:(UIColor *)borderColor {
    _borderColor = borderColor;
    self.backgroundColor = borderColor;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [self refreshDimensions];
}

- (void)refreshDimensions {
    self.layer.cornerRadius = CGRectGetWidth(self.bounds) / 2.f;

    self.imageView.frame = CGRectInset(self.bounds, _borderWidth, _borderWidth);
    self.imageView.layer.cornerRadius = CGRectGetWidth(self.imageView.bounds) / 2.f;
}

- (void)setBorderWidth:(CGFloat)borderWidth {
    _borderWidth = borderWidth;
    [self refreshDimensions];
}

- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];
    [self refreshDimensions];
}

@end

回答1:


You could try to use a CAShapelayer with a circular path as the mask for the Layer instead of using the corner radius.

Alternatively you can place the image view in a container that has the border and is one/two pixel larger.




回答2:


As said in comments, you can add a transparent border to the image so it will be ok. Here is a piece of code to do so (a category to UIImageView) :

+ (UIImage *)imageWithImage:(UIImage *)image withTransparentBorderOfWidth:(CGFloat)width {
    CGSize size = image.size;
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width + width * 2, size.height + width * 2), NO, 0.0);
    [image drawInRect:CGRectMake(width, width, size.width, size.height)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}



回答3:


OP's solution is unnecessarily complicated. An easier and cleaner solution. Create a UIView, clip to bounds, mask, border, and corner radius like above and then add a UIIamgeview as a subview of that UIView. The UIIamgeview will be clipped by the parent view and you won't have the bleeding issue.




回答4:


My UIButton needed a rounded corner radius which resulted in jagged edges. Setting borderStyle to .roundedRect fixed it.

button.borderStyle = .roundedRect
button.layer.cornerRadius = 4
button.layer.borderWidth = 1
button.layer.borderColor = .red.cgColor



回答5:


Here's a subclass of UIImageView that solves this problem.

As the accepted answer suggests, it adds a rounded CAShapeLayer that has a border width and a corner radius 1px larger than "wanted". Its frame starts at CGPoint(x: 1, y: 1) and has a height 2px larger than the height of the image view. That way, it covers the bleed-through.

Swift 3+ solution

Subclass:

class BorderedRoundedImageView: UIImageView {
    let borderLayer = CALayer()

    var borderWidth: CGFloat!
    var borderColor: UIColor!

    func setUp() {
        borderLayer.borderWidth = borderWidth + 1
        borderLayer.borderColor = borderColor.cgColor
        layer.addSublayer(borderLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        borderLayer.cornerRadius = layer.cornerRadius + 1
        borderLayer.frame = CGRect(x: -1, y: -1, width: frame.width + 2, height: frame.height + 2)
    }
}

Usage:

@IBOutlet weak var imageView: UIImageView!

[...]

imageView.layer.cornerRadius = 20
imageView.borderWidth = 2
imageView.borderColor = .lightGray
imageView.setUp()

Result:




回答6:


Try setting:

[self setClipToBounds:YES]



回答7:


I had the same problem and wanted a solution which would work well with a Storyboard. What I did was place my image inside of a view and then set both to a custom class which controls the behavior. I can now totally control the design from a Storyboard.

I've placed the code on GitHub.

https://github.com/brennanMKE/CircleButton

What it does is override the drawRect function in UIView for both a UIButton and regular UIView so it can work with many views. A wrapper view is also used to control the border color and width. I simply make sure there is some margin between the wrapped view and the superview and use the difference as the border width. The background color of the superview becomes the border color. Now I can make these changes quickly in many scenes in a Storyboard without custom coding each instance.

- (void)drawRect:(CGRect)rect {
    // round view and superview with a border using the background color of the superview
    self.layer.cornerRadius = CGRectGetWidth(self.frame) / 2;
    self.layer.masksToBounds = YES;

    if ([self.superview isKindOfClass:[SSTCircleWrapperView class]]) {
        self.superview.layer.cornerRadius = CGRectGetWidth(self.superview.frame) / 2;
        self.superview.layer.masksToBounds = YES;
        self.superview.layer.borderColor = self.superview.backgroundColor.CGColor;
        self.superview.layer.borderWidth = (CGRectGetWidth(self.superview.frame) - CGRectGetWidth(self.frame)) / 2;
    }
}


来源:https://stackoverflow.com/questions/19565736/ios-rounded-rectangle-with-border-bleeds-color

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!