ios 快速创建一个只有两个圆角的矩形?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29618760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 05:36:18  来源:igfitidea点击:

Create a rectangle with just two rounded corners in swift?

iosswiftcore-graphics

提问by Maralc

I need to create a rectangle that have just two rounded corners in swift (Objective C code also ok).

我需要快速创建一个只有两个圆角的矩形(Objective C 代码也可以)。

At the moment my code is creating two rectangles with

目前我的代码正在创建两个矩形

CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 5, 5, nil);

and

CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 60), 0, 0, nil);

and merging them (to have two right angle corners and two rounded ones) but I am not happy with the code and I am pretty sure there should be much better ways to do it.

并合并它们(有两个直角和两个圆角)但我对代码不满意,我很确定应该有更好的方法来做到这一点。

I am new to iOS and graphical development and swift.

我是 iOS 和图形开发的新手,而且很快。

回答by iwasrobbed

Here's a quick Swift 3 extension you can use to do rounding and optional borders.

这是一个快速的 Swift 3 扩展,您可以使用它来进行舍入和可选边框。

Note: if you're using autolayout, you may need to call this in one of the view lifecycle callbacks like viewDidLayoutSubviewsor layoutSubviewsafter the view has been constrained.

注意:如果您使用自动布局,您可能需要在视图生命周期回调之一中调用它,例如viewDidLayoutSubviewslayoutSubviews在视图被约束之后。

import UIKit

extension UIView {

    /**
     Rounds the given set of corners to the specified radius

     - parameter corners: Corners to round
     - parameter radius:  Radius to round to
     */
    func round(corners: UIRectCorner, radius: CGFloat) {
        _ = _round(corners: corners, radius: radius)
    }

    /**
     Rounds the given set of corners to the specified radius with a border

     - parameter corners:     Corners to round
     - parameter radius:      Radius to round to
     - parameter borderColor: The border color
     - parameter borderWidth: The border width
     */
    func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
        let mask = _round(corners: corners, radius: radius)
        addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
    }

    /**
     Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border

     - parameter diameter:    The view's diameter
     - parameter borderColor: The border color
     - parameter borderWidth: The border width
     */
    func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
        layer.masksToBounds = true
        layer.cornerRadius = diameter / 2
        layer.borderWidth = borderWidth
        layer.borderColor = borderColor.cgColor;
    }

}

private extension UIView {

    @discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
        return mask
    }

    func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
        let borderLayer = CAShapeLayer()
        borderLayer.path = mask.path
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.lineWidth = borderWidth
        borderLayer.frame = bounds
        layer.addSublayer(borderLayer)
    }

}

回答by Sanjay Mohnani

In Swift 2.3you could do so by

Swift 2.3你可以这样做

let maskPath = UIBezierPath(roundedRect: anyView.bounds,
            byRoundingCorners: [.BottomLeft, .BottomRight],
            cornerRadii: CGSize(width: 10.0, height: 10.0))

let shape = CAShapeLayer()
shape.path = maskPath.CGPath
view.layer.mask = shape


In Objective-Cyou could use the UIBezierPathclass method

Objective-C 中,你可以使用UIBezierPathclass 方法

bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:

example implementation-

示例实现-

// set the corner radius to the specified corners of the passed container
- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
    UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
                                                  byRoundingCorners:corners
                                                        cornerRadii:CGSizeMake(10.0, 10.0)];
    CAShapeLayer *shape = [[CAShapeLayer alloc] init];
    [shape setPath:rounded.CGPath];
    view.layer.mask = shape;
}

and call the above method as-

并将上述方法称为-

[self setMaskTo:anyView byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight];

回答by wcarhart

Swift 4+, iOS 11+

斯威夫特 4+,iOS 11+

If you already have a UIViewnamed myViewreferenced as an IBOutlet, try adding the following two lines in ViewDidLoad()or wherever it's being loaded:

如果您已经有一个UIViewmyView引用为 an的命名IBOutlet,请尝试在ViewDidLoad()加载它的地方或任何地方添加以下两行:

myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]

You can change the array []to any combination of MinX, MinY, MaxX, and MaxYto select the desired corners. The above example rounds the bottom two corners.

可以将阵列改变[]到的任何组合MinXMinYMaxX,和MaxY选择所需的角落。上面的例子圆了底部的两个角。

This is just another approach, can be a bit simpler depending on your design.

这只是另一种方法,根据您的设计可能会更简单一些。

回答by budidino

Swift 3- Useful UIViewextension when you need to round specific corners of some views:

Swift 3-UIView当您需要圆某些视图的特定角时的有用扩展:

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

then just use it like this:

然后像这样使用它:

someView.round(corners: [.topLeft, .topRight], radius: 5)

回答by Eric

Building on top of Sanjay's excellent answer, I wrote a quick CALayer extension for Swift 2.3, in case you need to do this sort of "only round some corners" thing more than once.

以 Sanjay 的出色回答为基础,我为 Swift 2.3 编写了一个快速的 CALayer 扩展,以防您需要不止一次地做这种“只绕过某些角落”的事情。

extension CALayer {
  func roundCorners(corners: UIRectCorner, radius: CGFloat) {
    let maskPath = UIBezierPath(roundedRect: bounds,
                                byRoundingCorners: corners,
                                cornerRadii: CGSize(width: radius, height: radius))

    let shape = CAShapeLayer()
    shape.path = maskPath.CGPath
    mask = shape
  }
}

Usage:

用法:

myView.layer.roundCorners([.TopLeft, .TopRight], radius: myCornerRadius)

Swift 3.0 (In this example the bounds came from the view not from the layer. Using the bounds from the view make this code to work with views in a UITableViewCell.):

Swift 3.0(在这个例子中,边界来自视图而不是层。使用视图的边界使这段代码可以与 UITableViewCell 中的视图一起使用。):

func roundCorners(corners: UIRectCorner, radius: CGFloat, viewBounds: CGRect) {

    let maskPath = UIBezierPath(roundedRect: viewBounds,
                                byRoundingCorners: corners,
                                cornerRadii: CGSize(width: radius, height: radius))

    let shape = CAShapeLayer()
    shape.path = maskPath.cgPath
    mask = shape
}

Usage:

用法:

myView.layer.roundCorners(corners: [.topLeft, .topRight], radius: myCornerRadius, viewBounds: bounds)

回答by Andy

Here is what you do in Swift 2.0

这是您在Swift 2.0 中所做的

var maskPath = UIBezierPath(roundedRect: anyView.bounds,
        byRoundingCorners: [.BottomLeft, .BottomRight],
        cornerRadii: CGSize(width: 10.0, height: 10.0))

回答by Fattie

2017...

2017...

enter image description here

在此处输入图片说明

@IBDesignable
class RoundedEnds: UIView {

    override func layoutSubviews() { setup() } // "layoutSubviews" is best

    func setup() {
        let r = self.bounds.size.height / 2
        let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:r)
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
    }
}

For only some corners, just change to:

只有一些角落,只需更改为:

enter image description here

在此处输入图片说明

roundedRect: self.bounds,
  byRoundingCorners: [.topLeft, .topRight],
  cornerRadii: CGSize(width: r, height: r)

Note that as usual there have been many small changes in Swift, eg capitalization of constants, etc.

请注意,像往常一样,Swift 中有许多小的变化,例如常量的大写等。

回答by Bogdan Bystritskiy

Swift 4:

斯威夫特 4:

let maskPath = UIBezierPath(
            roundedRect: view.bounds,
            byRoundingCorners: [.allCorners],
            cornerRadii: CGSize(width: 10.0, height: 10.0)
        )

let shape = CAShapeLayer()
shape.path = maskPath.cgPath

view.layer.mask = shape

回答by cjnevin

Updated iWasRobbed's answer to work with the Swift 3.0 GM version:

更新了 iWasRobbed 的答案以使用 Swift 3.0 GM 版本:

import UIKit

extension UIView {

    /**
     Rounds the given set of corners to the specified radius

     - parameter corners: Corners to round
     - parameter radius:  Radius to round to
     */
    func round(corners: UIRectCorner, radius: CGFloat) {
        _round(corners: corners, radius: radius)
    }

    /**
     Rounds the given set of corners to the specified radius with a border

     - parameter corners:     Corners to round
     - parameter radius:      Radius to round to
     - parameter borderColor: The border color
     - parameter borderWidth: The border width
     */
    func round(corners: UIRectCorner, radius: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
        let mask = _round(corners: corners, radius: radius)
        addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
    }

    /**
     Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border

     - parameter diameter:    The view's diameter
     - parameter borderColor: The border color
     - parameter borderWidth: The border width
     */
    func fullyRound(diameter: CGFloat, borderColor: UIColor, borderWidth: CGFloat) {
        layer.masksToBounds = true
        layer.cornerRadius = diameter / 2
        layer.borderWidth = borderWidth
        layer.borderColor = borderColor.cgColor;
    }

}

private extension UIView {

    @discardableResult func _round(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
        return mask
    }

    func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) {
        let borderLayer = CAShapeLayer()
        borderLayer.path = mask.path
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.lineWidth = borderWidth
        borderLayer.frame = bounds
        layer.addSublayer(borderLayer)
    }

}

回答by rawnly

iOS 11+ Only | You can check iOS usage stats here

仅限 iOS 11+ | 您可以在此处查看 iOS 使用情况统计信息

Explanation

解释

Since the CACornerMaskrawValue is an UIntyou know that a CACornerMaskrawValueis the sum of each CACornerMask.ElementrawValue

由于CACornerMaskrawValue 是一个UInt你知道一个CACornerMaskrawValue是每个rawValue的总和CACornerMask.Element

More specifically:

进一步来说:

  • TopLeft (layerMinXMinYCorner) = 1
  • TopRight (layerMaxXMinYCorner) = 2
  • BottomLeft (layerMinXMaxYCorner) = 4
  • BottomRight (layerMaxXMaxYCorner) = 8
  • 左上角 ( layerMinXMinYCorner) = 1
  • 右上 ( layerMaxXMinYCorner) = 2
  • 左下角 ( layerMinXMaxYCorner) = 4
  • 右下角 ( layerMaxXMaxYCorner) = 8

So for example if you want top leftand top rightcorners you can just type CACornerMask(rawValue: 3).

因此,例如,如果您想要左上角右上角,则只需键入CACornerMask(rawValue: 3).



?Example

?例子

Below a simple extension of an UIView

下面是一个简单的扩展 UIView

extension UIView {
    enum Corner:Int {
        case bottomRight = 0,
        topRight,
        bottomLeft,
        topLeft
    }

    private func parseCorner(corner: Corner) -> CACornerMask.Element {
        let corners: [CACornerMask.Element] = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]
        return corners[corner.rawValue]
    }

    private func createMask(corners: [Corner]) -> UInt {
        return corners.reduce(0, { (a, b) -> UInt in
            return a + parseCorner(corner: b).rawValue
        })
    }

    func roundCorners(corners: [Corner], amount: CGFloat = 5) {
        layer.cornerRadius = amount
        let maskedCorners: CACornerMask = CACornerMask(rawValue: createMask(corners: corners))
        layer.maskedCorners = maskedCorners
    }
}

You can use this like:

你可以这样使用:

let myRect = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
myRect.roundCorners(corners: [.topRight, .topLeft])