Kiedy pojawi się klawiatura, zmieniają się rozmiary widżetów Flutter. Jak temu zapobiec?

114

Mam kolumnę rozszerzonych widżetów w następujący sposób:

 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,
          ),
        ],
      ),
    );

To wygląda tak:

wprowadź opis obrazu tutaj

convertFrom, zawiera TextField. Po dotknięciu tego pola tekstowego na ekranie pojawia się klawiatura systemu Android. Zmienia to rozmiar ekranu, więc widżety zmieniają rozmiar w następujący sposób:

wprowadź opis obrazu tutaj

Czy istnieje sposób, aby klawiatura „nakładała” ekran, aby moja kolumna nie zmieniała rozmiaru? Jeśli nie używam Expandedwidżetów i nie zakoduję na stałe wysokości dla każdego widżetu, widżety nie zmieniają rozmiaru, ale pojawia się błąd w czarno-żółte paski, gdy pojawia się klawiatura (ponieważ nie ma wystarczającej ilości miejsca). Nie jest to również elastyczne dla wszystkich rozmiarów ekranu.

Nie jestem pewien, czy jest to specyficzne dla Androida, czy dla Fluttera.

Mary
źródło
W treści szkieletu użyj SingleChildScrollView.
linhadiretalipe

Odpowiedzi:

287

Zaktualizowana odpowiedź

resizeToAvoidBottomPaddingjest teraz przestarzała .

Zaktualizowanym rozwiązaniem jest ustawienie resizeToAvoidBottomInsetwłaściwości na false.


Oryginalna odpowiedź

W swoim Scaffoldustaw resizeToAvoidBottomPaddingwłaściwość na false.

aziza
źródło
11
Czy jest sposób, aby uzyskać podobny efekt android:windowSoftInputMode="adjustPan"? Jeśli dodam resizeToAvoidBottomPaddingdo rusztowania, zakryje to TextField.
Epicality
3
Nie wiem o Androidzie, ale ogólnie dobrą praktyką jest zawijanie układu wewnątrz ListView w tym przypadku
aziza
@aziza, cierpiałem na ten sam problem, ale po rozwiązaniu działa dobrze, ale jest inny problem, sprawdź wideo z linku. Obraz migał, gdy pojawia się klawiatura. dropbox.com/s/lian92mnzz8kv9w/FlutterIssue1.mov?dl=0
Kishan Vyas
@KishanVyas to samo ze mną obraz zniknął.
stuckedoverflow
@aziza Solid answer
Val
35

Większość innych odpowiedzi sugeruje użycie resizeToAvoidBottomPadding=false. Z mojego doświadczenia wynika, że ​​pozwala to klawiaturze zakrywać pola tekstowe, jeśli znajdują się pod miejscem, w którym pojawiłaby się klawiatura.

Moim obecnym rozwiązaniem jest wymuszenie, aby moja kolumna była tej samej wysokości co ekran, a następnie umieszczenie jej w taki SingleChildScrollViewsposób, aby Flutter automatycznie przewijał mój ekran tylko na tyle, gdy używana jest klawiatura.

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
            ],
          ),
        ),
      ),
    ),
  );
}

Używam, NeverScrollableScrollPhysicsaby użytkownik nie mógł się przewijać.

Duncan Jones
źródło
4
Wypróbowałem twój sposób bez NeverScrollableScrollPhysicsi wszystko wygląda dobrze, z wyjątkiem tego, że użytkownik może próbować przesuwać palcem w górę iw dół i może zobaczyć poświatę nadmiernego przewijania. Kiedy używam, NeverScrollableScrollPhysicszachowuje się tak samo, jakresizeToAvoidBottomInset
Sajad Jaward,
Ustaw właściwość podstawową na false.
VLXU
1
ale używanie NeverScrollableScrollPhysicssprawia, że ​​nie jest on przewijany również za pomocą klawiatury.
hiwa doski
18

Ustaw resizeToAvoidBottomInsetaby falsezamiast resizeToAvoidBottomPaddingktóra jest nieaktualna.

    return Scaffold(
      resizeToAvoidBottomInset : false,
      body: YourWidgets(),
    );
ArtiomLK
źródło
3
To te same odpowiedzi @Ojonugwa, może redaktor zaktualizował zaakceptowaną odpowiedź po tym, jak opublikowałem moją, więc teraz różnica jest taka, że ​​moja zawiera przykład?
ArtiomLK
5

Moje podejście polega SingleChildScrollViewna ClampingScrollPhysicsfizyce.

SingleChildScrollView(
  physics: ClampingScrollPhysics(),
  child: Container(),
)
Legowisko
źródło
4

Metoda 1: Usuń android:windowSoftInputMode="adjustResize"z pliku AndroidManifest.xml (w przeciwnym razie nadpisze kod flutter) i dodaj resizeToAvoidBottomPadding: falseScaffold, jak poniżej:

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

Metoda 2 (niezalecane): Po prostu dodaj android:windowSoftInputMode="stateVisible"w AndroidManifest.xml w działaniu, będzie działać tylko dla Androida i nie dla IOS.

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

Uwaga: nie ustawiaj go naandroid:windowSoftInputMode="adjustResize"

yatin deokar
źródło
4

Cóż, myślę, że jeśli zaimplementujemy rozwiązanie @ Aman, nasza aplikacja będzie zachowywać się brzydko, ponieważ gdy pojawi się klawiatura, nie dostosuje naszego widoku ekranu do dostępnej wysokości i rozróżni inne pola ukryte za klawiaturą. Więc sugerowałbym użycie SingleChildScrollViewzamiast tego.

Owiń swój kod, SingleChildScrollViewjak podano poniżej,

 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,
      ),
    ],
  ),
 ),
);
Deepak Jha
źródło
zdajesz sobie sprawę z tego, że spowoduje to natychmiastowe pojawienie się masy błędów, ponieważ rozszerzony widżet będzie miał nieskończoną ilość miejsca do wypełnienia, podaną przez pojedynczy widok przewijania
Christian X
3

Sugeruję, aby resizeToAvoidBottomInset: falsemimo wszystko użyć, aby zapobiec zmianie rozmiaru widżetów, jeśli klawiatura nagle pojawi się na ekranie. Na przykład, jeśli użytkownik korzysta z czatów na Facebooku w Twojej aplikacji.

Aby klawiatura nie nakładała się na widżety, na ekranach, na których jest to potrzebne, proponuję następujące podejście, w którym wysokość jest SingleChildScrollViewzmniejszona do wysokości dostępnej przestrzeni. W tym przypadku SingleChildScrollViewprzewija się również do wybranego widżetu.

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()
        ],
      ),
    ),
  ),
);
birca123
źródło
2

W zależności od przypadku użycia możesz również rozważyć użycie widoku listy . Zapewniłoby to przewijanie zawartości, gdy nie ma wystarczającej ilości miejsca. Jako przykład możesz spojrzeć na demo Textfield w aplikacji Galeria

aptik
źródło
4
Ale to nadal nie sprawia, że ​​pole tekstowe, które wybrałeś, jest widoczne, klawiatura nadal będzie na nie nakładać. Musisz sam to przewinąć. Nie przyzwyczajony do tego jako programista / użytkownik Androida
Boy
1

Dla mnie zmiana poniżej właściwości item z true na false

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

w pliku

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

sprawił, że Flutter przeciąga całą zawartość strony w górę na fokus wprowadzania danych

Flutter przeciągnij całą zawartość strony w górę na fokus wprowadzania

javeedishaq
źródło
to będzie działać tylko dla Androida, tak jak się wydaje ...
Christian X
1

Miałem ten sam problem i zacząłem próbować losowych rozwiązań, aby go naprawić, a nagle to naprawiło. wprowadź opis obrazu tutaj

Owiń główny kontener nadrzędny w SingleChildScrollView () i podaj mu wysokość urządzenia, tj. Device_height = MediaQuery.of (context) .size.height.

Spowoduje to przewijanie całej strony, ale nie zmieni rozmiaru żadnego widżetu.

Rudr Thakur
źródło
Działa idealnie! Dzięki!!
Gihan Sandaru
Cieszę się, że mogłem pomóc!
Rudr Thakur