概述
Flutter提供了从单一代码库构建可移动设备、桌面和Web上运行的应用程序的新机会。然而,伴随着这些机遇,新的挑战也随之而来。您希望您的应用程序让用户感到熟悉,通过最大限度地提高可用性并保存舒适和无缝的体验来适应每个平台。也就是说,您需要构建的应用程序不仅是多平台,而且是完全平台自适应的。
开发平台自适应应用程序有很多考虑因素,但它们分为三大类:
- Layout
- Input
- Idioms and norms
一、创建自适应布局
将您的应用程序移植到多个平台时,您必须先考虑的事情之一是如何使其适应将在其上运行的各种尺寸和形状的布局。
1.1、布局小部件
如果您一直在构建应用程序或网站,您可能熟悉创建响应式界面。对于Flutter开发人员来说幸运的是,有大量的小部件可以让这一切变得更容易。
Flutter的一些最有用的布局小部件包括:
Single Child
Align
——在自身内部对齐一个子部件。对于垂直和水平对齐,它采用介于-1和1之间的双精度值。AspectRatio
——尝试将子部件的大小调整为特定的横纵比。ConstrainedBox
——对其子项加大小限制,提供对最小或最大大小的控制。CustomSingleChildLayout
——使用委托函数定位单个子项。委托可以确定子项的布局约束和定位。Expanded和Flexible
——允许一个Row
或一个Coolumn
子项收缩或增长以填充任何可用空间。FractionallySizeBox
——将其子项调整为可用空间的一小部分。LayoutBuilder
——构建一个可以根据其父级大小自行回流的小部件。SingleChildScrollView
——向单个孩子添加滚动。通常与Row
或Column
一起使用。
Multiple Child
Column
、Row
、Flex
——在单个水平或垂直运行中布置子项。Column
和Row
都是继承自Flex
。CustomMultiChildLayout
——在布局阶段使用委托函数定位多个子项。Flow
——类似于CustomMultiChildLayout
,但效率更高,因为它是绘制阶段而不是布局阶段执行的。ListView
、GridView
和CustomScrollView
——提供可滚动的子项列表。Stack
——相对于边缘分层和定位多个子项。功能类似于CSS中的固定位置。Table
——对其子项使用经典的表格布局算法,组合多行和多列。Wrap
——在多个水平或垂直中显示其子项。
1.2、视觉密度
不同的输入设备提供不同级别的精度,这需要不同大小和点击区域。Flutter的VisualDensity
类可以轻松调整整个应用程序的视图密度,例如,通过在触摸设备放大按钮(因此更容易点击)。
当您在MaterialApp
,MaterialComponents
中更改VisualDensity
时,支持它会设置动画以匹配它们的密度。默认情况下,水平和垂直密度均设置为0.0,但您可以将密度设置为任何负值或正值。通过在不同密度之间切换,您可以轻松调整您的UI:
double densityAmt = touchMode ? 0.0 : -1.0;
VisualDensity density = VisualDensity(horizontal: densityAmt, vertical: densityAmt);
return MaterialApp(theme: Theme(visualDensity: density),home: MainAppScaffold(),debugShowCheckModeBanner: false,
);
要VisualDensity
在您自己的视图中使用,您可以查找:
VisualDensity density = Theme.of(context).visualDensity;
容器不仅自己对密度变化做出反应,还会在密度变化时进行动画处理。这将您的自定义组件与内置组件联系在一起,以实现整个应用程序的平滑过渡效果。
如果所示,VisualDensiity
是无单位的,因此对于不同的视图可能意味着不同的事物。在这个例子中,1个密度单位等于6个像素,但这完全取决于您的观点。它没有单位的事实使它非常通用,并且它应适用于大多数情况。
值得注意的是,Material
组件通常为每个视觉密度单位使用大约4个逻辑像素的值。有关支持的组件的更多信息,请参阅VisualDensity
API。有关一般密度原则的更多信息,请参阅Material Design 指南。
1.3、上下文布局
如果您需要的不仅仅是密度变化,而且找不到满足您需要的小部件,您可以采用更程序化的方法参数、计算大小、交换小部件,或者完全重构您的UI以适应特定的外形尺寸。
1.3.1、基于屏幕的断点
最简单的程序布局形式使用基于屏幕的断点。在Flutter中,这可以通过MediaQuery
API来完成。对于此处使用的大小没有硬性规定,但这些事一般值:
class FormFactor {static double desktop = 900;static double tablet = 600;static double handset = 300;
}
使用断点,您可以设置一个简单地系统来确定设备类型:
ScreenType getFormFactor(BuildContext context) {// Use .shortestSide to detect device typee regardless of orientationdouble deviceWidth = MediaQuery.of(context).size.shortestSlide;if (deviceWidth > FormFactor.desktop) return ScreenType.Desktop;if (deviceWidth > FormFactor.tablet) return ScreenType.Tablet;if (deviceWidth > FormFactor.handset) return ScreenType.HHandset;return ScreenType.Watch;
}
作为替代方案,您可以对其进行更多抽象并根据从小到大进行定义:
enum ScreenSize { Small, Normal, Large, ExtraLarge }
ScreenSize getSize(BuildContext context) {double deviceWidth = MediaQuery.of(context).size.shoortestSide;if (deviceWidth > 900) return ScreenSize.ExtraLarge;if (deviceWidth >