Когда появляется клавиатура, размер виджетов Flutter изменяется. Как этого избежать?


101

У меня есть такой столбец расширенных виджетов:

 return new Container(
      child: new Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          new Expanded(
            flex: 1,
            child: convertFrom,
          ),
          new Expanded(
            flex: 1,
            child: convertTo,
          ),
          new Expanded(
            flex: 1,
            child: description,
          ),
        ],
      ),
    );

Выглядит это так:

введите описание изображения здесь

convertFrom, включает TextField. Когда я нажимаю на это текстовое поле, на экране появляется клавиатура Android. Это изменяет размер экрана, поэтому размер виджетов изменяется следующим образом:

введите описание изображения здесь

Есть ли способ, чтобы клавиатура «накладывала» на экран, чтобы размер моего столбца не менялся? Если я не использую Expandedвиджеты и жестко задаю высоту для каждого виджета, размер виджетов не изменяется, но при появлении клавиатуры я получаю ошибку с черно-желтыми полосами (потому что места недостаточно). Это также не подходит для всех размеров экрана.

Я не уверен, относится ли это к Android или Flutter.


В теле Scaffold используйте SingleChildScrollView.
linhadiretalipe,

Ответы:


259

В вашем Scaffoldустановите для resizeToAvoidBottomInsetсвойства значение false.

Свойство resizeToAvoidBottomPadding устарело .... В вашем Scaffoldустановите для resizeToAvoidBottomPaddingсвойства значение false.


11
Есть ли способ произвести подобный эффект android:windowSoftInputMode="adjustPan"? Если я добавлю resizeToAvoidBottomPaddingк каркасу, он закроет TextField.
Epicality 09

2
Я не знаю насчет Android, но, как правило, в этом случае рекомендуется оборачивать макет внутри ListView
азиза,

@aziza, у меня была такая же проблема, но после вашего решения она работает нормально, но есть еще одна проблема, пожалуйста, проверьте видео по ссылке Изображение мигало при появлении клавиатуры. dropbox.com/s/lian92mnzz8kv9w/FlutterIssue1.mov?dl=0
Кишан

@KishanVyas же у меня имиджа нет.
застрял overflow

@aziza Твердый ответ
Val

27

В большинстве других ответов предлагается использовать resizeToAvoidBottomPadding=false. По моему опыту, это позволяет клавиатуре закрывать текстовые поля, если они находятся под тем местом, где должна располагаться клавиатура.

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

Widget build(BuildContext context) {
  return Scaffold(
    body: SingleChildScrollView(
      physics: NeverScrollableScrollPhysics(),
      child: ConstrainedBox(
        constraints: BoxConstraints(
          minWidth: MediaQuery.of(context).size.width,
          minHeight: MediaQuery.of(context).size.height,
        ),
        child: IntrinsicHeight(
          child: Column(
            mainAxisSize: MainAxisSize.max,
            children: <Widget>[
              // CONTENT HERE
            ],
          ),
        ),
      ),
    ),
  );
}

Я использую, NeverScrollableScrollPhysicsчтобы пользователь не мог прокрутить себя.


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

Установите для основного свойства значение false.
VLXU

16

Набор resizeToAvoidBottomInsetдля falseвместо resizeToAvoidBottomPaddingкоторых является устаревшим.

    return Scaffold(
      resizeToAvoidBottomInset : false,
      body: YourWidgets(),
    );

Чем этот ответ отличается от принятого?
Оджонугва Джуд Очалифу,

2
Это те же ответы @Ojonugwa, возможно, редактор обновил принятый ответ после того, как я опубликовал свой, так что теперь разница в том, что мой включает пример?
ArtiomLK

4

Метод 1: Удалите android:windowSoftInputMode="adjustResize"из файла AndroidManifest.xml ( В противном случае он будет перекрывать флаттер кода) и добавить resizeToAvoidBottomPadding: falseв строительном лесе , как показано ниже:

Scaffold(
      resizeToAvoidBottomPadding: false,
      appBar: AppBar()
)

Метод 2 (не рекомендуется): просто добавьте android:windowSoftInputMode="stateVisible"в android AndroidManifest.xml в активности, он будет работать только для Android, а не для IOS.

<activity
       ...
        android:windowSoftInputMode="stateVisible">

Примечание. Не устанавливайте значениеandroid:windowSoftInputMode="adjustResize"


4

Что ж, я думаю, если мы реализуем решение @Aman, это заставит наше приложение вести себя некрасиво, так как при появлении клавиатуры оно не будет настраивать наше окно просмотра на доступную высоту и будет различать другие поля, скрытые за клавиатурой. Поэтому я бы предложил использовать SingleChildScrollViewвместо этого.

Оберните свой код, SingleChildScrollViewкак указано ниже,

 return new Container(
  child: SingleChildScrollView(
    child: new Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: <Widget>[
      new Expanded(
        flex: 1,
        child: convertFrom,
      ),
      new Expanded(
        flex: 1,
        child: convertTo,
      ),
      new Expanded(
        flex: 1,
        child: description,
      ),
    ],
  ),
 ),
);

2

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


4
Но это по-прежнему не делает видимым выбранный вами TextField, клавиатура все равно будет перекрывать его. Прокручивать придется самому. Не привык как разработчик / пользователь Android
Boy

2

Мой подход заключается в использовании SingleChildScrollViewс ClampingScrollPhysicsфизикой.

SingleChildScrollView(
  physics: ClampingScrollPhysics(),
  child: Container(),
)

1

Для меня изменение свойства ниже элемента с true на false

<item name="android:windowFullscreen">false</item>

в файле

android/app/src/main/res/values/styles.xml

заставил Flutter перетаскивать все содержимое страницы вверх в фокусе ввода

Flutter перетащите все содержимое страницы вверх в фокус ввода


0

Я предлагаю использовать в resizeToAvoidBottomInset: falseлюбом случае, чтобы предотвратить изменение размера виджетов, если клавиатура внезапно появляется на экране. Например, если пользователь использует заголовки чата Facebook в вашем приложении.

Чтобы клавиатура не накладывала виджеты на нужные вам экраны, я предлагаю следующий подход, при котором высота SingleChildScrollViewуменьшается до высоты доступного пространства. В этом случае SingleChildScrollViewтакже выполняется прокрутка к виджету в фокусе.

final double screenHeight = MediaQuery.of(context).size.height;
final double keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
return Scaffold(
  resizeToAvoidBottomInset: false,
  body: SizedBox(
    height: screenHeight - keyboardHeight,
    child: SingleChildScrollView(
      child: Column(
        children: [
          const SizedBox(height: 200),
          for (var i = 0; i < 10; i++) const TextField()
        ],
      ),
    ),
  ),
);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.