SwiftUI长按按钮,像加载栏一样填充

xxls0lw8  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(148)

我的应用程序有一个完成按钮,我想让它,当用户按下按钮,他们必须举行他们的手指按下2秒之前的行动是初始化(即弹出窗口出现)。当他们举行,按钮填补了从左到右类似于加载栏。这是我目前的代码,但由于某种原因,它不工作

@GestureState private var isLongPressing = false

Button("Complete") {
    withAnimation {
        viewModel.isPopupPresented.toggle()
        viewModel.stopProgressTimer()
    }
}
.font(.system(size: 20, weight: .heavy, design: .rounded))
.foregroundColor(.white)
.frame(width: 150, height: 40, alignment: .center)
.background(
    ZStack {
        RoundedRectangle(cornerRadius: 20, style: .continuous)
            .fill(Color.secondaryColor)

        if isLongPressing {
            RoundedRectangle(cornerRadius: 20, style: .continuous)
                .fill(Color.red)
                .frame(width: 150 * CGFloat(viewModel.progress), height: 40, alignment: .leading)
        }
    }
)
.gesture(
    LongPressGesture(minimumDuration: 2.0)
        .updating($isLongPressing) { value, state, _ in
            state = value
            if value {
                viewModel.startProgressTimer()
            } else {
                viewModel.stopProgressTimer()
            }
        }
        .onEnded { value in
            if isLongPressing {
                // Trigger your action here
                viewModel.isPopupPresented.toggle()
                viewModel.stopProgressTimer()
            }
        }
)

字符串
在我的ViewModel中,我有以下内容:

@Published var progress: Double = 0.0
    private var progressTimer: Timer?

    func resetProgress() {
        progressTimer?.invalidate()
        progress = 0.0
    }

    func startProgressTimer() {
        progressTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
            if self.progress < 1.0 {
                self.progress += 0.1
            } else {
                self.progress = 1.0
                self.resetProgress()
            }
        }
    }

    func stopProgressTimer() {
        progressTimer?.invalidate()
        progress = 0.0
    }

3pvhb19x

3pvhb19x1#

我首先检测触摸事件(使用DragGesture(minimumDistance: 0))。在触摸时,我们启动一个2秒的动画进度。同时,检测一个持续时间为2的长按手势。
如果在拖动手势结束之前没有检测到长按,这意味着按下时间小于2秒,因此我们取消动画。否则,如果检测到长按,则显示弹出窗口。

@State private var touchDown = false

...

.simultaneousGesture(
    DragGesture(minimumDistance: 0).onChanged({ value in
        if !touchDown {
            withAnimation(.linear(duration: 2)) {
                touchDown = true
            }
        }
    }).onEnded({ _ in
        if !isPopupPresented {
            touchDown = false
        }
    })
)
.simultaneousGesture(
    LongPressGesture(minimumDuration: 2, maximumDistance: .infinity)
        .onEnded({ _ in
            isPopupPresented = true
        })
)

字符串
touchDownbackground中用于制作动画。
完整代码:

struct ContentView: View {
    @State private var touchDown = false
    @State private var isPopupPresented = false
    
    var body: some View {
        
        Text("Complete")
            .font(.system(size: 20, weight: .heavy, design: .rounded))
            .foregroundColor(.white)
            .frame(width: 150, height: 40, alignment: .center)
            .background(
                RoundedRectangle(cornerRadius: 20, style: .continuous)
                    .fill(Color.secondary)
                    .overlay(alignment: .leading) {
                        RoundedRectangle(cornerRadius: 20, style: .continuous)
                            .fill(Color.red)
                            // I prefer the effect of using an offset instead of width
                            .offset(x: touchDown ? 0 : -150)
                    }
                    .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
            )
            .simultaneousGesture(
                DragGesture(minimumDistance: 0).onChanged({ value in
                    if !touchDown {
                        withAnimation(.linear(duration: 2)) {
                            touchDown = true
                        }
                    }
                }).onEnded({ _ in
                    if !isPopupPresented {
                        touchDown = false
                    }
                })
            )
            .simultaneousGesture(
                LongPressGesture(minimumDuration: 2, maximumDistance: .infinity)
                    .onEnded({ _ in
                        isPopupPresented = true
                    })
            )
            .sheet(isPresented: $isPopupPresented) {
                Text("Foo")
            }
    }
}

相关问题