gpt4 book ai didi

SwiftUI:可以从任何 View 触发的全局覆盖

转载 作者:IT王子 更新时间:2023-10-29 05:48:52 26 4
gpt4 key购买 nike

我是 SwiftUI 框架的新手,我还没有全面了解它,所以请多多包涵。

有没有办法在绑定(bind)更改时从“另一个 View ”内部触发“覆盖 View ”?见下图:

enter image description here

我认为这个“叠加 View ”会包含我所有的 View 。我还不确定如何执行此操作 - 也许使用 ZIndex。我也想当绑定(bind)更改时我需要某种回调,但我也不确定该怎么做。

这是我目前所得到的:

内容 View

struct ContentView : View {
@State private var liked: Bool = false

var body: some View {
VStack {
LikeButton(liked: $liked)
}
}
}

点赞按钮

struct LikeButton : View {
@Binding var liked: Bool

var body: some View {
Button(action: { self.toggleLiked() }) {
Image(systemName: liked ? "heart" : "heart.fill")
}
}

private func toggleLiked() {
self.liked = !self.liked
// NEED SOME SORT OF TOAST CALLBACK HERE
}
}

我觉得我的 LikeButton 中需要某种回调,但我不确定这一切在 Swift 中是如何工作的。

如有任何帮助,我们将不胜感激。提前致谢!

最佳答案

在 SwiftUI 中构建“ toast ”非常简单且有趣!

让我们开始吧!

struct Toast<Presenting>: View where Presenting: View {

/// The binding that decides the appropriate drawing in the body.
@Binding var isShowing: Bool
/// The view that will be "presenting" this toast
let presenting: () -> Presenting
/// The text to show
let text: Text

var body: some View {

GeometryReader { geometry in

ZStack(alignment: .center) {

self.presenting()
.blur(radius: self.isShowing ? 1 : 0)

VStack {
self.text
}
.frame(width: geometry.size.width / 2,
height: geometry.size.height / 5)
.background(Color.secondary.colorInvert())
.foregroundColor(Color.primary)
.cornerRadius(20)
.transition(.slide)
.opacity(self.isShowing ? 1 : 0)

}

}

}

}

正文说明:

  • GeometryReader 为我们提供了 superview 的首选大小,从而为我们的 Toast 提供了完美的大小。
  • ZStack 将 View 堆叠在一起。
  • 逻辑很简单:如果不应该看到 toast (isShowing == false),那么我们将呈现 presenting View 。如果 toast 必须呈现 (isShowing == true),那么我们将 presenting View 渲染得有点模糊——因为我们可以——然后我们创建 toast接下来。
  • toast 只是一个带有 TextVStack,具有自定义框架大小、一些设计花哨的功能(颜色和圆角半径)和默认 幻灯片过渡。

我在 View 上添加了这个方法,使 Toast 的创建更容易:

extension View {

func toast(isShowing: Binding<Bool>, text: Text) -> some View {
Toast(isShowing: isShowing,
presenting: { self },
text: text)
}

}

还有一个关于如何使用它的小演示:

struct ContentView: View {

@State var showToast: Bool = false

var body: some View {
NavigationView {
List(0..<100) { item in
Text("\(item)")
}
.navigationBarTitle(Text("A List"), displayMode: .large)
.navigationBarItems(trailing: Button(action: {
withAnimation {
self.showToast.toggle()
}
}){
Text("Toggle toast")
})
}
.toast(isShowing: $showToast, text: Text("Hello toast!"))
}

}

我使用了 NavigationView 来确保 View 填满整个屏幕,因此 Toast 的大小和位置都正确。

withAnimation block 确保应用 Toast 转换。


外观:

enter image description here

借助 SwiftUI DSL 的强大功能,可以轻松扩展 Toast

Text 属性可以很容易地变成一个@ViewBuilder 闭包来适应最奢侈的布局。


将其添加到您的内容 View :

struct ContentView : View {
@State private var liked: Bool = false

var body: some View {
VStack {
LikeButton(liked: $liked)
}
// make it bigger by using "frame" or wrapping it in "NavigationView"
.toast(isShowing: $liked, text: Text("Hello toast!"))
}
}

如何在 2 秒后隐藏 toast(根据要求):

在 toast VStack 中的 .transition(.slide) 之后附加此代码。

.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
self.isShowing = false
}
}
}

在 Xcode 11.1 上测试

关于SwiftUI:可以从任何 View 触发的全局覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56550135/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com