Flutter入门——面向iOS开发者——用户界面基础
本博客介绍Flutter中UI开发的基础知识以及它与SwiftUI的比较。这包括如何开始开发您的应用程、显示静态文本、创建按钮、对按下事件做出反应、显示列表、网格等。
一、入口
在SwiftUI中,牛奶可以使用它App来启动您的应用程序。
@main
struct MyApp: App {
var body: some Scene {
WindowGroup{
HomePage()
}
}
}
另一种常见的SwiftUI做法是将应用程序主题放在struct符合View协议中。如下所示
struct HomePage: View {
var body: some View {
Text("Hello, World!")
}
}
要启动您的Flutter应用程序,请将您的应用程序实例传递给该runApp函数。
void main() {
runApp(const MyApp());
}
App是一个小部件。构建方法描述了他所带喵的用户界面部分。通常以WidgetApp类开始您的应用程序,例如CupertinoApp.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// Returns a CupertinoApp that, by default,
// has the look and feel of an iOS app.
return const CupertinoApp(
home: HomePage(),
);
}
}
上面使用的小部件HomePage可能以类Scaffold开头。Scaffold实现应用程序的基本布局结构。
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'Hello, World!',
),
),
);
}
}
请注意 Flutter 如何使用Center小部件。SwiftUI 默认在其中心呈现视图的内容。Flutter 并非总是如此。 Scaffold不会body在屏幕中央呈现其小部件。要使文本居中,请将其包裹在一个Center小部件中。要了解不同的小部件及其默认行为,请查看小部件目录。
二、添加按钮
在SwiftUI中,您使用Button struct来创建按钮。
Button("Do something") {
// This clsure gets called when your
//button is tapped
}
要在Flutter中获得相同的结果哦,请使用CupertinoButton类:
CupertinoButton(
onPressed: () {
// This closure is called when your button is tapped.
},
child: const Text('Do something'),
)
Flutter使您可以访问具有预定义的各种按钮。该CupertinoButton来自Cupertino库。Cupertino库中的小部件是为了Apple设计的系统。
三、水平对齐组件
在SwiftUI,堆栈视图在设计布局中起着重要作用。两个独立的结构允许您创建堆栈:
HStack用于水平堆栈视图。VStack用于垂直堆栈视图。
以下SwiftUI视图将地球图像和文本添加到水平堆栈视图:
HStack {
Image(systemName: "globe")
Text("Hello, world!")
}
Flutter使用Row而不是HStack
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(CupertinoIcons.globe),
Text('Hello, world!'),
],
)
该Row小部件需要参数List<Widget>中的一个children。该mainAxisAlignment属性告诉Flutter如何定位具有额外空间的子项。MainAxisAlignment.center将孩子定位在主轴的中心。对于Row,主轴是水平轴。
四、垂直对齐组件
在SwiftUI,您可以VStack即将组件排列成垂直的柱子。
VStack {
Image(systemName: "globe")
Text("Hello, world!")
}
Flutter与上一个示例相同的代码。除了将Row替换成Column.
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(CupertinoIcons.globe),
Text('Hello, world!'),
],
)
五、显示列表视图
在SwiftUI中,您使用List基本组件来显示项目序列。要显示一系列模型对象,请确保用户识别您的模型对象。要使对象可识别,请使用Identifiable协议。
struct Person: Identifiable {
var name: String
}
var persons = [ Person(name: "Person 1"), Person(name: "Person 2"), Person(name: "Person 3"),]
struct ListWithPersons: View {
let persons: [Person]
var body: some View {
List {
ForEach(persons) { person in
Text(person.name)
}
}
}
}
这类似于Flutter喜欢构建其类标小部件的方式。Flutter不需要列表时候可识别的。您设置要显示的项目数,然后为每个项目构建小部件。
class Person {
String name;
Person(this.name);
}
var items = [
Person('Person 1'),
Person('Person 2'),
Person('Person 3'),
];
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index].name),
);
}
),
);
}
}
Flutter对列表有一些注意事项:
- 该
ListView小部件具有构建方法。就像FoorEach SwiftUI List结构中的一样。 itemCount参数ListView设置显示多少项目的ListView.- 有一个索引参数,该
itemBuilder参数介于零和比itemCount小一之间。
前面的示例ListTile为每个项目返回了一个小部件。该ListTile小部件包括属性像height和font-size.这些属性有助于构建列表。但是,Flutter允许您返回几乎所有代表您的数据的小部件。
六、显示网格
在SwiftUI中构建非条件网格时,您可以使用Grid with GridRow
Grid {
GridRow {
Text("Row 1")
Image(systemName: "square.and.arrow.down")
Image(systemName: "square.and.arrow.up")
}
GridRow {
Text("Row 2")
Image(systemName: "square.and.arrow.down")
Image(systemName: "square.and.arrow.up")
}
}
要在Flutter中显示网格,请使用GridView小部件。这个小部件有各种构造函数。每个构造函数都有相似的目标,但使用不同的输入参数。以下示例使用.builder()初始化程序:
const widgets = [
Text('Row 1'),
Icon(CupertinoIcons.arrow_down_square),
Icon(CupertinoIcons.arrow_up_square),
Text('Row 2'),
Icon(CupertinoIcons.arrow_down_square),
Icon(CupertinoIcons.arrow_up_square),
];
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisExtend: 40.0,
),
itemCount: widgets.length,
itemBuilder: (context, index) => widgets[index].
),
);
}
}
SliverGridDelegateWithFixedCrossAxisCount委托确定网格用于布置其组件的各种参数。这包括crossAxisCount规定每行显示的项目数。
SwiftUIGrid和 Flutter 的GridView不同之处在于Grid 需要GridRow. GridView使用委托来决定网格应如何布置其组件。
七、创建滚动视图
在SwiftUI中,您可以使用它ScrollView来创建自定义滚动组件。以下示例以可滚动的方式显示一系列PersonView实例。
ScrollView {
VStack(alignment: .leading) {
ForEach(persons) { person in
PersonView(person: person)
}
}
}
为了创建滚动视图,Flutter使用SingleChildScrollView.再以下示例中,该函数mockPerson模拟Person类的实例以创建自定义PersonView小部件。
SingleChildScrollView(
child: Column(
children: mockPersons
.map(
(person) => PersonView(
person: person,
),
)
.toList(),
),
)
八、响应式和自适应设计
在SwiftUI中,,您可以使用它GeometryReader来出行间相对视图大小。
例如,您可以:
- 乘以
geometry.size.width一些因素来设置宽度。 - 用作
GeometryReader断点来更改应用程序的设计。 您还可以查看尺寸登记是否有.regular或正在.compact使用horizontalSizeClass.
要在Flutter中创建相对视图,您可以使用以下两个选项之一:
- 获取类
BoxConstraints中的对象LayooutBuilder。 - 在构建函数中使用
MediaQuery.of()来获取当前应用程序的大小和方向。 要了解更多信息,请查看创建响应式和自适应应用程序。
九、管理状态
在SwiftUI中,您使用@State属性包装器来表示SwiftUI视图的内部状态。
strcut ContentView: View {
@State private var counter = 0;
var body: some View {
VStack{
Button("+") {counter+=1}
Text(String(counter))
}
}
}
SwiftUI还包括几个选项,用于更复杂的状态管理,例如ObservableObject协议。
Flutter使用StatefulWidget.使用以下两个类实现有状态小部件:
StatefulWidget的子类State的子类
该State对象存储小部件的状态。要更改小部件的状态,请setState()从State子类调用以告诉框架重绘小部件。
以下示例显示了计数器应用程序的一部分:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$_counter'),
TextButton(
onPressed: () => setState(() {
_counter++;
}),
child: const Text('+'),
),
],
),
),
);
}
}
要了解更多管理状态的方法,请查看状态管理。
十、动画
存在两种主要类型的UI动画
- 隐式从当前值到新目标的动画
- 当被问到时,明确的动画。
10.1、隐式动画
SwiftUI和Flutter对动画采用了类似的当大。在这两个框架中,您都可以指定参数。例如duration,和curve。
在SwiftUI中,您使用animate()修饰符来处理隐式动画。
Button("Yap me!"){
angle +=45
}
.rotationEffect(.degrees(angle))
.animation(.easeIn(duration: 1))
Flutter包含用于隐式动画的小部件。这简化了动画通用小部件。Flutter使用以下格式命名这些小部件:AnimatedFoo.
例如:要旋转按钮,请使用AnimateRotation类。这使Transform.rotate小部件具有动画效果。
AnimatedRotation(
duration: const Duration(seconds: 1),
turns: turns,
curve: Curves.easeIn,
child: TextButton(
onPressed: () {
setState(() {
turns += .125;
});
},
child: const Text('Tap me!'),
),
),
Flutter允许您创建自定义隐式动画。要编写新的动画小部件,请使用TweenAnimationBuilder
10.2、显示动画
对于显示动画,SwiftUI使用该withAnimation()函数。
Flutter包括名称格式类似于FooTransition。一个例子就是RotationTransition.
Flutterh还允许您使用AnimatedWidget或创建自定义动画AnimatedBuilder.
要了解有关 Flutter 中动画的更多信息,请参阅动画概述。
十一、在屏幕上绘图
在SwiftUI中,您可以CooreGraphics用来在屏幕上绘制线条和形状。
Flutter有一个基于Canvas类的API,有两个类可以帮你画图:
CustomPaint需要painter
CustomPaint(
painter: SignaturePainter(_points),
size: Size.infinite,
),
CustomPainter实现您的算法以绘制到画布上。
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List<Offset?> points;
@override
void paint(Canvas canvas, Size size) {
fianl Paint paint = Paint()
..color = Colors.black
..strokeWidth = 5.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null) {
canvas.drawLine(points[i]!, points[i + 1]!, paint);
}
}
}
@override
bool shouldRepaint(SignaturePainter oldDelegate) => oldDelegate.points != points;
}
转载自:https://juejin.cn/post/7184384388178640953