Разрыв SwiftUI TextField при анимации клавиатуры

Я создаю интерфейс в стиле чата с помощью SwiftUI с TextField внизу и List элементов над ним. Когда текстовое поле получает фокус и появляется клавиатура, поле и его фон не остаются прикрепленными к клавиатуре, а перемещаются немного вперед или назад. Вот пример:

Это было сделано с помощью safeAreaInset:

struct ContentView: View {
  @State private var message = ""
  
  var body: some View {
    List([Color.red, .orange, .yellow, .green, .blue, .indigo, .purple], id: \.self) { color in
      color
        .frame(height: 150)
        .listRowInsets(EdgeInsets())
    }
    .scrollContentBackground(.hidden)
    .safeAreaInset(edge: .bottom) {
      TextField("Chat", text: $message)
        .textFieldStyle(.roundedBorder)
        .padding()
        .background(.thinMaterial)
    }
  }
}

Я получаю аналогичные результаты, располагая их в VStack:

  var body: some View {
    VStack(spacing: 0) {
      List([Color.red, .orange, .yellow, .green, .blue, .indigo, .purple], id: \.self) { color in
        color
          .frame(height: 150)
          .listRowInsets(EdgeInsets())
      }
      .scrollContentBackground(.hidden)

      TextField("Chat", text: $message)
        .textFieldStyle(.roundedBorder)
        .padding()
        .background(.thinMaterial)
    }
  }

Время анимации не было бы большой проблемой, если бы фон за текстовым полем во время анимации распространялся на клавиатуру. Пробовал сделать это с помощью ignoresSafeArea(.all, edges: .bottom), но видимого эффекта это не дало.

Я обнаружил, что превосходный Callsheet Кейси Лисса нашел способ сделать это (он упомянул, что использовал SwiftUI для приложения), но я не уверен, как это сделать. Вот как выглядит Callsheet при наличии клавиатуры:

Кто-нибудь знает, как добиться такого поведения?

Я не могу воспроизвести это на iOS 17.4 (или, возможно, мои глаза просто плохо видят быстро движущиеся объекты). Какую версию iOS вы используете?

Sweeper 28.08.2024 03:38

В демонстрациях использовались Xcode 15.4 и iOS 17.5. Я получаю тот же результат, используя Xcode 16 beta 6 с iOS 18. Поведение непоследовательное, но постоянное. Клавиатура движется довольно быстро, поэтому это кратковременно (но очень раздражает). Включите медленную анимацию, чтобы ее было легче увидеть.

smr 28.08.2024 11:59

Вы уверены, что настоящий разрыв вызван не .scrollContentBackground(.hidden)? Кроме того, подтвердили ли вы, что это происходит и на реальных устройствах. Симуляторы иногда...

Bram 28.08.2024 12:00

Модификатор scrollContentBackground предназначен только для того, чтобы скрыть другую ошибку пользовательского интерфейса — описанное мной поведение все равно произойдет, если вы его удалите. И да, вы получаете то же самое на устройстве (используя iOS 17.5 на телефоне — у вас нет под рукой устройства iOS 18, но маловероятно, что это будет разница).

smr 28.08.2024 13:05

Те из вас, кто заключает опечатку: почему? Использование ShapeStyle вместо представления, требующего ViewModifier, не является опечаткой!

grg 28.08.2024 22:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Заставлять TextField точно соответствовать анимации клавиатуры бесполезно, поскольку можно использовать сторонние клавиатуры или другие подобные замены клавиатуры, которые имеют собственную анимацию представления.

Вместо этого вы правы, если хотите, чтобы фон был представлен после TextField. Вы упоминаете, что пытались сделать это с помощью ignoresSafeArea, но безрезультатно, но не указываете, где именно вы это пробовали в коде, что наводит меня на мысль, что это просто было привязано к неправильному представлению.

Представление, в котором вы хотите игнорировать безопасную область клавиатуры, — это именно фон. В вашем случае это тонкий материал. Поэтому материалу необходимо игнорировать безопасную зону.

ThinMaterial — это ShapeStyle, а не View, поэтому модификаторы ViewModifiers нельзя применять напрямую.
Вместо этого создайте представление самостоятельно и примените модификатор.

struct ContentView: View {
    …
    var body: some View {
        …
        .safeAreaInset(edge: .bottom) {
            TextField("Chat", text: $message)
                …
                .background {
                    Rectangle().fill(.thinMaterial).edgesIgnoringSafeArea(.all)
                }
        }
    }
}

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

Как вы говорите, я прикрепил расширение безопасной зоны к неправильному виду. Очень признателен за помощь. Однако есть одна небольшая поправка — вместо устаревшего edgesIgnoringSafeArea я бы рекомендовал ignoresSafeArea(.all, edges: .bottom).

smr 28.08.2024 22:24

Другие вопросы по теме