Quando o teclado aparece, os widgets Flutter são redimensionados. Como evitar isso?

114

Eu tenho uma coluna de widgets expandidos como este:

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

Se parece com isso:

insira a descrição da imagem aqui

convertFrom, inclui um TextField. Quando toco neste campo de texto, o teclado Android aparece na tela. Isso muda o tamanho da tela, para que os widgets sejam redimensionados assim:

insira a descrição da imagem aqui

Existe uma maneira de fazer com que o teclado "sobreponha" a tela para que minha coluna não seja redimensionada? Se eu não usar Expandedwidgets e codificar uma altura para cada widget, os widgets não são redimensionados, mas recebo o erro de listras pretas e amarelas quando o teclado aparece (porque não há espaço suficiente). Isso também não é flexível para todos os tamanhos de tela.

Não tenho certeza se este é um específico do Android ou específico do Flutter.

Maria
fonte
Em seu corpo de andaime, use SingleChildScrollView.
linhadiretalipe

Respostas:

287

Resposta Atualizada

resizeToAvoidBottomPaddingagora está obsoleto .

A solução atualizada é definir a resizeToAvoidBottomInsetpropriedade como false.


Resposta Original

Em seu Scaffold, defina a resizeToAvoidBottomPaddingpropriedade como false.

aziza
fonte
11
Existe alguma maneira de produzir um efeito semelhante a android:windowSoftInputMode="adjustPan"? Se eu adicionar resizeToAvoidBottomPaddingao scaffold, ele acaba cobrindo o TextField.
Epicalidade,
3
Não sei sobre o Android, mas geralmente é uma boa prática envolver seu layout dentro de um ListView neste caso
aziza
@aziza, eu estava sofrendo do mesmo problema, mas depois de sua solução funcionou bem, mas há outro problema, verifique o vídeo do link A imagem estava piscando quando o teclado apareceu. dropbox.com/s/lian92mnzz8kv9w/FlutterIssue1.mov?dl=0
Kishan Vyas
@KishanVyas a mesma imagem comigo se foi.
stickedoverflow
@aziza Resposta sólida
Val
35

A maioria das outras respostas sugere o uso resizeToAvoidBottomPadding=false. Na minha experiência, isso permite que o teclado cubra campos de texto se eles estiverem abaixo de onde o teclado apareceria.

Minha solução atual é forçar minha coluna a ter a mesma altura da tela e, em seguida, colocá-la em um SingleChildScrollViewpara que o Flutter role automaticamente minha tela para cima apenas o suficiente quando o teclado for usado.

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

Eu uso NeverScrollableScrollPhysicspara que o usuário não possa rolar sozinho.

Duncan Jones
fonte
4
Tentei do seu jeito sem NeverScrollableScrollPhysicse tudo parece bem, exceto o usuário pode tentar deslizar para cima e para baixo e eles podem ver o brilho da rolagem. Quando eu uso o, NeverScrollableScrollPhysicsele me dá o mesmo comportamento queresizeToAvoidBottomInset
Sajad Jaward
Defina a propriedade primária como false.
VLXU
1
mas o uso NeverScrollableScrollPhysicsfaz com que não seja rolado para cima com o teclado também.
hiwa doski
18

Definido resizeToAvoidBottomInsetcomo em falsevez de resizeToAvoidBottomPaddingque está obsoleto.

    return Scaffold(
      resizeToAvoidBottomInset : false,
      body: YourWidgets(),
    );
ArtiomLK
fonte
3
São as mesmas respostas @Ojonugwa, talvez o editor tenha atualizado a resposta aceita depois que eu postei a minha, então agora a diferença é que a minha inclui um exemplo?
ArtiomLK
5

Minha abordagem é usar SingleChildScrollViewcom a ClampingScrollPhysicsfísica.

SingleChildScrollView(
  physics: ClampingScrollPhysics(),
  child: Container(),
)
Den
fonte
4

Método 1: Remova android:windowSoftInputMode="adjustResize"do arquivo AndroidManifest.xml (caso contrário, ele substituirá o código de flutter) e adicione o resizeToAvoidBottomPadding: falseScaffold como a seguir:

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

Método 2 (não recomendado): Basta adicionar android:windowSoftInputMode="stateVisible"AndroidManifest.xml em atividade, ele só funcionará para Android e não para IOS.

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

Nota: Não defina comoandroid:windowSoftInputMode="adjustResize"

Yatin Deokar
fonte
4

Bem, eu acho que se implementarmos a solução de @Aman, isso fará com que nosso aplicativo se comporte feio como quando o teclado aparece, não ajustará nossa janela de visualização da tela de acordo com a altura disponível e fará com que outros campos se escondam atrás do teclado. Então, eu sugeriria usar em seu SingleChildScrollViewlugar.

Envolva seu código SingleChildScrollViewconforme fornecido a seguir,

 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
fonte
você está ciente do fato de que isso lançará imediatamente uma massa de erros porque o widget expandido terá espaço infinito para preencher fornecido pelo singleechildscrollview
Christian X
2

Dependendo do caso de uso, você também pode considerar o uso de uma exibição de lista . Isso garantiria que o conteúdo rolar quando não houver espaço suficiente. Como exemplo, você pode ver a demonstração do campo de texto no aplicativo de galeria

aptik
fonte
4
Mas isso ainda não torna o TextField que você selecionou visível, o teclado ainda o sobreporá. Você tem que rolar sozinho. Não costumava ser um desenvolvedor / usuário Android
Garoto,
2

Minha sugestão é usar resizeToAvoidBottomInset: falseassim mesmo para evitar que os widgets sejam redimensionados se o teclado aparecer repentinamente na tela. Por exemplo, se um usuário usa o chat do Facebook enquanto está em seu aplicativo.

Para evitar que o teclado se sobreponha aos widgets, nas telas onde for necessário, sugiro a seguinte abordagem, em que a altura é SingleChildScrollViewreduzida à altura do espaço disponível. Nesse caso, SingleChildScrollViewtambém rola para o widget em foco.

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
fonte
1

Para mim, alterando a propriedade do item abaixo de verdadeiro para falso

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

no arquivo

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

fez o Flutter arrastar todo o conteúdo da página para cima no foco de entrada

Flutter arraste todo o conteúdo da página para cima no foco de entrada

javeedishaq
fonte
isso só funcionará para Android como parece ...
Christian X
1

Eu estava enfrentando o mesmo problema e comecei a tentar soluções aleatórias para corrigi-lo e de repente isso resolveu. insira a descrição da imagem aqui

Envolva o contêiner pai principal em SingleChildScrollView () e atribua a altura do dispositivo, ou seja, device_height = MediaQuery.of (context) .size.height.

Isso tornará a página inteira rolável, mas não redimensionará nenhum widget.

Rudr Thakur
fonte
Funcionando perfeitamente! Obrigado!!
Gihan Sandaru
Que bom que pude ajudar!
Rudr Thakur