当@State 变量以高频率刷新视图时,导航栏/工具栏按钮工作不可靠 [英] Navigationbar- / Toolbar Button not working reliable when @State variable refresh the view with a high frequency

查看:22
本文介绍了当@State 变量以高频率刷新视图时,导航栏/工具栏按钮工作不可靠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到当至少有一个 @State 变量经常刷新视图时,导航栏/工具栏按钮无法正常工作.

I noticed that Navigationbar- / Toolbar Buttons are not working properly when there is at least one @State variable refreshing the View very often.

我创建了一个简单的应用程序来测试它.

I created a simple app to test it.

在下面的代码示例中,您有 3 个选项来触发模式表.一个按钮在主视图中,一个在工具栏中,一个在导航栏中.

With below Code example you have 3 options to trigger a modal sheet. One Button in the main View, one in the toolbar and one in the navigationbar.

当我的计时器没有更新数字"时所有 3 个按钮都正常工作.当我启动计时器时,它将每 0,1 秒刷新一次视图,只有主视图中的按钮每次都会工作.工具栏/导航栏中的按钮大部分时间都不起作用.(我的计时器的 TimeInterval 越短,按钮的工作就越少)

When my timer doesn't update "number" all 3 buttons are working properly. When i start the Timer which will refresh the view every 0,1 second only the button in the main view will work every time. The buttons in toolbar / navigationbar do not work most of the time. (The shorter the TimeInterval of my timer the less the buttons are working)

import SwiftUI

struct ContentView: View {

    @State private var number = 0
    @State private var showModal = false

    func startTimer() {
        Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (_) in
            number += 1
        }
    }

    var body: some View {

        NavigationView {
            VStack {
                Text("Count \(number)")
                Button(action: startTimer, label: {
                    Text("Start Timer")
                })

                Button(action: { showModal.toggle() }, label: {
                    Text("Open Modal")
                })
            }
            .navigationBarTitle("Home", displayMode: .inline)
            .navigationBarItems(leading:
                                    Button(action: {
                                        showModal.toggle()
                                    }, label: {
                                        Text("Open Modal")
                                    }))

            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Button(action: {
                        showModal.toggle()
                    }, label: {
                        Text("Open Modal")
                    })
                }
            }
        }

        .sheet(isPresented: $showModal, content: {
            Text("Hello, World!")
        })

    }
}

有没有人知道有没有办法让这两个按钮正常工作?

Does anyone have an idea if there is a way to make the 2 buttons work properly?

此问题发生在 Xcode 12 beta 5 和 Xcode Xcode 11.6(没有工具栏,因为它在那里不可用)

This issue occurs with Xcode 12 beta 5 and Xcode Xcode 11.6 (without toolbar as it's not available there)

推荐答案

提供的变体中的 number 状态刷新了整个视图,这是问题的结果,对于 UI 来说不是很理想.

The number state in provided variant refreshes entire view, that is a result of issue, and not very optimal for UI.

导航栏的解决方案,总体来说还是不错的,就是将刷新部分分离成独立的视图,所以SwiftUI渲染引擎只重建它.

The solution for navigation bar, and in general good style, is to separate refreshing part into standalone view, so SwiftUI rendering engine rebuild only it.

使用 Xcode 12b3/iOS 14 测试

Tested with Xcode 12b3 / iOS 14

struct TestOftenUpdate: View {

    @State private var showModal = false

    var body: some View {

        NavigationView {
            VStack {
                QuickTimerView()
                Button(action: { showModal.toggle() }, label: {
                    Text("Open Modal")
                })
            }
            .navigationBarTitle("Home", displayMode: .inline)
            .navigationBarItems(leading:
                                    Button(action: {
                                        showModal.toggle()
                                    }, label: {
                                        Text("Open Modal")
                                    }))

            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Button(action: {
                        showModal.toggle()
                    }, label: {
                        Text("Open Modal")
                    })
                }
            }
        }

        .sheet(isPresented: $showModal, content: {
            Text("Hello, World!")
        })

    }
}

struct QuickTimerView: View {
    @State private var number = 0

    var body: some View {
        VStack {
            Text("Count \(number)")
            Button(action: startTimer, label: {
                Text("Start Timer")
            })
        }
    }

    func startTimer() {
        Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (_) in
            number += 1
        }
    }

}

使用 toolbar 是不同的问题 - 即使没有计时器视图,它在第一张工作表打开后也不起作用,这就是原因

With toolbar is different issue - it does not work after first sheet open even without timer view, and here is why

正如所见,按钮布局已损坏且位于工具栏区域之外,这就是命中测试失败的原因 - 这是应该报告的 Apple 缺陷.

as it is seen the button layout has corrupted and outside of toolbar area, that is why hit testing fails - and this is Apple defect that should be reported.

解决方法 1:

将工具栏放在导航视图之外(视觉工具栏较小,但有时可能是合适的,因为按钮有效)

Place toolbar outside navigation view (visually toolbar is smaller, but sometimes might be appropriate, because button works)

    NavigationView {
       // ... other code
    }
    .toolbar {
        ToolbarItem(placement: .bottomBar) {
            Button(action: {
                showModal.toggle()
            }, label: {
                Text("Open Modal")
            })
        }
    }

这篇关于当@State 变量以高频率刷新视图时,导航栏/工具栏按钮工作不可靠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆