我们可以根据下面有适配属性的Widget来进行屏幕适配
1.MediaQuery
通过它可以直接获得屏幕的大小(宽度 / 高度)和方向(纵向 / 横向)
Size screenSize = MediaQuery.of(context).size;
double width = screenSize.width;
double height = screenSize.height;
Orientation orientation = MediaQuery.of(context).orientation;
//横向:orientation==Orientation.portrait
//纵向:orientation==Orientation.landscape
实例代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';class HomePage11 extends StatelessWidget {@overrideWidget build(BuildContext context) {Size screenSize = MediaQuery.of(context).size;Orientation orientation = MediaQuery.of(context).orientation;return Scaffold(body: Container(color: Colors.pink,child: Center(child: Text('View\n\n' +'[整个屏幕的宽]: ${screenSize.width.toStringAsFixed(2)}\n\n' +'[整个屏幕的高]: ${screenSize.height.toStringAsFixed(2)}\n\n''[MediaQuery orientation]: $orientation',style: TextStyle(color: Colors.white, fontSize: 18),),),),);}
}
2. LayoutBuilder
使用 LayoutBuilder 组件,可以获得一个 BoxConstraints 对象,通过该对象我们就可以拿到 Widget 的 maxWidth(最大宽度) 和maxHeight(最大高度)
import 'package:flutter/material.dart';class HomePage11 extends StatelessWidget {@overrideWidget build(BuildContext context) {Size screenSize = MediaQuery.of(context).size;return Scaffold(body: Row(children: [Expanded(flex: 2,child: LayoutBuilder(builder: (context, constraints) => Container(color: Colors.pink,child: Center(child: Text('View 1\n\n' +'[MediaQuery]:\n ${screenSize.width.toStringAsFixed(2)}\n\n' +'[LayoutBuilder]:\n${constraints.maxWidth.toStringAsFixed(2)}',style: TextStyle(color: Colors.white, fontSize: 18),),),),),),Expanded(flex: 3,child: LayoutBuilder(builder: (context, constraints) => Container(color: Colors.white,child: Center(child: Text('View 2\n\n' +'[MediaQuery]:\n ${screenSize.width.toStringAsFixed(2)}\n\n' +'[LayoutBuilder]:\n${constraints.maxWidth.toStringAsFixed(2)}',),),),),),],),);}
}
3. OrientationBuilder
要确定当前 Widget 的方向,可以使用 OrientationBuilder 组件。这里的方向与 MediaQuery 提供的设备方向不同。如下这个示例:
import 'package:flutter/material.dart';class HomePage11 extends StatelessWidget {@overrideWidget build(BuildContext context) {Orientation deviceOrientation = MediaQuery.of(context).orientation;return Scaffold(body: Column(children: [Expanded(flex: 2,child: Container(color: Colors.pink,child: OrientationBuilder(builder: (context, orientation) => Center(child: Text('View 1\n\n' +'[MediaQuery orientation]:\n$deviceOrientation\n\n' +'[OrientationBuilder]:\n$orientation',style: TextStyle(color: Colors.white, fontSize: 18),),),),),),Expanded(flex: 3,child: OrientationBuilder(builder: (context, orientation) => Container(color: Colors.white,child: Center(child: Text('View 2\n\n' +'[MediaQuery orientation]:\n$deviceOrientation\n\n' +'[OrientationBuilder]:\n$orientation',),),),),),],),);}
}
4. Expanded 和 Flexible
Expanded 和 Flexible 这两个组件可以和 Column/Row 搭配使用,来实现非常完美的自适应效果。Expanded 可以用来拓展 Row, 、Column 和 Flex,从而让子组件填充可用空间,Flexible 功能类似但并不一定能填充全部可用空间。
下面这个例子演示了混合使用 Expanded 和 Flexible 的各种方式:
import 'package:flutter/material.dart';class HomePage11 extends StatelessWidget {const HomePage11({super.key});@overrideWidget build(BuildContext context) {return Scaffold(backgroundColor: Colors.white,body: SafeArea(child: Column(children: [Row(children: [ExpandedWidget(),FlexibleWidget(),],),Row(children: [ExpandedWidget(),ExpandedWidget(),],),Row(children: [FlexibleWidget(),FlexibleWidget(),],),Row(children: [FlexibleWidget(),ExpandedWidget(),],),],),),);}
}class ExpandedWidget extends StatelessWidget {const ExpandedWidget({super.key});@overrideWidget build(BuildContext context) {return Expanded(child: Container(decoration: BoxDecoration(color: Colors.pink,border: Border.all(color: Colors.white),),child: Padding(padding: const EdgeInsets.all(16.0),child: Text('Expanded',style: TextStyle(color: Colors.white, fontSize: 24),),),),);}
}class FlexibleWidget extends StatelessWidget {const FlexibleWidget({super.key});@overrideWidget build(BuildContext context) {return Flexible(child: Container(decoration: BoxDecoration(color: Colors.amber,border: Border.all(color: Colors.white),),child: Padding(padding: const EdgeInsets.all(16.0),child: Text('Flexible',style: TextStyle(color: Colors.blue, fontSize: 24),),),),);}
}
5. FractionallySizedBox
FractionallySizedBox 组件可以使子组件填充部分可用空间,该特性在 Expanded 或 Flexible 中特别有用。示例如下:
import 'package:flutter/material.dart';class HomePage11 extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(backgroundColor: Colors.white,body: SafeArea(child: Column(mainAxisAlignment: MainAxisAlignment.start,children: [Row(crossAxisAlignment: CrossAxisAlignment.start,children: [FractionallySizedWidget(widthFactor: 0.4),],),Row(crossAxisAlignment: CrossAxisAlignment.start,children: [FractionallySizedWidget(widthFactor: 0.6),],),Row(crossAxisAlignment: CrossAxisAlignment.start,children: [FractionallySizedWidget(widthFactor: 0.8),],),Row(crossAxisAlignment: CrossAxisAlignment.start,children: [FractionallySizedWidget(widthFactor: 1.0),],),],),),);}
}class FractionallySizedWidget extends StatelessWidget {final double widthFactor;FractionallySizedWidget({required this.widthFactor});@overrideWidget build(BuildContext context) {return Expanded(child: FractionallySizedBox(alignment: Alignment.centerLeft,widthFactor: widthFactor,child: Container(decoration: BoxDecoration(color: Colors.pink,border: Border.all(color: Colors.white),),child: Padding(padding: const EdgeInsets.all(16.0),child: Text('${widthFactor * 100}%',style: TextStyle(color: Colors.white, fontSize: 24),),),),),);}
}
6. AspectRatio
AspectRatio 组件可以直接指定子组件的固定宽高比例,使用时,我们可以使用布局约束的最大宽度,并给定一个宽高比自适应其高度,如下示例:
import 'package:flutter/material.dart';
import 'package:fraction/fraction.dart';class HomePage11 extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(backgroundColor: Colors.white,body: SafeArea(child: Column(children: [AspectRatioWidget(ratio: '16 / 9'),AspectRatioWidget(ratio: '3 / 2'),],),),);}
}class AspectRatioWidget extends StatelessWidget {final String ratio;AspectRatioWidget({required this.ratio});@overrideWidget build(BuildContext context) {return AspectRatio(aspectRatio: Fraction.fromString(ratio).toDouble(),child: Container(decoration: BoxDecoration(color: Colors.orange,border: Border.all(color: Colors.white),),child: Padding(padding: const EdgeInsets.all(16.0),child: Center(child: Text('AspectRatio - $ratio',style: TextStyle(color: Colors.white, fontSize: 24),),),),),);}
}