Swift - 将 2 个 UIView 与 1 个无缝边框组合

Swift -Combine 2 UIViews with 1 Seamless Border

我将以下 2 个 UIView 固定在一起。

顶部是名为 ballonView 的常规 UIView,底部是名称为 TriangleView 的 UIView 的子类。我有一个 border 绕过 ballonView,但我希望 border 也像这样绕过 triangleView。边框看起来是无缝的。

我该怎么做?

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .black

    displayBalloonView()
}

lazy var balloonView: UIView = {
    let v = UIView()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.backgroundColor = .orange
    v.layer.borderWidth = 3
    v.layer.borderColor = UIColor.white.cgColor
    v.layer.cornerRadius = 7
    v.layer.masksToBounds = true
    v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
    return v
}()

lazy var triangleView: TriangleView = {
    let v = TriangleView()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.fillColor = UIColor.orange
    v.backgroundColor = .clear
    return v
}()


func displayBalloonView() {

    view.addSubview(balloonView)
    balloonView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    balloonView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16).isActive = true
    balloonView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16).isActive = true
    balloonView.heightAnchor.constraint(equalToConstant: 70).isActive = true
    
    view.addSubview(triangleView)
    triangleView.topAnchor.constraint(equalTo: balloonView.bottomAnchor).isActive = true
    triangleView.centerXAnchor.constraint(equalTo: balloonView.centerXAnchor).isActive = true
    triangleView.widthAnchor.constraint(equalToConstant: 35).isActive = true
    triangleView.heightAnchor.constraint(equalToConstant: 25).isActive = true
    
    let messageLabel = UILabel()
    messageLabel.translatesAutoresizingMaskIntoConstraints = false
    messageLabel.text = "Tap here to see more"
    messageLabel.textColor = .white
    messageLabel.font = UIFont.systemFont(ofSize: 15, weight: .medium)
    messageLabel.textAlignment = .center
    messageLabel.numberOfLines = 0 // the text might be more than 1 line and I would set the balloonView to the label's height but for simplicity I just set the ballonView heightConstraint to 70
    messageLabel.sizeToFit()
    
    balloonView.addSubview(messageLabel)
    messageLabel.centerYAnchor.constraint(equalTo: balloonView.centerYAnchor).isActive = true
    messageLabel.leadingAnchor.constraint(equalTo: balloonView.leadingAnchor, constant: 16).isActive = true
    messageLabel.trailingAnchor.constraint(equalTo: balloonView.trailingAnchor, constant: -16).isActive = true
}

三角形视图:

class TriangleView : UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    var fillColor = UIColor()
    
    override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else { return }
        context.beginPath()
        context.move(to: CGPoint(x: rect.minX, y: rect.minY))
        context.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
        context.addLine(to: CGPoint(x: (rect.midX), y: rect.maxY))
        context.closePath()
        context.setFillColor(fillColor.cgColor)
        context.fillPath()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

只需“手动”绘制带三角形的圆角矩形作为贝塞尔曲线路径。我最终将其作为草图:

在它前面放置一个标签留作 reader 的练习。它只是一个包含我在代码中构建的图像的图像视图:

let r = UIGraphicsImageRenderer(size: CGSize(width: 200, height: 100))
let im = r.image {
    ctx in
    let con = ctx.cgContext
    con.move(to: CGPoint(x:100, y:10))
    con.addArc(tangent1End: CGPoint(x:190, y:10), tangent2End: CGPoint(x:190, y:80), radius: 10)
    con.addArc(tangent1End: CGPoint(x:190, y:80), tangent2End: CGPoint(x:0, y:80), radius: 10)
    con.addLine(to: CGPoint(x:110, y:80))
    con.addLine(to: CGPoint(x:100, y:95))
    con.addLine(to: CGPoint(x:90, y:80))
    con.addArc(tangent1End: CGPoint(x:10, y:80), tangent2End: CGPoint(x:10, y:0), radius: 10)
    con.addArc(tangent1End: CGPoint(x:10, y:10), tangent2End: CGPoint(x:200, y:10), radius: 10)
    con.addLine(to: CGPoint(x:100, y:10))
    con.setLineWidth(3)
    con.setStrokeColor(UIColor.white.cgColor)
    con.setFillColor(UIColor.red.cgColor)
    con.drawPath(using: .fillStroke)
}
let iv = UIImageView(image:im)

您将图像视图添加到您的界面并将标签放在它前面,一切就绪。当然,我已经对我的数字进行了硬编码,但是嘿,这只是一个草图;根据需要调整。