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

SwiftUI自定义滑块遮罩异常:滑块靠近右端时轨道两端均圆角

修复SwiftUI自定义滑块轨道圆角问题

我用SwiftUI开发自定义滑块,采用RoundedRectangle作为未选中轨道,通过遮罩Rectangle实现进度显示。滑块处于中间位置时效果正常,但拖动到靠近右侧边缘时,未选中轨道的两端都会显示圆角,需要修复为仅右端显示圆角。

解决方案

问题根源是原代码使用了全圆角的RoundedRectangle,再通过leading padding控制轨道位置,当轨道宽度缩小时,两端圆角都会暴露。正确做法是给未选中轨道仅设置右端圆角,并直接计算其位置和宽度,避免padding导致的形状收缩问题。

修改后的完整代码

struct Slider: View {
    @Binding var progress: CGFloat
    private let stroke: CGFloat = 5.0
    private var thumbWidth: CGFloat { stroke * 2 }
    private var thumbHeight: CGFloat { thumbWidth * 3.5 }
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Color.black.ignoresSafeArea()
                
                VStack {
                    let sliderWidth = geometry.size.width - thumbWidth
                    let thumbLeftX = progress * sliderWidth
                    let activeTrackWidth = thumbLeftX
                    let inactiveTrackWidth = geometry.size.width - (thumbLeftX + thumbWidth)
                    
                    ZStack(alignment: .leading) {
                        // 选中的进度轨道
                        Rectangle()
                            .fill(Color.white.opacity(0.5))
                            .frame(width: activeTrackWidth, height: stroke)
                        
                        // 未选中的背景轨道(仅右端圆角)
                        RoundedRectangle(cornerRadius: stroke, corners: [.topRight, .bottomRight])
                            .frame(width: max(0, inactiveTrackWidth), height: stroke)
                            .offset(x: thumbLeftX + thumbWidth)
                        
                        // 滑块Thumb
                        Capsule()
                            .fill(.red)
                            .frame(width: thumbWidth, height: thumbHeight)
                            .offset(x: thumbLeftX)
                            .gesture(
                                DragGesture()
                                    .onChanged { gesture in
                                        let newProgress = min(max(gesture.location.x / sliderWidth, 0), 1)
                                        progress = newProgress
                                    }
                            )
                    }
                    .frame(height: thumbHeight)
                }
            }
        }
    }
}

struct SliderView: View {
    @State private var progress: CGFloat = 0.0
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            Slider(progress: $progress)
        }
    }
}

关键修改点

  • 将全圆角RoundedRectangle替换为仅右端圆角的形状,用RoundedRectangle(cornerRadius:stroke, corners: [.topRight, .bottomRight])确保左端始终为直角。
  • 去掉padding控制轨道位置的方式,直接通过offset和计算后的宽度定位未选中轨道,避免宽度收缩时暴露左端圆角。
  • 调整进度计算逻辑,基于可滑动区域(总宽度减去thumb宽度)计算位置,确保thumb拖动到两端时轨道显示准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 07:32:17