iOS: Chat bubble change position of tail

Viewed 48

I'm trying to achive this layout [LAYOUT TO ACHIEVE]

and right now I have gradient part done, blur part done, and also bezier path mostly done. My question is that I can't replace TAIL from bottom right part to top left part (to be similar like in the picture).

[LAYOUT ACHIEVED]

My Code I wrote for acheiving:

public final class BubbleView: UIView {
    public var configuration: Configuration = Configuration.defaultConfiguration {
        didSet {
            setNeedsLayout()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        
        commonInit()
    }
    
    private func commonInit() {
        super.backgroundColor = .clear
    }

    public override func draw(_ rect: CGRect) {
        let hasBlurSubview = subviews.compactMap({$0}).contains(where: {$0 is UIVisualEffectView })
        guard !hasBlurSubview else {
            return
        }

        let lineWidth = configuration.lineWidth
        
        let bezierPath = UIBezierPath()
        bezierPath.lineWidth = lineWidth
        
        let bottom = rect.height - lineWidth
        let right = rect.width - lineWidth
        let top = 0.0
        let left = 0.0
        
        bezierPath.move(to: CGPoint(x: right - 22, y: bottom))
        bezierPath.addLine(to: CGPoint(x: 17 + lineWidth, y: bottom))
        bezierPath.addCurve(to: CGPoint(x: left, y: bottom - 18), controlPoint1: CGPoint(x: 7.61 + lineWidth, y: bottom), controlPoint2: CGPoint(x: left, y: bottom - 7.61))
        bezierPath.addLine(to: CGPoint(x: left, y: 17 + lineWidth))
        bezierPath.addCurve(to: CGPoint(x: 17 + borderWidth, y: top), controlPoint1: CGPoint(x: left, y: 7.61 + lineWidth), controlPoint2: CGPoint(x: 7.61 + lineWidth, y: top))
        bezierPath.addLine(to: CGPoint(x: right - 21, y: top))
        bezierPath.addCurve(to: CGPoint(x: right - 4, y: 17 + lineWidth), controlPoint1: CGPoint(x: right - 11.61, y: top), controlPoint2: CGPoint(x: right - 4, y: 7.61 + lineWidth))
        bezierPath.addLine(to: CGPoint(x: right - 4, y: bottom - 11))
        bezierPath.addCurve(to: CGPoint(x: right, y: bottom), controlPoint1: CGPoint(x: right - 4, y: bottom - 1), controlPoint2: CGPoint(x: right, y: bottom))
        bezierPath.addLine(to: CGPoint(x: right + 0.05, y: bottom - 0.01))
        bezierPath.addCurve(to: CGPoint(x: right - 11.04, y: bottom - 4.04), controlPoint1: CGPoint(x: right - 4.07, y: bottom + 0.43), controlPoint2: CGPoint(x: right - 8.16, y: bottom - 1.06))
        bezierPath.addCurve(to: CGPoint(x: right - 22, y: bottom), controlPoint1: CGPoint(x: right - 16, y: bottom), controlPoint2: CGPoint(x: right - 19, y: bottom))
        bezierPath.close()
        
        let blurEffect = UIVisualEffectView(effect: UIBlurEffect(style: .light))
        blurEffect.alpha = configuration.blurAlpha
        blurEffect.frame = bezierPath.bounds
        let mask = CAShapeLayer()
        mask.path = bezierPath.cgPath
        blurEffect.layer.mask = mask
        insertSubview(blurEffect, at: 0)
        
        let gradient = CAGradientLayer()
        gradient.frame = CGRect(origin: CGPoint.zero, size: size)
        gradient.colors = configuration.borderGradientColors.map({$0.cgColor})
        gradient.startPoint = configuration.borderGradientStartPoint
        gradient.endPoint = configuration.borderGradientEndPoint
        let shape = CAShapeLayer()
        shape.lineWidth = lineWidth
        shape.path = bezierPath.cgPath
        shape.strokeColor = UIColor.black.cgColor
        shape.fillColor = UIColor.clear.cgColor
        gradient.mask = shape
        blurEffect.layer.addSublayer(gradient)
    }
}

public class Configuration {
        static var defaultConfiguration: Configuration {
            return .init(
                lineWidth: 2.0,
                blurAlpha: 0.95,
                borderGradientColors: [Assets.Colors.white05.color, Assets.Colors.white01.color],
                borderGradientStartPoint: CGPoint(x: 0.0, y: 0.5),
                borderGradientEndPoint: CGPoint(x: 1.0, y: 0.5)
            )
        }
        
        var lineWidth: CGFloat
        var blurAlpha: CGFloat
        var borderGradientColors: [UIColor]
        var borderGradientStartPoint: CGPoint
        var borderGradientEndPoint: CGPoint

        init(
            lineWidth: CGFloat,
            blurAlpha: CGFloat,
            borderGradientColors: [UIColor],
            borderGradientStartPoint: CGPoint,
            borderGradientEndPoint: CGPoint
        ) {
            self.lineWidth = lineWidth
            self.blurAlpha = blurAlpha
            self.borderGradientColors = borderGradientColors
            self.borderGradientStartPoint = borderGradientStartPoint
            self.borderGradientEndPoint = borderGradientEndPoint
        }
    }
0 Answers
Related