【问题标题】:UIBezierPath does not draw rounded bottom cornersUIBezierPath 不绘制圆角底角
【发布时间】:2013-04-16 10:16:57
【问题描述】:

我正在尝试为我的观点制作圆角并解决一个奇怪的问题。

我使用以下代码为我的视图制作圆角

bezierPath = [UIBezierPath bezierPathWithRoundedRect:btnView.bounds
                                       byRoundingCorners:UIRectCornerAllCorners
                                             cornerRadii:radius];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.frame = btnView.bounds;
    maskLayer.path = bezierPath.CGPath;
    btnView.layer.mask = maskLayer;

问题是,它不适用于底角。如果我使用UIRectCornerBottomLeft,则不会发生任何事情,如果我使用UIRectCornerAllCorners,则只有顶角是圆角的。

编辑:我不使用 layer.cornerRadius 因为我只想圆底角。

事实证明,如果我从视图中删除 UIViewAutoresizingFlexibleHeight 自动调整大小掩码,我没有问题。但我想使用自动调整大小的蒙版。如果可以,有可能吗?

我已经尝试在设置图层蒙版之前和之后设置 autoresizingMask。运气不好!

【问题讨论】:

  • 为什么不直接使用 layer.cornerradius?
  • 对@LithuT.V 我在发表评论之前先发布答案:)
  • @LithuT.V 我已经更新了我的问题。
  • @ParasJoshi :是的,我发表了评论,同时你把它作为答案。

标签: iphone ios uiview rounded-corners uibezierpath


【解决方案1】:

然后用波纹管代码代替圆角...

btnView.layer.cornerRadius = 8.0;

只需在您的.m 中导入QuartzCore/QuartzCore.h,如下所示...

#import <QuartzCore/QuartzCore.h>

更新:

为此,您可以使用UIBezierPath 的不同RoundingCorners 属性,如下所示......

例如:UIRectCornerBottomLeft,UIRectCornerBottomRight,UIRectCornerTopLeft,UIRectCornerTopRightUIRectCornerAllCorners

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect: btnView.bounds
                                               byRoundingCorners:UIRectCornerBottomLeft
                                                     cornerRadii:CGSizeMake(10.0, 10.0)];

CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = btnView.bounds;
maskLayer.path = maskPath.CGPath;
btnView.layer.mask = maskLayer;
[btnView setNeedsDisplay];

【讨论】:

【解决方案2】:

您可以使用view.layer.cornerRadius 设置圆角。

已编辑:使用以下内容

 layer.mask = MTDContextCreateRoundedMask(layer.bounds, topleftRadius, topRightRadius, bottomLeftRadius,bottomRightRadius);

这是支持的方法。

static inline UIImage* MTDContextCreateRoundedMask(CGRect rect, CGFloat radius_tl, CGFloat radius_tr, CGFloat radius_bl, CGFloat radius_br)
{
    CGContextRef context;
    CGColorSpaceRef colorSpace;

    colorSpace = CGColorSpaceCreateDeviceRGB();

    context = CGBitmapContextCreate( NULL, rect.size.width, rect.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast );

    CGColorSpaceRelease(colorSpace);

    if ( context == NULL ) {
        return NULL;
    }


    CGFloat minx = CGRectGetMinX( rect ), midx = CGRectGetMidX( rect ), maxx = CGRectGetMaxX( rect );
    CGFloat miny = CGRectGetMinY( rect ), midy = CGRectGetMidY( rect ), maxy = CGRectGetMaxY( rect );

    CGContextBeginPath( context );
    CGContextSetGrayFillColor( context, 1.0, 0.0 );
    CGContextAddRect( context, rect );
    CGContextClosePath( context );
    CGContextDrawPath( context, kCGPathFill );

    CGContextSetGrayFillColor( context, 1.0, 1.0 );
    CGContextBeginPath( context );
    CGContextMoveToPoint( context, minx, midy );
    CGContextAddArcToPoint( context, minx, miny, midx, miny, radius_bl );
    CGContextAddArcToPoint( context, maxx, miny, maxx, midy, radius_br );
    CGContextAddArcToPoint( context, maxx, maxy, midx, maxy, radius_tr );
    CGContextAddArcToPoint( context, minx, maxy, minx, midy, radius_tl );
    CGContextClosePath( context );
    CGContextDrawPath( context, kCGPathFill );

    CGImageRef bitmapContext = CGBitmapContextCreateImage( context );
    CGContextRelease( context );

    UIImage *theImage = [UIImage imageWithCGImage:bitmapContext];
    CGImageRelease(bitmapContext);

    return theImage.layer.mask;
}

【讨论】:

  • 我得到“函数 MTDContextCreateRoundedMask 的隐式声明无效”。而且我找不到任何关于该函数的文档这是一个私有 API 吗?
  • 我收到警告“不兼容的指针类型从 UIImage * 分配给 CALayer *”,如果我运行它会因访问错误而崩溃
【解决方案3】:

在我得到另一个答案之前,如果可以将 autoresizingMask 与 UIBezierPath 一起使用,我会说 NO 并标记为正确答案。

我不会删除我的问题,因为任何人都可以在不知道原因的情况下排除同样的问题。

【讨论】:

  • 只需在 dispatch_async(dispatch_get_main_queue(), ^{ // make round corner }) 中尝试您的代码;
  • 这有什么原因吗?我在 viewDidLoad() 和 viewDidLayoutSubviews() 中做到了这一点,但没有任何效果。当我应用 dispatch_main 时它起作用了......看起来很奇怪。有什么原因吗?
【解决方案4】:

我刚刚遇到了一个类似的问题,需要几个小时才能解决 - 答案非常简单:将我的代码从 viewDidLoad 移动到 viewDidLayoutSubviews:这是自动布局完成后调用的第一个方法......所以我怀疑我确实有4 个圆角,但不知何故它们超出了屏幕边缘。

【讨论】:

  • 轮流中 viewDidLayoutSubviews 不会被调用并且不适合自动布局。
【解决方案5】:

解决方案:

-(void)roundCorners:(UIRectCorner)corner radius:(float)radius
{   
    _cornerRadius = radius;
    _corner = corner;
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    // Drawing code
    [super drawRect:rect];

    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:_corner cornerRadii:CGSizeMake(_cornerRadius, _cornerRadius)];

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = self.bounds;
    maskLayer.path = maskPath.CGPath;

    self.layer.mask = maskLayer;
}

【讨论】:

    【解决方案6】:

    不得不改变视角。由于自动调整大小,viewDidLoad 中的底角无法使用。必须将代码移动到 viewDidAppear。

    -(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    
    CGRect bounds = self.view.bounds;
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerBottomLeft) cornerRadii:CGSizeMake(5.0, 5.0)];
    
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = bounds;
    maskLayer.path = maskPath.CGPath;
    self.view.layer.mask = maskLayer;
    
    self.view.layer.masksToBounds = YES;
    [self.view setNeedsDisplay];
    }
    

    【讨论】:

      【解决方案7】:

      我终于成功了,它确实有效。试试吧。

      CGRect frame = self.accountBackgroundImage2.frame;
      frame.size.height = self.view.bounds.size.height;
      UIBezierPath *path=[UIBezierPath bezierPathWithRoundedRect:self.accountBackgroundImage2.bounds byRoundingCorners:(UIRectCornerBottomLeft |UIRectCornerBottomRight) cornerRadii:CGSizeMake(12.5, 12.5)];
      
      CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
      shapeLayer.frame = self.accountBackgroundImage2.bounds;
      shapeLayer.path  = path.CGPath;
      _accountBackgroundImage2.layer.mask = shapeLayer;
      self.accountBackgroundImage2.frame = frame;
      

      【讨论】:

        【解决方案8】:

        另一种方式

        在“viewWillLayoutSubviews”中执行

        - (void)viewWillLayoutSubviews{
        [self roundCornersOnView:self.buttonJoin onTopLeft:NO topRight:YES bottomLeft:YES bottomRight:NO radius:10.0];
        }
        

        功能

        -(UIButton *)roundCornersOnView:(UIButton *)button onTopLeft:(BOOL)tl topRight:(BOOL)tr bottomLeft:(BOOL)bl bottomRight:(BOOL)br radius:(float)radius {
        
        if (tl || tr || bl || br) {
            UIRectCorner corner = 0; //holds the corner
            //Determine which corner(s) should be changed
            if (tl) {
                corner = corner | UIRectCornerTopLeft;
            }
            if (tr) {
                corner = corner | UIRectCornerTopRight;
            }
            if (bl) {
                corner = corner | UIRectCornerBottomLeft;
            }
            if (br) {
                corner = corner | UIRectCornerBottomRight;
            }
        
            UIButton *roundedView = button;
            UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:roundedView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(radius, radius)];
            CAShapeLayer *maskLayer = [CAShapeLayer layer];
            maskLayer.frame = roundedView.bounds;
            maskLayer.path = maskPath.CGPath;
            roundedView.layer.mask = maskLayer;
            return roundedView;
        } else {
            return button;
        }
        

        }

        【讨论】:

          【解决方案9】:

          我认为你应该使用

          bezierPath.lineCapStyle = CGLineCap.Round
          

          【讨论】: