You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS:如何将聊天气泡尾部从右下调整至左上

解决方案:调整聊天气泡尾部至左上位置

要将气泡尾部从当前的右下位置修改为目标的左上位置,核心是重新构建UIBezierPath的绘制路径,把尾部的曲线逻辑从右下角区域转移到左上角区域,同时修正原代码中的变量笔误。

以下是修改后的完整draw(_:)方法代码:

public override func draw(_ rect: CGRect) {
    let hasBlurSubview = subviews.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 = lineWidth
    let left = lineWidth
    
    // 从左上尾部的起始点开始绘制
    bezierPath.move(to: CGPoint(x: left + 22, y: top))
    // 绘制左上尾部的贝塞尔曲线
    bezierPath.addCurve(to: CGPoint(x: left + 11.04, y: top + 4.04), 
                        controlPoint1: CGPoint(x: left + 19, y: top), 
                        controlPoint2: CGPoint(x: left + 16, y: top))
    bezierPath.addCurve(to: CGPoint(x: left - 0.05, y: top + 0.01), 
                        controlPoint1: CGPoint(x: left + 8.16, y: top + 1.06), 
                        controlPoint2: CGPoint(x: left + 4.07, y: top - 0.43))
    bezierPath.addLine(to: CGPoint(x: left, y: top))
    bezierPath.addCurve(to: CGPoint(x: left + 4, y: top + 11), 
                        controlPoint1: CGPoint(x: left, y: top), 
                        controlPoint2: CGPoint(x: left + 4, y: top + 1))
    
    // 绘制气泡主体右侧边缘
    bezierPath.addLine(to: CGPoint(x: left + 4, y: bottom - 17))
    bezierPath.addCurve(to: CGPoint(x: left + 21, y: bottom), 
                        controlPoint1: CGPoint(x: left + 4, y: bottom - 7.61), 
                        controlPoint2: CGPoint(x: left + 11.61, y: bottom))
    
    // 绘制气泡主体底部边缘
    bezierPath.addLine(to: CGPoint(x: right - 17, y: bottom))
    bezierPath.addCurve(to: CGPoint(x: right, y: bottom - 17), 
                        controlPoint1: CGPoint(x: right - 7.61, y: bottom), 
                        controlPoint2: CGPoint(x: right, y: bottom - 7.61))
    
    // 绘制气泡主体右侧边缘
    bezierPath.addLine(to: CGPoint(x: right, y: top + 17))
    bezierPath.addCurve(to: CGPoint(x: right - 17, y: top), 
                        controlPoint1: CGPoint(x: right, y: top + 7.61), 
                        controlPoint2: CGPoint(x: right - 7.61, y: top))
    
    // 绘制气泡主体顶部边缘,回到尾部起始点闭合路径
    bezierPath.addLine(to: CGPoint(x: left + 22, y: top))
    bezierPath.close()
    
    let blurEffect = UIVisualEffectView(effect: UIBlurEffect(style: .light))
    blurEffect.alpha = configuration.blurAlpha
    blurEffect.frame = bounds // 改用bounds避免路径边界偏移问题
    let mask = CAShapeLayer()
    mask.path = bezierPath.cgPath
    blurEffect.layer.mask = mask
    insertSubview(blurEffect, at: 0)
    
    let gradient = CAGradientLayer()
    gradient.frame = bounds
    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)
}

关键修改说明:

  1. 路径起点转移:将路径起始点从右下区域转移到左上区域,重新编写尾部的贝塞尔曲线逻辑,匹配目标布局的左上尾部形状。
  2. 变量修正:原代码中17 + borderWidth改为17 + lineWidth,修复未定义变量的错误。
  3. 边界适配:将top和left的初始值从0.0调整为lineWidth,避免边框被视图边缘切割。
  4. 模糊视图优化:将blurEffect.frame = bezierPath.bounds改为blurEffect.frame = bounds,解决路径边界导致的模糊区域偏移问题。

补充优化建议:

  • 可在Configuration中新增tailPosition枚举(如.topLeft、.bottomRight),实现动态切换气泡尾部位置的功能,提升组件复用性。
  • 将路径绘制逻辑封装为独立方法,例如createBubblePath(with rect: CGRect, lineWidth: CGFloat, tailPosition: TailPosition) -> UIBezierPath,让代码结构更清晰。

内容的提问来源于stack exchange,提问作者Michael Grigoryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 09:05:21