我有一个像这样的扩展小部件列:
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 widgets,并为每个widget硬编码一个高度,这些widget就不会调整大小,但是当键盘出现时,我会得到一个黑黄条纹错误(因为没有足够的空间)。这也不是对所有屏幕尺寸都灵活。
我不确定这是android特有的还是flutter特有的。
方法1:从AndroidManifest.xml文件中删除android:windowSoftInputMode=" adjuststresize "(否则它将覆盖flutter代码),并在Scaffold中添加resizeToAvoidBottomPadding: false,如下所示:
Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar()
)
方法2(不推荐):只需添加android:windowSoftInputMode=" statevvisible "在android AndroidManifest.xml的活动,它将只适用于android和不适用于IOS像。
<activity
...
android:windowSoftInputMode="stateVisible">
注意:不要设置为android:windowSoftInputMode=" adjuststresize "
大多数其他答案建议使用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的解决方案,它将使我们的应用程序行为丑陋,因为当键盘出现时,它不会调整我们的屏幕视口根据可用的高度,它将使其他字段隐藏在键盘后面。所以我建议用esinglechildscrollview代替。
包装您的代码与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,
),
],
),
),
);
我的建议是使用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()
],
),
),
),
);
这是一个完美的解决方案,使您能够在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() )
],
)))),
),
));
}
}
重要的部分是带有正确BoxConstraints和InstrinsicHeight小部件的ConstrainedBox。
PS: MediaQuery.of .padding(上下文)。top + kToolbarHeight) == Appbar的高度
特点:
打开键盘时,背景图像不会调整大小
能够滚动隐藏在键盘后面的元素
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(),
],
),
),
),
),
);
}
}