Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 使用CALayers的圆形UIView-只有一些角-如何?_Iphone_Objective C_Xcode_Uiview_Calayer - Fatal编程技术网

Iphone 使用CALayers的圆形UIView-只有一些角-如何?

Iphone 使用CALayers的圆形UIView-只有一些角-如何?,iphone,objective-c,xcode,uiview,calayer,Iphone,Objective C,Xcode,Uiview,Calayer,在我的应用程序中,有四个按钮,名称如下: 左上角 左下角 右上角 右下角 按钮上方有一个图像视图或UIView 现在,假设用户点击左上角的按钮。上面的图像/视图应在该特定角处四舍五入 我在将圆角应用于UIView时遇到一些困难 现在,我使用以下代码将圆角应用于每个视图: // imgVUserImg is a image view on IB. imgVUserImg.image=[UIImage imageWithData:[NSData dataWithContentsOfU

在我的应用程序中,有四个按钮,名称如下:

左上角 左下角 右上角 右下角 按钮上方有一个图像视图或UIView

现在,假设用户点击左上角的按钮。上面的图像/视图应在该特定角处四舍五入

我在将圆角应用于UIView时遇到一些困难

现在,我使用以下代码将圆角应用于每个视图:

    // imgVUserImg is a image view on IB.
    imgVUserImg.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"any Url Here"];
    CALayer *l = [imgVUserImg layer];
    [l setMasksToBounds:YES];
    [l setCornerRadius:5.0];  
    [l setBorderWidth:2.0];
    [l setBorderColor:[[UIColor darkGrayColor] CGColor]];
上述代码将圆度应用于所提供视图的每个角。相反,我只想将圆度应用于选定的角点,如-top/top+left/bottom+right等

可能吗?如何操作?

请参阅。您必须将自己的矩形绘制到带有一些圆角的CGPath,将CGPath添加到CGContext,然后使用CGContextClip对其进行剪裁

您还可以将带有alpha值的圆角矩形绘制到图像中,然后使用该图像创建一个新层,并将其设置为图层的遮罩属性。

我使用at的答案和中的代码生成此代码

然后我意识到我回答了错误的问题,给出了一个完整的UILabel而不是UIImage,因此我使用以下代码来更改它:

使用视图模板创建iPhone项目。在视图控制器中,添加以下内容:

- (void)viewDidLoad
{
    CGRect rect = CGRectMake(10, 10, 200, 100);
    MyView *myView = [[MyView alloc] initWithFrame:rect];
    [self.view addSubview:myView];
    [super viewDidLoad];
}
MyView只是一个UIImageView子类:

@interface MyView : UIImageView
{
}
我以前从未使用过图形上下文,但我成功地将这些代码拼凑在一起。其中两个角的代码丢失了。如果您阅读代码,您可以看到我是如何通过删除一些CGContextAddArc调用和代码中的一些radius值来实现这一点的。所有角点的代码都在那里,因此将其作为起点,删除创建不需要的角点的部分。请注意,如果需要,您也可以制作具有2或3个圆角的矩形

代码并不完美,但我相信你可以稍微整理一下

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float radius, int roundedCornerPosition)
{

    // all corners rounded
    //  CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
    //  CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
    //  CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, 
    //                  radius, M_PI / 4, M_PI / 2, 1);
    //  CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, 
    //                          rect.origin.y + rect.size.height);
    //  CGContextAddArc(context, rect.origin.x + rect.size.width - radius, 
    //                  rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
    //  CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius);
    //  CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, 
    //                  radius, 0.0f, -M_PI / 2, 1);
    //  CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
    //  CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, 
    //                  -M_PI / 2, M_PI, 1);

    // top left
    if (roundedCornerPosition == 1) {
        CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
        CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
        CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, 
                        radius, M_PI / 4, M_PI / 2, 1);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, 
                                rect.origin.y + rect.size.height);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
        CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y);
    }   

    // bottom left
    if (roundedCornerPosition == 2) {
        CGContextMoveToPoint(context, rect.origin.x, rect.origin.y);
        CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, 
                                rect.origin.y + rect.size.height);
        CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
        CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
        CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, 
                        -M_PI / 2, M_PI, 1);
    }

    // add the other corners here


    CGContextClosePath(context);
    CGContextRestoreGState(context);
}


-(UIImage *)setImage
{
    UIImage *img = [UIImage imageNamed:@"my_image.png"];
    int w = img.size.width;
    int h = img.size.height;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

    CGContextBeginPath(context);
    CGRect rect = CGRectMake(0, 0, w, h);


    addRoundedRectToPath(context, rect, 50, 1);
    CGContextClosePath(context);
    CGContextClip(context);

    CGContextDrawImage(context, rect, img.CGImage);

    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    [img release];

    return [UIImage imageWithCGImage:imageMasked];
}

不要忘了,您需要在其中安装QuartzCore框架才能正常工作。

从iOS 3.2开始,您可以使用UIBezierPath的功能创建一个开箱即用的圆角矩形,其中只有您指定的角是圆角的。然后,您可以将其用作CAShapeLayer的路径,并将其用作视图层的遮罩:

// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds 
                                               byRoundingCorners:UIRectCornerTopLeft
                                                     cornerRadii:CGSizeMake(10.0, 10.0)];

// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageView.bounds;
maskLayer.path = maskPath.CGPath;

// Set the newly created shape layer as the mask for the image view's layer
imageView.layer.mask = maskLayer;
就这样-不要在核心图形中手动定义形状,也不要在Photoshop中创建遮罩图像。该层甚至不需要失效。应用圆角或更改为新的角点与定义新的UIBezierPath并将其CGPath用作遮罩层的路径一样简单。bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:方法的corners参数是一个位掩码,因此可以通过将多个角组合在一起进行圆角。

编辑:添加阴影 如果你想给它添加一个阴影,需要做更多的工作

由于imageView.layer.mask=maskLayer应用遮罩,因此通常不会在其外部显示阴影。诀窍是使用透明视图,然后将两个子层Calayer添加到视图的层:shadowLayer和roundedLayer。两者都需要使用UIBezierPath。图像将作为roundedLayer的内容添加


我在我的代码中的很多地方都使用过这段代码,它100%正确。您可以通过更改一个属性byRoundingCorners:UIRectCornerBottomLeft来更改任何录像机

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

                CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
                maskLayer.frame = view.bounds;
                maskLayer.path = maskPath.CGPath;
                view.layer.mask = maskLayer;
                [maskLayer release];

有一个更简单、更快的答案,可以根据您的需要使用,也可以使用阴影。可以将超层上的maskToBounds设置为true,并偏移子层,使其两个角位于超层边界之外,从而有效地将两个边上的圆角切掉


当然,只有当您希望在同一侧只有两个圆角,并且从一侧剪切几个像素时,层的内容看起来是相同的时,这才有效。使条形图只在顶部四舍五入非常有用。

Stuarts将特定角四舍五入的示例非常有用。如果你想绕多个角,比如左上角和右上角,这就是方法

// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageview
                                               byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight
                                                     cornerRadii:CGSizeMake(10.0, 10.0)];

// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageview.bounds;
maskLayer.path = maskPath.CGPath;

// Set the newly created shape layer as the mask for the image view's layer
imageview.layer.mask = maskLayer; 

只舍入一些角不会很好地进行自动调整大小或自动布局


因此,另一种选择是使用常规的拐角半径,并将不需要的拐角隐藏在另一个视图下或其superview边界之外,确保将其设置为剪辑其内容。

总结Stuart的答案,可以使用如下圆角方法:

@implementation UIView (RoundCorners)

- (void)applyRoundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];

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

    self.layer.mask = maskLayer;
}

@end
因此,要应用圆角,只需执行以下操作:

[self.imageView applyRoundCorners:UIRectCornerTopRight|UIRectCornerTopLeft radius:10];

虽然已经晚了五年,但我认为目前人们这样做的方式并非100%正确。很多人都有过这样的问题:使用UIBezierPath+CAShapeLayer方法会干扰自动布局,特别是当它设置在情节提要上时。没有答案,所以我决定加上我自己的

有一种非常简单的方法可以避免这种情况:在drawRect:CGRect函数中绘制圆角

举个例子,如果我想上一轮 对于UIView,我将子类UIView,然后在适当的地方使用该子类

import UIKit

class TopRoundedView: UIView {

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)

        var maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: UIRectCorner.TopLeft | UIRectCorner.TopRight, cornerRadii: CGSizeMake(5.0, 5.0))

        var maskLayer = CAShapeLayer()
        maskLayer.frame = self.bounds
        maskLayer.path = maskPath.CGPath

        self.layer.mask = maskLayer
    }
}

这是解决问题的最佳方法,不需要花任何时间去适应。

谢谢分享。在这里,我想分享swift 2.0的解决方案,以供进一步参考。要符合UIRectCorner的协议

let mp = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.bottomLeft, .TopLeft], cornerRadii: CGSize(width: 10, height: 10))
let ml = CAShapeLayer()
ml.frame = self.bounds
ml.path = mp.CGPath
self.layer.mask = ml
带Swift 3+语法的CALayer扩展

它可以像这样使用:

let layer: CALayer = yourView.layer
layer.round(roundedRect: yourView.bounds, byRoundingCorners: [.bottomLeft, .topLeft], cornerRadii: CGSize(width: 5, height: 5))
为了添加到和,我在Swift中创建了一个简单的、可重用的UIView。根据您的用例,您可能希望进行修改,以避免在每个布局上创建对象等,但我希望使其尽可能简单。如果您不喜欢子类化,扩展允许您将此应用于其他视图的ex.UIImageView

extension UIView {

    func roundCorners(_ roundedCorners: UIRectCorner, toRadius radius: CGFloat) {
        roundCorners(roundedCorners, toRadii: CGSize(width: radius, height: radius))
    }

    func roundCorners(_ roundedCorners: UIRectCorner, toRadii cornerRadii: CGSize) {
        let maskBezierPath = UIBezierPath(
            roundedRect: bounds,
            byRoundingCorners: roundedCorners,
            cornerRadii: cornerRadii)
        let maskShapeLayer = CAShapeLayer()
        maskShapeLayer.frame = bounds
        maskShapeLayer.path = maskBezierPath.cgPath
        layer.mask = maskShapeLayer
    }
}

class RoundedCornerView: UIView {

    var roundedCorners: UIRectCorner = UIRectCorner.allCorners
    var roundedCornerRadii: CGSize = CGSize(width: 10.0, height: 10.0)

    override func layoutSubviews() {
        super.layoutSubviews()
        roundCorners(roundedCorners, toRadii: roundedCornerRadii)
    }
}
以下是如何将其应用于UIViewController:


在iOS 11中,我们现在只能绕过一些拐角

let view = UIView()

view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

我建议定义图层的遮罩。遮罩本身应该是具有专用路径的CAShapeLayer对象。您可以使用下一个UIView扩展Swift 4.2:

extension UIView {
    func round(corners: UIRectCorner, with radius: CGFloat) {
        let maskLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = UIBezierPath(
            roundedRect: bounds,
            byRoundingCorners: corners,
            cornerRadii: CGSize(width: radius, height: radius)
        ).cgPath
        layer.mask = maskLayer
   }
}

很好的一个,这在分组UITableView单元格的selectedBackgroundViews上帮了我很多忙:-不管怎样,在转弯后要给这个视图添加阴影吗?尝试以下操作但未成功。`self.layer.masksToBounds=否;self.layer.shadowColor=[UIColor blackColor].CGColor;self.layer.shadowRadius=3;self.layer.shadowOffset=CGSizeMake-3,3;self.layer.shadowOpacity=0.8;self.layer.shouldRasterize=是`@克丽斯瓦格纳:关于向圆形视图应用阴影,请参见我的编辑。@StuDev好极了!我已经为阴影视图选择了一个子视图,但这要好多了!没想到会这样添加子层。谢谢为什么我的图像会变成白色,那么当我滚动UITableView并重新创建单元格时,它会工作!为什么?在UITableView子视图(例如UITableViewCells或UITableViewHeaderFooterView)上使用此解决方案时,滚动时会导致平滑度差。另一种使用方法是性能更好的解决方案,它为所有角添加了一个角半径。为了只“显示”特定的圆角,如右上角和右下角,我在frame.origin.x上添加了一个子视图,并为其图层指定了拐角半径。如果有人找到了更好的解决方案,我很感兴趣。在UITableView子视图(例如UITableViewCells或UITableViewHeaderFooterView)上使用此解决方案时,滚动时会导致平滑度差。另一种使用方法是性能更好的解决方案,它为所有角添加了一个角半径。为了只“显示”特定的圆角,如右上角和右下角,我在frame.origin.x上添加了一个子视图,并为其图层指定了拐角半径。如果有人找到了更好的解决方案,我很感兴趣。对于大小可能会改变的视图,它不能像预期的那样工作。示例:UILabel。设置掩码路径,然后通过设置文本来更改大小,将保留旧掩码。将需要子类化和重载drawRect。这不是解决问题的正确方法。只有在视图中进行自定义绘图(例如使用核心图形)时,才应覆盖drawRect_u3;,否则即使是空的实现也会影响性能。每次创建一个新的遮罩层也是不必要的。实际需要做的只是在视图边界更改时更新遮罩层的“路径”特性,而执行此操作的位置在layoutSubviews方法的覆盖范围内。
class MyViewController: UIViewController {

    private var _view: RoundedCornerView {
        return view as! RoundedCornerView
    }

    override func loadView() {
        view = RoundedCornerView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        _view.roundedCorners = [.topLeft, .topRight]
        _view.roundedCornerRadii = CGSize(width: 10.0, height: 10.0)
    }
}
let view = UIView()

view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
extension UIView {
    func round(corners: UIRectCorner, with radius: CGFloat) {
        let maskLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = UIBezierPath(
            roundedRect: bounds,
            byRoundingCorners: corners,
            cornerRadii: CGSize(width: radius, height: radius)
        ).cgPath
        layer.mask = maskLayer
   }
}