我对SwiftUI框架还很陌生,我还没有完全了解它,所以请耐心听我说.

当绑定发生变化时,有没有办法从"另一个视图"内部触发"覆盖视图"?见下图:

enter image description here

我想这个"叠加视图"会把我所有的视图都包起来.我还不知道该怎么做——也许用ZIndex.我还想,当绑定发生变化时,我需要某种回调,但我也不知道该怎么做.

到目前为止,我得到的是:

ContentView

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

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

LikeButton

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中构建"祝wine 词"非常简单,而且很有趣!

让我们开始吧!

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个视图堆叠在一起.
  • 逻辑很简单:如果不应该看到烤面包(isShowing == false),那么我们渲染presenting视图.如果必须呈现祝wine 词(isShowing == true),那么我们用一点模糊来渲染presenting视图——因为我们可以——然后我们接下来创建祝wine 词.
  • toast只有VStackText,有定制的框架尺寸,一些设计铃铛和口哨( colored颜色 和角半径),以及默认的slide过渡.

我在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来确保整个屏幕都是视图,所以Toast的大小和位置都是正确的.

withAnimation块确保应用Toast转换.


How it looks:

enter image description here

借助SwiftUI DSL的强大功能,很容易扩展Toast.

Text号wine 店很容易变成@ViewBuilder号的封闭式建筑,以容纳最奢华的布局.


To add it to your content 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!"))
    }
}

How to hide the toast afte 2 seconds (as requested):

在toast VStack中的.transition(.slide)后面追加此代码.

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

Tested on Xcode 11.1

Swift相关问答推荐

JSON如何解码空对象

运行异步任务串行运行

如何在SWIFT中轻松格式化公制和英制使用的UnitVolume

Swift-Can无法在AudioKit中找出简单的麦克风效果-文件链

协议元类型'SomeProtocol.Type'上无法使用静态成员'currency'

为什么无法在 Swift 中使用AVFoundation扫描 QRCode

从 Obj-C 函数返回 swift 类的不兼容指针类型

Swift 并发任务与调度队列线程:是什么决定同时运行多少任务?

如何从我的 macOS 应用程序打开 (.log) 文件?

我如何遵守与演员的协议?

在 macOS (Swift) 上获取 BSD 驱动器名称的最佳方法是什么?

Swift并发:为什么不在其他后台线程上执行任务

`let case(value)` 和 `case(let value)` 之间的区别 (Swift)

AVPlayer 在 iOS 15.4 中寻求 completionHandler 返回 false

VStack SwiftUI 中的动态内容高度

使用 swift 运行 pod install 时出错

Swift 动画 WithDuration 语法是什么?

快速在 LLDB 中使用 po

如何在 SwiftUI 中以编程方式滚动列表?

如何将应用程序与 iOS 联系人应用程序集成?