Разный угол для каждого угла Swift 3 - iOS

Я хочу установить другой радиус угла для представления в Swift -3, я могу установить радиус для каждого угла на такое же значение, как и тот, который упоминается в следующем сообщении, как установить cornerRadius только для верхнего левого и верхнего правого угла угол UIView?

Есть ли способ установить радиус угла в следующем формате? Радиус слева вверху: 18 Радиус справа вверху: 18 Радиус справа внизу: 3 Радиус слева внизу: 18


person Vinodha Sundaramoorthy    schedule 09.11.2016    source источник
comment
см. этот ответ: stackoverflow.com/questions/10316902/   -  person Nhat Dinh    schedule 09.11.2016


Ответы (4)


Вы можете установить layer.cornerRadius по умолчанию на наименьшее значение, а затем установить границу маски слоя на большее значение.

let demoView = UIView(frame: CGRect(x: 100, y: 200, width: 100, height: 100))
demoView.backgroundColor = UIColor.red
demoView.layer.cornerRadius = 3.0

let maskPath = UIBezierPath(roundedRect: demoView.bounds,
                            byRoundingCorners: [.topLeft, .topRight, .bottomLeft],
                            cornerRadii: CGSize(width: 18.0, height: 0.0))

let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
demoView.layer.mask = maskLayer
view.addSubview(demoView)
person Marcos Griselli    schedule 09.11.2016
comment
Работает, как и ожидалось. Большое спасибо. - person Vinodha Sundaramoorthy; 09.11.2016
comment
Не работает с границей. Там в любом случае ? Спасибо - person Ali Ihsan URAL; 02.07.2018

Вы хотите добавить уникальное значение угла для каждого угла?

Вы хотите после этого добавить границу?

У меня есть решение, которое будет выглядеть так:

выглядит так

Сначала добавьте сделанное мной UIBezierPath расширение:

extension UIBezierPath {
    convenience init(shouldRoundRect rect: CGRect, topLeftRadius: CGSize = .zero, topRightRadius: CGSize = .zero, bottomLeftRadius: CGSize = .zero, bottomRightRadius: CGSize = .zero){

        self.init()

        let path = CGMutablePath()

        let topLeft = rect.origin
        let topRight = CGPoint(x: rect.maxX, y: rect.minY)
        let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY)
        let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY)

        if topLeftRadius != .zero{
            path.move(to: CGPoint(x: topLeft.x+topLeftRadius.width, y: topLeft.y))
        } else {
            path.move(to: CGPoint(x: topLeft.x, y: topLeft.y))
        }

        if topRightRadius != .zero{
            path.addLine(to: CGPoint(x: topRight.x-topRightRadius.width, y: topRight.y))
            path.addCurve(to:  CGPoint(x: topRight.x, y: topRight.y+topRightRadius.height), control1: CGPoint(x: topRight.x, y: topRight.y), control2:CGPoint(x: topRight.x, y: topRight.y+topRightRadius.height))
        } else {
             path.addLine(to: CGPoint(x: topRight.x, y: topRight.y))
        }

        if bottomRightRadius != .zero{
            path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y-bottomRightRadius.height))
            path.addCurve(to: CGPoint(x: bottomRight.x-bottomRightRadius.width, y: bottomRight.y), control1: CGPoint(x: bottomRight.x, y: bottomRight.y), control2: CGPoint(x: bottomRight.x-bottomRightRadius.width, y: bottomRight.y))
        } else {
            path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y))
        }

        if bottomLeftRadius != .zero{
            path.addLine(to: CGPoint(x: bottomLeft.x+bottomLeftRadius.width, y: bottomLeft.y))
            path.addCurve(to: CGPoint(x: bottomLeft.x, y: bottomLeft.y-bottomLeftRadius.height), control1: CGPoint(x: bottomLeft.x, y: bottomLeft.y), control2: CGPoint(x: bottomLeft.x, y: bottomLeft.y-bottomLeftRadius.height))
        } else {
            path.addLine(to: CGPoint(x: bottomLeft.x, y: bottomLeft.y))
        }

        if topLeftRadius != .zero{
            path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y+topLeftRadius.height))
            path.addCurve(to: CGPoint(x: topLeft.x+topLeftRadius.width, y: topLeft.y) , control1: CGPoint(x: topLeft.x, y: topLeft.y) , control2: CGPoint(x: topLeft.x+topLeftRadius.width, y: topLeft.y))
        } else {
            path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y))
        }

        path.closeSubpath()
        cgPath = path
    }
}

Затем добавьте это UIView расширение:

extension UIView{
    func roundCorners(topLeft: CGFloat = 0, topRight: CGFloat = 0, bottomLeft: CGFloat = 0, bottomRight: CGFloat = 0) {//(topLeft: CGFloat, topRight: CGFloat, bottomLeft: CGFloat, bottomRight: CGFloat) {
        let topLeftRadius = CGSize(width: topLeft, height: topLeft)
        let topRightRadius = CGSize(width: topRight, height: topRight)
        let bottomLeftRadius = CGSize(width: bottomLeft, height: bottomLeft)
        let bottomRightRadius = CGSize(width: bottomRight, height: bottomRight)
        let maskPath = UIBezierPath(shouldRoundRect: bounds, topLeftRadius: topLeftRadius, topRightRadius: topRightRadius, bottomLeftRadius: bottomLeftRadius, bottomRightRadius: bottomRightRadius)
        let shape = CAShapeLayer()
        shape.path = maskPath.cgPath
        layer.mask = shape
    }
}

Наконец, вызов метода

myView.roundCorners(topLeft: 10, topRight: 20, bottomLeft: 30, bottomRight: 40)

И добавляем границу. Очевидно, layer.borderRadius не будет работать должным образом, поэтому создайте границу, используя CAShapeLayer и ранее созданный путь.

let borderLayer = CAShapeLayer()
borderLayer.path = (myView.layer.mask! as! CAShapeLayer).path! // Reuse the Bezier path
borderLayer.strokeColor = UIColor.red.cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.lineWidth = 5
borderLayer.frame = myView.bounds
myView.layer.addSublayer(borderLayer)

Вуаля!

person Kirill Dobryakov    schedule 03.11.2018
comment
Я не знаю, почему у этого ответа такой низкий балл. Это лучший ответ. Охватывает каждый аспект. - person Adeel; 26.05.2019
comment
Можно немного упростить, например вместо path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y)), если можно path.addLine(to: topLeft) и много подобных строк. - person mojuba; 08.11.2019
comment
ответ хороший, но я пытаюсь применить тень .. тогда тень не применяется .. @ArashAfsharpour - person Maulik shah; 26.05.2020
comment
@Maulikshah тень на UIView? или кнопку? - person Arash Afsharpour; 29.05.2020

Немного улучшенный и упрощенный ответ, основанный на @Kirill Dobryakov's. Кривые могут оставлять очень маленькие, но заметные неровности, если вы посмотрите на них и поймете, что они не идеально круглые (попробуйте, например, рассмотреть сторону 40 и радиус 20). Я понятия не имею, как это вообще возможно, но в любом случае самый надежный способ - использовать дуги, которые образуют идеальные скругленные углы, а также компонент @IBDesigneable для вас:

extension UIBezierPath {

    convenience init(shouldRoundRect rect: CGRect, topLeftRadius: CGFloat, topRightRadius: CGFloat, bottomLeftRadius: CGFloat, bottomRightRadius: CGFloat){

        self.init()

        let path = CGMutablePath()

        let topLeft = rect.origin
        let topRight = CGPoint(x: rect.maxX, y: rect.minY)
        let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY)
        let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY)

        if topLeftRadius != 0 {
            path.move(to: CGPoint(x: topLeft.x + topLeftRadius, y: topLeft.y))
        } else {
            path.move(to: topLeft)
        }

        if topRightRadius != 0 {
            path.addLine(to: CGPoint(x: topRight.x - topRightRadius, y: topRight.y))
            path.addArc(tangent1End: topRight, tangent2End: CGPoint(x: topRight.x, y: topRight.y + topRightRadius), radius: topRightRadius)
        }
        else {
            path.addLine(to: topRight)
        }

        if bottomRightRadius != 0 {
            path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y - bottomRightRadius))
            path.addArc(tangent1End: bottomRight, tangent2End: CGPoint(x: bottomRight.x - bottomRightRadius, y: bottomRight.y), radius: bottomRightRadius)
        }
        else {
            path.addLine(to: bottomRight)
        }

        if bottomLeftRadius != 0 {
            path.addLine(to: CGPoint(x: bottomLeft.x + bottomLeftRadius, y: bottomLeft.y))
            path.addArc(tangent1End: bottomLeft, tangent2End: CGPoint(x: bottomLeft.x, y: bottomLeft.y - bottomLeftRadius), radius: bottomLeftRadius)
        }
        else {
            path.addLine(to: bottomLeft)
        }

        if topLeftRadius != 0 {
            path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y + topLeftRadius))
            path.addArc(tangent1End: topLeft, tangent2End: CGPoint(x: topLeft.x + topLeftRadius, y: topLeft.y), radius: topLeftRadius)
        }
        else {
            path.addLine(to: topLeft)
        }

        path.closeSubpath()
        cgPath = path
    }
}



@IBDesignable
open class VariableCornerRadiusView: UIView  {

    private func applyRadiusMaskFor() {
        let path = UIBezierPath(shouldRoundRect: bounds, topLeftRadius: topLeftRadius, topRightRadius: topRightRadius, bottomLeftRadius: bottomLeftRadius, bottomRightRadius: bottomRightRadius)
        let shape = CAShapeLayer()
        shape.path = path.cgPath
        layer.mask = shape
    }

    @IBInspectable
    open var topLeftRadius: CGFloat = 0 {
        didSet { setNeedsLayout() }
    }

    @IBInspectable
    open var topRightRadius: CGFloat = 0 {
        didSet { setNeedsLayout() }
    }

    @IBInspectable
    open var bottomLeftRadius: CGFloat = 0 {
        didSet { setNeedsLayout() }
    }

    @IBInspectable
    open var bottomRightRadius: CGFloat = 0 {
        didSet { setNeedsLayout() }
    }

    override open func layoutSubviews() {
        super.layoutSubviews()
        applyRadiusMaskFor()
    }
}
person mojuba    schedule 08.11.2019
comment
У меня странное поведение (например, закругляется только верхний левый угол), оказалось, что я правильно установил начальные значения, но затем во время анимации / макета путь нужно установить снова. Поскольку я делал это из UIViewController, я переопределил viewDidLayoutSubviews и снова вызвал это. Исправлена ​​проблема - person xaphod; 25.04.2020
comment
@xaphod немного странно, потому что мой компонент также переопределяет layoutSubviews(), который должен выполнять эту работу. Вероятно, что-то конкретное для вашей ситуации. - person mojuba; 26.04.2020
comment
Забыл упомянуть, что я не могу изменить класс целевого представления, поэтому я не использую эту часть вашего кода. - person xaphod; 26.04.2020
comment
ответ хороший, но я пытаюсь применить тень .. тогда тень не применяется .. - person Maulik shah; 25.05.2020
comment
Не забудьте установить радиус угла в didLayoutSubviews () - иначе вы можете столкнуться со странным поведением :) - person Nicolai Harbo; 28.05.2021
comment
Работает как по волшебству! дерзайте, ребята, проблема только с добавлением теней - person Jen Jose; 04.06.2021

лучший способ сделать это после iOS 11, так он выглядит более плавным.

 func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
        clipsToBounds = true
        layer.cornerRadius = radius
        layer.maskedCorners = CACornerMask(rawValue: corners.rawValue)
  }

для исходного ответа: https://stackoverflow.com/a/50289822/4206186

person Fırat Yenidünya    schedule 16.07.2020