Панель навигации- кнопка панели инструментов ненадежно работает, когда переменная @State обновляет представление с высокой частотой

#swift #xcode #swiftui

#swift #xcode #swiftui

Вопрос:

Я заметил, что кнопки Navigationbar- / Toolbar не работают должным образом, когда есть хотя бы одна переменная @State, которая очень часто обновляет представление.

Я создал простое приложение, чтобы протестировать его.

В приведенном ниже примере кода у вас есть 3 варианта запуска модального листа. Одна кнопка в главном окне, одна на панели инструментов и одна на панели навигации.

Когда мой таймер не обновляет «номер», все 3 кнопки работают должным образом. Когда я запускаю таймер, который будет обновлять вид каждые 0,1 секунды, каждый раз будет работать только кнопка в главном виде. Кнопки на панели инструментов / панели навигации большую часть времени не работают. (Чем короче интервал времени моего таймера, тем меньше кнопок работают)

 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!")
        })

    }
}
  

У кого-нибудь есть идея, есть ли способ заставить 2 кнопки работать должным образом?

Эта проблема возникает с Xcode 12 beta 5 и Xcode Xcode 11.6 (без панели инструментов, поскольку она там недоступна)

Ответ №1:

number Состояние в предоставленном варианте обновляет все представление, что является результатом проблемы и не очень оптимально для пользовательского интерфейса.

Решение для панели навигации и в целом хорошего стиля заключается в выделении обновляемой части в отдельный вид, поэтому механизм рендеринга SwiftUI перестраивает только ее.

Протестировано с 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 другой проблемой — она не работает после открытия первого листа даже без просмотра по таймеру, и вот почему

ДЕМОНСТРАЦИЯ

как видно, расположение кнопок повреждено и находится за пределами области панели инструментов, поэтому тестирование hit завершается неудачей — и это дефект Apple, о котором следует сообщить.

Обходной путь 1:

Поместите панель инструментов за пределы вида навигации (визуально панель инструментов меньше, но иногда может быть уместно, потому что кнопка работает)

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

Комментарии:

1. Большое вам спасибо за помощь. Я всегда помещал только большие представления в собственное автономное представление, а не только Textlabel. Я думаю, мне нужно работать в целом с более отдельными представлениями. Проблема с панелью инструментов, похоже, уже исправлена в Xcode 12b5 / iOS 14. Есть ли способ визуализировать в Xcode / simulator, какие части пользовательского интерфейса повторно отображаются при изменении чего-либо в пользовательском интерфейсе?

Ответ №2:

Xcode 13.1, цель симулятора iPhone 13 (и предварительный просмотр canvas).

Ни одно из других решений не сработало для меня, но я обнаружил, что это влияет только на верхние кнопки навигации и при наличии большого заголовка панели навигации.

Итак, то, что сработало, похоже,:

  1. Установка встроенного заголовка
     .navigationBarTitleDisplayMode(.inline)
      
  2. Нет заголовка
  3. Отсутствует панель инструментов с верхним краем (только нижняя панель)

Если проблема действительно проявилась, я мог бы просмотреть список, содержащийся в представлении (нет необходимости включать функцию обновления), и это также восстановило бы функциональность кнопки.

Комментарии:

1. У меня это сработало хорошо, после того, как все другие параметры не сработали. Спасибо!

2. Я действительно нахожу эту ту же проблему, и установка заголовка панели на встроенный вместо большого заголовка работает для меня.

3. СПАСИБО, этот встроенный модификатор сделал свое дело. Я уже вложил вспомогательные представления и понятия не имел, что это за исправление

4. у меня сработал Xcode 13.2