1

I have one screen and I need to add diagonal cut view in it after imageview.

Here is the screenshot of what I need to make,

Profile screen

So please help me in creating this kind of view.

I have referred this

and this questions.

But I want to know if there is any more reliable way to achieve this.

Thanks in advance.

KAR
  • 3,303
  • 3
  • 27
  • 50

2 Answers2

2

In order to do this, you can add a view to your storyboard and set the view's class to a custom class which will change the layout of the view to the diagonal cut.

The custom class should look as follows:

//
//  CustomShapeView.swift
//
//
//  Created by Umar Farooque on 17/09/17.
//  Copyright © 2017 ufocorp. All rights reserved.
//

import UIKit
@IBDesignable
class CustomShapeView: UIView {

    @IBInspectable var color : UIColor? = UIColor.gray {
        didSet {
            //            self.layer.backgroundColor = self.color?.cgColor
        }

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

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

    }

    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
        //get the size of the view
        let size = self.bounds.size
        //get 4 points for the shape layer
        let p1 = self.bounds.origin
        let p2 = CGPoint(x: p1.x + size.width, y: p1.y)
        let p3 = CGPoint(x: p2.x, y: size.height)
        let p4 = CGPoint(x: p1.x, y: size.height - 30)

        //create the path
        let path = UIBezierPath()
        path.move(to: p1)
        path.addLine(to: p2)
        path.addLine(to: p3)
        path.addLine(to: p4)
        path.close()
        (color ?? UIColor.gray).set()
        path.fill()

    }

}

And the result will be something like this:

enter image description here

Umar Farooque
  • 2,049
  • 21
  • 32
0

Using some responses I did this (On my case a triangle) with tap gestures: Blue Triangle with tap detection inside and outside

Class Triangle View


protocol TriangleViewProtocol {
    func shapeTapped()
    func outShapeTapped(touch: UITouch)
}

class TriangleView : UIView {
    var color: CGColor = UIColor.red.cgColor

    var delegate: TriangleViewProtocol?

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

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

    override func draw(_ rect: CGRect) {
        // Draw a shape with 3 sides
        self.layer.sublayers?.forEach({ $0.removeFromSuperlayer() })
        do {
            let rectangleLayer = try getPathPayer(arrPathPoints: [
                CGPoint(x: rect.maxX, y: rect.minY),
                CGPoint(x: rect.maxX, y: rect.maxY),
                CGPoint(x: rect.minX, y: rect.maxY)
                ])
            self.layer.addSublayer(rectangleLayer)
        } catch {
            debugPrint(error)
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // Get tap and calculate what side of view is touched
        guard let touch = touches.first,
            let sublayers = self.layer.sublayers as? [CAShapeLayer]else { return }
        let point = touch.location(in: self)
        for layer in sublayers{
            // On my case I need to get two actions
            // one if user tap on blue side
            // and other outside blue for send this actions to bellow views
            if let path = layer.path, path.contains(point) {
                self.delegate?.shapeTapped()
            }else {
                self.delegate?.outShapeTapped(touch: touch)
            }
        }
    }

    func getPathPayer(arrPathPoints:[CGPoint]) throws -> CAShapeLayer {
        enum PathError : Error{
            case moreThan2PointsNeeded
        }

        guard arrPathPoints.count > 2 else {
            throw PathError.moreThan2PointsNeeded
        }

        let lineColor = UIColor.black
        let lineWidth: CGFloat = 2
        let path = UIBezierPath()
        let pathLayer = CAShapeLayer()

        for (index,pathPoint) in arrPathPoints.enumerated() {
            switch index {
            case 0:
                path.move(to: pathPoint)

            case arrPathPoints.count - 1:
                path.addLine(to: pathPoint)
                path.close()

            default:
                path.addLine(to: pathPoint)
            }
        }

        pathLayer.path = path.cgPath
        pathLayer.strokeColor = lineColor.cgColor
        pathLayer.lineWidth = lineWidth
        pathLayer.fillColor = self.color

        return pathLayer
    }
}

Class My Controller

extension FirstView: TriangleViewProtocol {
    func shapeTapped() {
      // Action on blue side
    }
    func outShapeTapped(touch: UITouch) {
      //send outside actions to bellow view
        guard let filteredView = self.view.subviews.filter({ type(of: $0) != TriangleView.self && type(of: $0) == UIStackView.self }).first,
            let view = filteredView.hitTest(touch.location(in: filteredView), with: nil),
            let button = view as? UIButton else { return }
        button.sendActions(for: .touchUpInside)
    }
}

My .xib: xib file organization Now the other subviews (on my case the stackView) receive the tap when triangle is tapped on clear side.

Fresneda
  • 103
  • 3
  • 6