出现键盘时,Flutter小部件将调整大小。如何预防这种情况?

我有一个像这样的扩展小部件列:

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

它是这样的:

enter image description here

convertFrom包含一个TextField。当我点击这个文本框时,Android键盘就会出现在屏幕上。这会改变屏幕大小,所以小部件会像这样调整大小:

enter image description here

有没有办法让键盘“覆盖”屏幕,使我的列不调整大小?如果我不使用Expanded小部件并为每个小部件硬编码高度,小部件不会调整大小,但当键盘出现时,我得到了黑黄条纹错误(因为没有足够的空间)。这也不是对所有屏幕尺寸都灵活。

我不确定这是android特有的还是flutter特有的。

204836 次浏览

更新后的答案

resizeToAvoidBottomPadding现在是弃用

更新后的解决方案是将resizeToAvoidBottomInset属性设置为false


原来的答案

Scaffold中,将resizeToAvoidBottomPadding属性设置为false

根据用例,你也可以考虑使用列表视图。这将确保当没有足够的空间时,内容会滚动。作为一个例子,你可以在图库应用程序中查看文本框演示

resizeToAvoidBottomInset设置为false,而不是已弃用的resizeToAvoidBottomPadding

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

从AndroidManifest.xml文件中删除android:windowSoftInputMode="adjustResize"(否则它将覆盖flutter代码),并在Scaffold中添加resizeToAvoidBottomPadding: false,如下所示:

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

方法二(不推荐):只需在android AndroidManifest.xml中添加android:windowSoftInputMode="stateVisible",它只适用于android,而不适用于IOS等。

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

不要将其设置为android:windowSoftInputMode="adjustResize"

大多数其他答案建议使用resizeToAvoidBottomPadding=false。根据我的经验,这允许键盘掩盖文本字段,如果它们在键盘出现的地方下面。

我目前的解决方案是强制我的列与屏幕的高度相同,然后将其放置在SingleChildScrollView中,以便Flutter在使用键盘时自动向上滚动屏幕。

Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
physics: const 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,以便用户不能滚动自己。

好吧,我认为如果我们实现@Aman的解决方案,它将使我们的应用程序行为丑陋,因为当键盘出现时,它不会调整我们的屏幕视口根据可用的高度,它将使其他字段隐藏在键盘后面。所以我建议使用__abc0代替。

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

我的方法是使用SingleChildScrollViewClampingScrollPhysics物理。

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

对我来说,下面的项目属性从真变为假

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

在文件

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

已使Flutter在输入焦点上向上拖动所有页面内容

Flutter在输入焦点上向上拖动所有页面内容

我的建议是无论如何使用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()
],
),
),
),
);
我也面临着同样的问题,我开始尝试随机解决方案来解决它,突然它就解决了。 enter image description here < / p >

将主父容器包装在SingleChildScrollView()中,并为其提供设备高度,即device_height = MediaQuery.of(context).size.height。

这将使整个页面可滚动,但不会调整任何小部件的大小。

避免调整小部件的大小关注文本字段的最佳解决方案是使用SingleChildScrollView()ClampingScrollPhysics()物理。另外,记住设置高度是它的孩子(例如:使用container()),所以你可以通过Column()使用你的小部件:

return Scaffold(
body: SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Container(
height: size.height,
child: Column(
children:[
TextFormField()
],
),
),
),
);

resizeToAvoidBottomInset设置值false对我来说很好。

而且,resizeToAvoidBottomPadding对我来说工作得很好。你可以用任何一个。

这是完美的解决方案,它使你能够在SingleChildScrollView中包含全屏列。这允许你为所有屏幕尺寸创建一个完美的布局,并且能够拥有一个可滚动的屏幕,当你打开键盘或渲染后屏幕溢出时(例如文本输入字段验证),只有会滚动屏幕。

class PerfectFullScreen extends StatelessWidget {
const PerfectFullScreen({Key key}) : super(key: key);


@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(),
body: Builder(
builder: (context) => SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height -
(MediaQuery.of(context).padding.top + kToolbarHeight)),
child: IntrinsicHeight(
child: Column(
children: [
Container(
height: randomImageHeight,
child: Image.asset(
"assets/images/change_password.png",
fit: BoxFit.cover,
),
),
Expanded(
child: WidgetThatShouldTakeRemainingSpace() )
],
)))),
),
));
}
}

重要的部分是带有正确的BoxConstraintsInstrinsicHeight小部件的ConstrainedBox

PS: MediaQuery.of .padding(上下文)。top + kToolbarHeight) == Appbar的高度

现在回答可能太迟了,但下面的方法对我有用

Scaffold(
body: SingleChildScrollView(
physics: ClampingScrollPhysics(parent: NeverScrollableScrollPhysics()),
child: Container(

夹紧将自动滚动使文本字段可见,它的父NeverScrollable将不允许用户滚动。

.

功能:

  • 打开键盘时,背景图像不会调整大小
  • 能够滚动隐藏在键盘后面的元素
import 'package:flutter/material.dart';


SizedBox addPaddingWhenKeyboardAppears() {
final viewInsets = EdgeInsets.fromWindowPadding(
WidgetsBinding.instance!.window.viewInsets,
WidgetsBinding.instance!.window.devicePixelRatio,
);


final bottomOffset = viewInsets.bottom;
const hiddenKeyboard = 0.0; // Always 0 if keyboard is not opened
final isNeedPadding = bottomOffset != hiddenKeyboard;


return SizedBox(height: isNeedPadding ? bottomOffset : hiddenKeyboard);
}


/// The size of the screen.
class ScreenSizeService {
final BuildContext context;


const ScreenSizeService(
this.context,
);


Size get size => MediaQuery.of(context).size;
double get height => size.height;
double get width => size.width;
}


class LoginPage extends StatelessWidget {
final _imageUrl =
'https://images.unsplash.com/photo-1631823460501-e0c045fa716f?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyNHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60';


const LoginPage({Key? key}) : super(key: key);


@override
Widget build(BuildContext context) {
final screenWidth = ScreenSizeService(context).width;
final screenHeight = ScreenSizeService(context).height;


return Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(_imageUrl),
fit: BoxFit.cover,
),
),
child: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: screenWidth,
minHeight: screenHeight,
),
child: Column(
children: [
...List.generate(6, (index) {
return Column(
children: [
Container(
height: 60,
width: double.maxFinite,
color: Colors.pink[100],
child: Center(child: Text('$index')),
),
const SizedBox(height: 40),
],
);
}),
Container(color: Colors.white, child: const TextField()),
addPaddingWhenKeyboardAppears(),
],
),
),
),
),
);
}
}

这将滚动您的键盘和崩溃大小时,键盘消失。

showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child:SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Container(.......)));

当我们点击文本框和键盘打开媒体查询时,这种奇怪的媒体查询行为在堆栈中重建了一个相同的页面。

< p > < em > < >强MaterialApp ( useInheritedMediaQuery:真的,)< /强> < / em > < / p >

useInheritedMediaQuery设为true会有帮助。

我有同样的问题与我的屏幕,这里我如何解决它:

Scaffold(
resizeToAvoidBottomInset: false,
...
)

enter image description here