Display only the corners of a UIView

2020-06-04 08:40发布

问题:

How to display only the corners of a UIView?

        let view = UIView()
        view.layer.borderColor = UIColor.white.cgColor

        view.layer.borderWidth = 2 
           let maskframe = UIView(frame: CGRect(x:0, y:0, 
          width:view.frame.width, height:view.frame.height))

         view.layer.mask = maskframe.layer.`

This masks only the right edge and i dont understand how it works either.

回答1:

Try with this class, here I use a custom view drawing using CoreGraphics, added some Inspectable variables to help with customization

//
//  CornerView.swift
//  CornersViewSO
//
//  Created by Reinier Melian on 5/31/17.
//  Copyright © 2017 Reinier Melian. All rights reserved.
//

import UIKit
import CoreGraphics

@IBDesignable
class CornerView: UIView {

    @IBInspectable
    var sizeMultiplier : CGFloat = 0.2{
        didSet{
            self.draw(self.bounds)
        }
    }

    @IBInspectable
    var lineWidth : CGFloat = 2{
        didSet{
            self.draw(self.bounds)
        }
    }

    @IBInspectable
    var lineColor : UIColor = UIColor.black{
        didSet{
            self.draw(self.bounds)
        }
    }


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

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

    func drawCorners()
    {
        let currentContext = UIGraphicsGetCurrentContext()

        currentContext?.setLineWidth(lineWidth)
        currentContext?.setStrokeColor(lineColor.cgColor)

        //first part of top left corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: 0, y: 0))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width*sizeMultiplier, y: 0))
        currentContext?.strokePath()

        //top rigth corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: self.bounds.size.width - self.bounds.size.width*sizeMultiplier, y: 0))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: 0))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height*sizeMultiplier))
        currentContext?.strokePath()

        //bottom rigth corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height - self.bounds.size.height*sizeMultiplier))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width - self.bounds.size.width*sizeMultiplier, y: self.bounds.size.height))
        currentContext?.strokePath()

        //bottom left corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: self.bounds.size.width*sizeMultiplier, y: self.bounds.size.height))
        currentContext?.addLine(to: CGPoint(x: 0, y: self.bounds.size.height))
        currentContext?.addLine(to: CGPoint(x: 0, y: self.bounds.size.height - self.bounds.size.height*sizeMultiplier))
        currentContext?.strokePath()

        //second part of top left corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: 0, y: self.bounds.size.height*sizeMultiplier))
        currentContext?.addLine(to: CGPoint(x: 0, y: 0))
        currentContext?.strokePath()
    }


    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
        super.draw(rect)
        self.drawCorners()
    }


}

EDITED

Example Code of Use

import UIKit

class ViewController: UIViewController {

    var cornerViewCode : CornerView?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.cornerViewCode = CornerView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        self.view.addSubview(self.cornerViewCode!)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

this is how it looks

Hope this helps



回答2:

Check out this UIView:

class RectangleView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func draw(_ rect: CGRect) {

        let aPath = UIBezierPath()

        UIColor.black.set()

        aPath.move(to: CGPoint(x: rect.minX, y: 0.1*rect.maxY))
        aPath.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
        aPath.addLine(to: CGPoint(x: 20, y: rect.minY))
        aPath.stroke()

        aPath.move(to: CGPoint(x: rect.maxX - 0.1*rect.maxX, y: rect.minY))
        aPath.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
        aPath.addLine(to: CGPoint(x: rect.maxX, y: 0.1*rect.maxY))
        aPath.stroke()

        aPath.move(to: CGPoint(x: rect.maxX, y: rect.maxY - 0.1*rect.maxY))
        aPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        aPath.addLine(to: CGPoint(x: rect.maxX - 0.1*rect.maxX, y: rect.maxY))
        aPath.stroke()

        aPath.move(to: CGPoint(x: rect.minX + 0.1*rect.maxX, y: rect.maxY))
        aPath.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        aPath.addLine(to: CGPoint(x: rect.minX, y: rect.maxY - 0.1*rect.maxY))
        aPath.stroke()

    }

}


回答3:

If you don't wish to subclass UIView. The same can be achieved using Autolayout.

Swift Version: 3.0

Xcode Version 8.2.1

func setupAutoLayout() {
    let cameraViewWidth : Float = Float(UIScreen.main.bounds.size.width * 0.50)

    let edgeLength : Float = cameraViewWidth * 0.10

    cameraView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    cameraView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    cameraView.widthAnchor.constraint(equalToConstant: CGFloat(cameraViewWidth)).isActive = true
    cameraView.heightAnchor.constraint(equalToConstant: CGFloat(cameraViewWidth)).isActive = true

    //Top Left
    topLeftEdgeView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor).isActive = true
    topLeftEdgeView.topAnchor.constraint(equalTo: cameraView.topAnchor).isActive = true
    topLeftEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true
    topLeftEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true

    topLeftSideEdgeView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor).isActive = true
    topLeftSideEdgeView.topAnchor.constraint(equalTo: cameraView.topAnchor).isActive = true
    topLeftSideEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true
    topLeftSideEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true

    //Top Right
    topRightEdgeView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor).isActive = true
    topRightEdgeView.topAnchor.constraint(equalTo: cameraView.topAnchor).isActive = true
    topRightEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true
    topRightEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true

    topRightSideEdgeView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor).isActive = true
    topRightSideEdgeView.topAnchor.constraint(equalTo: cameraView.topAnchor).isActive = true
    topRightSideEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true
    topRightSideEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true

    //Bottom Left
    bottomLeftEdgeView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor).isActive = true
    bottomLeftEdgeView.bottomAnchor.constraint(equalTo: cameraView.bottomAnchor, constant : -CGFloat(1.0)).isActive = true
    bottomLeftEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true
    bottomLeftEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true

    bottomLeftSideEdgeView.leadingAnchor.constraint(equalTo: cameraView.leadingAnchor).isActive = true
    bottomLeftSideEdgeView.topAnchor.constraint(equalTo: cameraView.bottomAnchor, constant : -CGFloat(edgeLength + 1.0)).isActive = true
    bottomLeftSideEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true
    bottomLeftSideEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true

    //Bottom Right
    bottomRightEdgeView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor).isActive = true
    bottomRightEdgeView.bottomAnchor.constraint(equalTo: cameraView.bottomAnchor, constant : -CGFloat(1.0)).isActive = true
    bottomRightEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true
    bottomRightEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true

    bottomRightSideEdgeView.trailingAnchor.constraint(equalTo: cameraView.trailingAnchor).isActive = true
    bottomRightSideEdgeView.topAnchor.constraint(equalTo: cameraView.bottomAnchor, constant : -CGFloat(edgeLength + 1.0)).isActive = true
    bottomRightSideEdgeView.widthAnchor.constraint(equalToConstant: CGFloat(1.0)).isActive = true
    bottomRightSideEdgeView.heightAnchor.constraint(equalToConstant: CGFloat(edgeLength)).isActive = true
}

PS: Where cameraView, topLeftEdgeView, topLeftSideEdgeView... etc all are UIViews.

Here our edgeLength is dependent on cameraView width(currently 10%). At 0.50 this will draw complete border around cameraView.

Don't Forget to add translatesAutoresizingMaskIntoConstraints = false for all views involved!!



回答4:

I was able to achieve the same via BeizerPath and CAShapeLayer. Hence sharing the same.

Code created on Xcode 9.3 using Swift 4.0. Tested on iOS 10.0 and iOS 11.3

  func createCorners() -> Void {

        //Calculate the length of corner to be shown
        let cornerLengthToShow = self.bounds.size.height * 0.10
        print(cornerLengthToShow)

        // Create Paths Using BeizerPath for all four corners
        let topLeftCorner = UIBezierPath()
        topLeftCorner.move(to: CGPoint(x: self.bounds.minX, y: self.bounds.minY + cornerLengthToShow))
        topLeftCorner.addLine(to: CGPoint(x: self.bounds.minX, y: self.bounds.minY))
        topLeftCorner.addLine(to: CGPoint(x: self.bounds.minX + cornerLengthToShow, y: self.bounds.minY))

        let topRightCorner = UIBezierPath()
        topRightCorner.move(to: CGPoint(x: self.bounds.maxX - cornerLengthToShow, y: self.bounds.minY))
        topRightCorner.addLine(to: CGPoint(x: self.bounds.maxX, y: self.bounds.minY))
        topRightCorner.addLine(to: CGPoint(x: self.bounds.maxX, y: self.bounds.minY + cornerLengthToShow))

        let bottomRightCorner = UIBezierPath()
        bottomRightCorner.move(to: CGPoint(x: self.bounds.maxX, y: self.bounds.maxY - cornerLengthToShow))
        bottomRightCorner.addLine(to: CGPoint(x: self.bounds.maxX, y: self.bounds.maxY))
        bottomRightCorner.addLine(to: CGPoint(x: self.bounds.maxX - cornerLengthToShow, y: self.bounds.maxY ))

        let bottomLeftCorner = UIBezierPath()
        bottomLeftCorner.move(to: CGPoint(x: self.bounds.minX, y: self.bounds.maxY - cornerLengthToShow))
        bottomLeftCorner.addLine(to: CGPoint(x: self.bounds.minX, y: self.bounds.maxY))
        bottomLeftCorner.addLine(to: CGPoint(x: self.bounds.minX + cornerLengthToShow, y: self.bounds.maxY))

        let combinedPath = CGMutablePath()
        combinedPath.addPath(topLeftCorner.cgPath)
        combinedPath.addPath(topRightCorner.cgPath)
        combinedPath.addPath(bottomRightCorner.cgPath)
        combinedPath.addPath(bottomLeftCorner.cgPath)

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = combinedPath
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.lineWidth = 3

        layer.addSublayer(shapeLayer)
    }