-2

I am trying to make this image appear with some rounded corners, dictated in code belowThis shape with rounded edges

My code for this is as follows. I want path1,path[4], path[5] rounded. I am open to a different approach. Please dont recommend UIBezierPath(roundedRect:..) as I dont need corenrs 0,2 rounded. This is tricky!

        let width = self.view.frame.size.width
        let trianglePath = UIBezierPath()
        var pts = [CGPoint(x:  2 * width / 16, y: width / 16),
               CGPoint(x: width / 32, y: width / 16 + width / 16),
               CGPoint(x: 2 * width / 16 , y: width / 16 + width / 8),
               CGPoint(x: width / 5  + 2 * width / 16, y: width / 8 + width / 16),
               CGPoint(x: width / 5  + 2 * width / 16, y: width / 16 ),
               CGPoint(x: 2 * width / 16, y:  width / 16 )
        ]

      // this path replaces this, because i cannot easily add rectangle
        //var path = UIBezierPath(roundedRect: rect, cornerRadius: width / 37.5).cgPath

        trianglePath.move(to: pts[0])
        trianglePath.addLine(to: pts[1]) // needs to be rounded
        trianglePath.addLine(to: pts[2])
        trianglePath.addLine(to: pts[3])
        trianglePath.addLine(to: pts[4]) // needs to be rounded
        trianglePath.addLine(to: pts[5]) // needs to be rounded
        trianglePath.close()

        let layer = CAShapeLayer()

        layer.path = trianglePath.cgPath
        layer.fillColor = UIColor.blue.cgColor
        layer.lineCap = kCALineCapRound
        layer.lineJoin = kCALineJoinRound
        layer.zPosition = 4
        layer.isHidden = false
        view.layer.addSublayer(layer)
MattEm
  • 181
  • 1
  • 8
  • 2
    "Please dont recommend UIBezierPath" Please don't tell people what to recommend. You worry about asking the _question_ clearly (which you are not doing so far) and let people who know more than you worry about what the answer might be. Try showing a drawing of the shape you _want_ - so far, it is utterly unclear what you'd like to do. – matt Jan 25 '17 at 22:18

2 Answers2

1

You can create a clipping path as explained here: https://www.raywenderlich.com/162313/core-graphics-tutorial-part-2-gradients-contexts

Specifically this bit:

let path = UIBezierPath(roundedRect: rect,
              byRoundingCorners: .allCorners,
                    cornerRadii: CGSize(width: 8.0, height: 8.0))
path.addClip()
kakubei
  • 5,321
  • 4
  • 44
  • 66
0

If you want to make rounded shapes you must use

trianglePath.AddArcToPoint(...);

See documentation here: https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html#//apple_ref/doc/uid/TP40010156-CH11-SW5

To be extra helpful, here is an entire subclass which you can use to learn how to draw custom views. Hope this helps.

import Foundation
import UIKit

final class BorderedView:UIView
{
    var drawTopBorder = false
    var drawBottomBorder = false
    var drawLeftBorder = false
    var drawRightBorder = false

    var topBorderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4)
    var leftBorderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4)
    var rightBorderColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
    var bottomBorderColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)

    var upperLeftCornerRadius:CGFloat = 0
    var upperRightCornerRadius:CGFloat = 0
    var lowerLeftCornerRadius:CGFloat = 0
    var lowerRightCornerRadius:CGFloat = 0

    var subview:UIView?
    fileprivate var visibleView:UIView!
    fileprivate var _backgroundColor:UIColor!

    override init(frame: CGRect)
    {
        super.init(frame: frame)
        super.backgroundColor = UIColor.clear
    }

    required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
        super.backgroundColor = UIColor.clear
    }

    func setVisibleBackgroundColor(_ color:UIColor)
    {
        _backgroundColor = color
    }

    func setBackgroundGradient(_ gradient:CAGradientLayer)
    {
        gradient.frame = visibleView.bounds
        gradient.masksToBounds = true
        visibleView.layer.insertSublayer(gradient, at: 0)
    }

    func drawView()
    {
        visibleView = UIView(frame: self.frame)
        visibleView.backgroundColor = _backgroundColor
        visibleView.clipsToBounds = true
        if let v = subview
        {
            visibleView.addSubview(v)
        }
    }

    override func draw(_ rect: CGRect)
    {
        // Drawing code
        let width = rect.size.width - 0.5;
        let height = rect.size.height - 0.5;

        guard let context = UIGraphicsGetCurrentContext() else { return }
        let w = self.frame.size.width;
        let h = self.frame.size.height;

        // Create clipping area as path.
        let path = CGMutablePath();
        path.move(to: CGPoint(x: 0, y: upperLeftCornerRadius))
        path.addArc(tangent1End: CGPoint(x: 0, y: 0), tangent2End: CGPoint(x: upperLeftCornerRadius, y: 0), radius: upperLeftCornerRadius)
        path.addLine(to: CGPoint(x: w - upperRightCornerRadius, y: 0))
        path.addArc(tangent1End: CGPoint(x: w, y: 0), tangent2End: CGPoint(x: w, y: upperRightCornerRadius), radius: upperRightCornerRadius)
        path.addLine(to: CGPoint(x: w, y: h - lowerRightCornerRadius))
        path.addArc(tangent1End: CGPoint(x: w, y: h), tangent2End: CGPoint(x: w - lowerRightCornerRadius, y: h), radius: lowerRightCornerRadius)
        path.addLine(to: CGPoint(x: lowerLeftCornerRadius, y: h))
        path.addArc(tangent1End: CGPoint(x: 0, y: h), tangent2End: CGPoint(x: 0, y: h - lowerLeftCornerRadius), radius: lowerLeftCornerRadius)
        path.closeSubpath();
        // Add clipping area to path
        context.addPath(path);
        // Clip to the path and draw the image
        context.clip ();

        self.drawView()
        visibleView.layer.render(in: context)

        // ********** Your drawing code here **********
        context.setLineWidth(0.5);
        var stroke = false

        if (drawTopBorder)
        {
            context.setStrokeColor(topBorderColor.cgColor);
            context.move(to: CGPoint(x: 0, y: 0.5)); //start at this point
            context.addLine(to: CGPoint(x: width, y: 0.5)); //draw to this point
            stroke = true
        }

        if (drawLeftBorder)
        {
            context.setStrokeColor(leftBorderColor.cgColor);
            context.move(to: CGPoint(x: 0.5, y: 0.5)); //start at this point
            context.addLine(to: CGPoint(x: 0.5, y: height)); //draw to this point
            stroke = true
        }

        if (drawBottomBorder)
        {
            context.setStrokeColor(bottomBorderColor.cgColor);
            context.move(to: CGPoint(x: 0.5, y: height)); //start at this point
            context.addLine(to: CGPoint(x: width, y: height)); //draw to this point
            stroke = true
        }

        if (drawRightBorder)
        {
            context.setStrokeColor(rightBorderColor.cgColor);
            context.move(to: CGPoint(x: width, y: 0.5)); //start at this point
            context.addLine(to: CGPoint(x: width, y: height)); //draw to this point
            stroke = true
        }

        // and now draw the Path!
        if stroke
        {
            context.strokePath();
        }
    }
}
Bjørn Ruthberg
  • 336
  • 1
  • 15
  • Thanks Bjorn, my question is why does layer.linecap and layer.linejoin not make the connections round, as per apple docs? @bjørn-ruthberg – MattEm Jan 25 '17 at 22:21
  • They do, but this is very small details. You would want something like 3 to 5 points to see a nice rounded border. Then you need to use the addarctopoint method. it takes some effort to get your head around, but once you get it, it'll be your go-to solution :) – Bjørn Ruthberg Jan 25 '17 at 22:39
  • I updated my answer to include an example class. You can mess around with that until you get the shape you want. If you need any explanations, just ask. – Bjørn Ruthberg Jan 26 '17 at 11:55