赞
踩
ViewConfiguration()
的size与devicePixelRatio达到适配的目的void main() { runApp(MyApp()); } class MyApp extends BaseStatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter', home: Scaffold( body: Column( children: [ TextField(), ], ), ), ); } }
runApp() ——> MaterialApp() ——> Scaffold() ——> _TextField()
build()
函数是如何布局的ScaffoldState
中的build函数即可@override Widget build(BuildContext context) { ///省略若干代码.... return _ScaffoldScope( ///省略若干代码.... child: Material( child: AnimatedBuilder(animation: _floatingActionButtonMoveController, builder: (BuildContext context, Widget? child) { return CustomMultiChildLayout( children: children, delegate: _ScaffoldLayout( extendBody: _extendBody, extendBodyBehindAppBar: widget.extendBodyBehindAppBar, minInsets: minInsets, ///省略若干代码.... ), ); }), ), }
CustomMultiChildLayout
组件的,这里就只需要关注minInsets
这个参数就行了:// The minimum insets for contents of the Scaffold to keep visible.
final EdgeInsets minInsets = mediaQuery.padding.copyWith(
bottom: _resizeToAvoidBottomInset ? mediaQuery.viewInsets.bottom : 0.0,
);
// The minimum viewPadding for interactive elements positioned by the
// Scaffold to keep within safe interactive areas.
final EdgeInsets minViewPadding = mediaQuery.viewPadding.copyWith(
bottom: _resizeToAvoidBottomInset && mediaQuery.viewInsets.bottom != 0.0 ? 0.0 : null,
);
minInsets
是个EdgeInsets
对象,而它的bottom值则是从mediaQuery.viewInsets.bottom
中获取的viewInsets
这个参数到底是什么意思呢?来看下类中的注释吧大家可以自己通过谷歌翻译查看下,大致意思就是:
被系统UI遮挡的部分,当键盘可见时viewInsets.bottom的值对应于键盘的顶部
,也就是说键盘高度会等于viewInsets.bottom的值
MediaQueryData
相信大家都不陌生了吧,用来获取系统的一些信息数据MediaQueryData mediaQuery = MediaQuery.of(context)
InheritedWidget
组件的,用来达到各子组件中数据共享的目的。那这个组件是在什么时候初始化的呢?MaterialApp
组件中寻找答案了,这同样是个StatefulWidget组件_MediaQueryFromWindowsState#buld()
中MaterialApp ——> _MaterialAppState#build() ——> WidgetsApp ——> _WidgetsAppState#build() ——> _MediaQueryFromWindow() ——> _MediaQueryFromWindowsState#build()
@override
Widget build(BuildContext context) {
MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance!.window);
if (!kReleaseMode) {
data = data.copyWith(platformBrightness: debugBrightnessOverride);
}
return MediaQuery(
data: data,
child: widget.child,
);
}
MediaQuery
,而数据是从WidgetsBinding.instance!.window
上获取的数据Scaffold
的布局;一开始说了是由于使用了屏幕适配框架导致的bug,也就是说这个window上的devicePixelRatio
、size
并没有修改到,这才导致了viewInsets的bottom
值计算错误,可以具体看下MediaQueryData的创建MediaQueryData.fromWindow(ui.SingletonFlutterWindow window) : size = window.physicalSize / window.devicePixelRatio, devicePixelRatio = window.devicePixelRatio, textScaleFactor = window.textScaleFactor, platformBrightness = window.platformBrightness, padding = EdgeInsets.fromWindowPadding(window.padding, window.devicePixelRatio), viewPadding = EdgeInsets.fromWindowPadding(window.viewPadding, window.devicePixelRatio), viewInsets = EdgeInsets.fromWindowPadding(window.viewInsets, window.devicePixelRatio), systemGestureInsets = EdgeInsets.fromWindowPadding(window.systemGestureInsets, window.devicePixelRatio), accessibleNavigation = window.accessibilityFeatures.accessibleNavigation, invertColors = window.accessibilityFeatures.invertColors, disableAnimations = window.accessibilityFeatures.disableAnimations, boldText = window.accessibilityFeatures.boldText, highContrast = window.accessibilityFeatures.highContrast, alwaysUse24HourFormat = window.alwaysUse24HourFormat, navigationMode = NavigationMode.traditional;
MediaQuery.of(context)
从树中向上查找拿到MediaQueryData
这个流程来下手static MediaQueryData of(BuildContext context) {
assert(context != null);
assert(debugCheckHasMediaQuery(context));
return context.dependOnInheritedWidgetOfExactType<MediaQuery>()!.data;
}
Scaffold
组件外层包一层自己的MediaQuery
,让它获取的是我们给定的值就可以了,具体代码如下:class KeyboardScaffoldWidget extends StatefulWidget { final Widget child; const KeyboardScaffoldWidget({Key? key, required this.child}) : super(key: key); @override State<StatefulWidget> createState() { return _KeyboardScaffoldWidgetState(); } } class _KeyboardScaffoldWidgetState extends XyBaseState<KeyboardScaffoldWidget> with WidgetsBindingObserver { ///设计稿宽度 double screenWidth = 375; double get adapterRatio { return window.physicalSize.width / screenWidth; } @override void initState() { super.initState(); WidgetsBinding.instance!.addObserver(this); } @override void didChangeAccessibilityFeatures() { setState(() {}); } // METRICS @override void didChangeMetrics() { setState(() {}); } @override void didChangeTextScaleFactor() { setState(() {}); } // RENDERING @override void didChangePlatformBrightness() { setState(() {}); } @override Widget build(BuildContext context) { return MediaQuery( data: createMediaQueryData(adapterRatio), child: widget.child, ); } @override void dispose() { super.dispose(); WidgetsBinding.instance!.removeObserver(this); } //创建适配后的MediaQueryData,解决:键盘顶起输入框有间距问题 ///只修改viewInsets的devicePixelRatio static MediaQueryData createMediaQueryData(double devicePixelRatio) { SingletonFlutterWindow window = WidgetsBinding.instance!.window; return MediaQueryData( ///省略部分代码.... ///只修改viewInsets的devicePixelRatio viewInsets: EdgeInsets.fromWindowPadding(window.viewInsets, devicePixelRatio)); } }
Scaffold
外层就可以解决return KeyboardScaffoldWidget(
child: Scaffold(...),
);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。