创建Flutter工程
flutter
中工程名
、文件夹
和文件
命名规则: 不要用驼峰
、不要用大写
、不要用中文
。
类名可以用驼峰命名
创建工程方式
- 命令创建
// -i objc指定 OC语言,hello_flutter为工程名
flutter create -i objc hello_flutter
- 工具栏创建
- Android Studio启动页创建入口
配置Flutter SDK路径
image.png
Flutter
工程配置
- 配置
android
、ios
语言类型,选择平台类型
- 选择工程
Project
- 选择模拟器,运行flutter工程
Flutter能运行在iOS与Android平台的原因是什么?
原因是在iOS与Android平台都安装了渲染引擎
Flutter与RN的本质区别?
-
RN
:对原生UI
即UIKit
的包装,一旦原生UI产生更新,那么RN也需要进行更新,对原生的依赖性很强,RN有热更新
-
Flutter
:把不同平台的渲染引擎
安装在手机上,渲染引擎
负责解析Dart
代码进行页面展示,Flutter有热重载
优点
:效率高,不依赖于UI,安卓iOS高度统一
缺点
:引入渲染引擎会导致安装包体积增大
hello_flutter
更新Flutter
版本
// 检查flutter环境配置
$ flutter doctor
// 更新flutter版本
$ flutter upgrade
解决Android Studio快捷键Cmd + Q的bug
Android Studio
如果使用快捷键Cmd + Q
强退,有可能会锁住当前的运行环境。一旦锁住运行环境,再次打开工程就有可能出现问题,原因是Android Studio
中为了保护数据,里面有一个缓存机制
。
解决方案
强退Android Studio
导致flutter
卡住了,就需要删除缓存文件
,lockfile文件目录~/flutter/bin/cache/lockfile
开始Flutter编写
- 实现基层组件都需要导入头文件
material.dart
,导入常用的素材
类似于iOS中的UIKit
// 导入flutter的UI库,类似于iOS的UIKit
import 'package:flutter/material.dart';
- 在 iOS中运行APP 是在
window
中,在Flutter
中使用runApp
,在这个里面添加组件,我们先来看看Text
组件
// flutter入口函数
void main() {
runApp(const Center(
child: Text(
'helloFlutter',
textDirection: TextDirection.ltr,
),
));
}
- 当前运行页面里面有两个小部件
Center
、Text
,都是继承于Widget
-
Center
相当于OC中的view
,child
相当于subView
的意思 -
Text
相当于UILabel
flutter是增量渲染
,不会改变组件内容,会直接用新的组件替换旧的组件,直接修改控件本身,以此改变值,所以效率很高;flutter没有页面层级
,它只有一层页面
Dart中的var、final 和 const介绍
- var声明变量
void main() {
var a;//变量
print(a); // 打印结果为null
var b;//变量
b = "this is b !";
print(b); // 打印结果为 this is b !
}
-
var
声明的变量,没有指定值
,也没有指定类型
,是一个动态类型
,鼠标放上去会提示类型! -
dart
中使用var
声明变量,可以赋值不同类型的值,会自动推断变量的类型
和Swift中是一样的效果。 -
var
声明的变量如果没有初始化,那么它的值是null
- final声明变量
void main(){
final a = 10;
a = "hello"; // 运行报错
final b;
b = "hello";
print(b); // 打印结果为 hello
final c;
print(c); // 运行报错
}
-
final
修饰的是一个最终的变量,不能再次赋值
,否则会报错。也可以先声明再次赋值
,但是只能赋值一次。 -
final
适用声明以后不会改变的变量,也就类似一个常量的意思,它只能赋值一次。 -
final
声明的变量,不赋值是不可以使用的
。
- const声明常量
void main(){
const a;
a = 8; // 运行报错
const b = 8;
print(b); // 打印结果为 8
}
-
const
修饰常量,声明的时候就得赋值
,这也是和变量最大的区别! -
const
常量也是不可以修改的,不可以再次赋值,这点和 final 一样
。
自定义Widget
Widget
分为两大类有状态stateful
、无状态stateless
,其实flutter
小组件本质上都是无状态
的,有状态只是定义了一些功能方便开发
-
无状态stateless
表示不可变,如果要想改变,用新的组件替换当前组件 -
有状态stateful
表示在当前树中,内部小组件可以更改状态。影响页面渲染的数据保存起来就是有状态的
自定义Widget
- 继承于
无状态小部件
- 要想让小部件显示在页面上,必须实现
build
方法返回Widget
import 'package:flutter/material.dart';
void main() {
runApp(MyWidget());
}
// 如果main()里面只有一行代码,可以使用箭头函数进行缩写
//void main() => runApp(MyWidget());
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'helloFlutter',
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 14,color: Colors.orange,backgroundColor: Colors.white),
),
);
}
}
image.png
flutter热重载
如果iOS项目过大,编译时间会很长,虽然我们只改了一行代码,想要查看效果,也需要编译很长时间。而flutter
开发中有一个好处,不需要重新启动flutter工程。比如我们改了Text
文字大小,flutter会增量渲染我们修改的内容
,不会重复渲染其他内容,即flutter热重载
。增量渲染
就是用新的小部件直接替换旧的小部件
,将内容展示出来。
如果flutter项目是有状态的,那么数据发生了更改,就需要重新启动flutter项目。即渲染树发生了变化
,需要重新启动flutter项目
。
如果是有状态的小部件
,而且状态发生了变化,热重载状态是不会清零的
。如果要想把状态清零,需要重新启动项目
文字样式
flutter
中创建模型对象
是不会渲染的。这样的对象成员属性是可以更改的,一旦模型对象的属性发生变化,通过这个模型对象取到新的数据,用来创建新的小部件
。
import 'package:flutter/material.dart';
void main() => runApp(MyWidget());
// 继承于无状态小部件
// 要想让小部件显示在页面上,必须实现build方法,返回Widget
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'helloFlutter123123',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: Colors.orange,
)
),
);
}
}
image.png
Text组件
- 创建Text
Text()
构造方法创建 - Text属性
textDirection 文本对齐 (必须要写的属性,否则内容不显示)
TextAlign.center 将文本对齐容器的中心。
TextAlign.end 对齐容器后缘上的文本。
TextAlign.justify 拉伸以结束的文本行以填充容器的宽度。即使用了decorationStyle才起效
TextAlign.left 对齐容器左边缘的文本。
TextAlign.right 对齐容器右边缘的文本。
TextAlign.start 对齐容器前缘上的文本。
maxLines 最大行数
overflow 处理字数溢出
TextOverflow.clip 剪切溢出的文本以修复其容器。
TextOverflow.ellipsis 使用省略号表示文本已溢出。
TextOverflow.fade 将溢出的文本淡化为透明。
textScaleFactor 字号系数
-
TextStyle style
属性
color 文本颜色。
decoration 绘制文本装饰:
下划线(TextDecoration.underline)
上划线(TextDecoration.overline)
删除线(TextDecoration.lineThrough)
无(TextDecoration.none)
decorationStyle 绘制文本装饰的样式:
画一条虚线 TextDecorationStyle.dashed
画一条虚线 TextDecorationStyle.dotted
画两条线 TextDecorationStyle.double
画一条实线 TextDecorationStyle.solid
画一条正弦线(波浪线) TextDecorationStyle.wavy
fontWeight 绘制文本时使用的字体粗细:
FontWeight.bold 常用的字体重量比正常重。即w700
FontWeight.normal 默认字体粗细。即w400
FontWeight.w100 薄,最薄
FontWeight.w200 特轻
FontWeight.w300 轻
fontStyle 字体变体:
FontStyle.italic 使用斜体
FontStyle.normal 使用直立
textBaseline 对齐文本的水平线:
TextBaseline.alphabetic:文本基线是标准的字母基线
TextBaseline.ideographic:文字基线是表意字基线;
fontSize 字体大小
letterSpacing 水平字母之间的空间间隔(逻辑像素为单位)。可以使用负值来让字母更接近。
wordSpacing 单词之间添加的空间间隔(逻辑像素为单位)。可以使用负值来使单词更接近。
height 文本行与行的高度,作为字体大小的倍数
locale 用于选择区域特定字形的语言环境
background 文本背景色
foreground 文本的前景色
shadows 实现一些特殊效果
MaterialApp
- 素材App
- 有
home
属性,主页面 - 有
debugShowCheckedModeBanner
属性,便于我们在调试版本中做操作
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyWidget(),
);
}
}
// 继承于无状态小部件
// 要想让小部件显示在页面上,必须实现build方法,返回Widget
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'helloFlutter123123',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: Colors.orange,
)
),
);
}
}
运行效果
Scaffold小部件
-
Scaffold
是Material Design
布局结构的基本实现,此类提供了用于显示drawer
、snackbar
和底部sheet
的API,是带有导航栏
的小部件。 - 有
body
属性,显示在导航栏下面的区域,需要传递一个Widget
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('FlutterDemo'),
),
),
);
}
}
// Scaffold主要属性
appBar:显示在界面顶部的一个 AppBar
body:当前界面所显示的主要内容
floatingActionButton: 在 Material 中定义的一个功能按钮。
persistentFooterButtons:固定在下方显示的按钮。
drawer:侧边栏控件
bottomNavigationBar:显示在底部的导航栏按钮栏。
backgroundColor:背景颜色
resizeToAvoidBottomPadding: 控制界面内容 body
是否重新布局来避免底部被覆盖了,比如当键盘显示的时候,重新布局避免被键盘盖住内容。默认值为 true。
image.png
自定义小部件MyWidget
嵌入home
页
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('FlutterDemo'),
),
body: MyWidget(),
),
);
}
}
// 继承于无状态小部件
// 要想让小部件显示在页面上,必须实现build方法,返回Widget
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'helloFlutter123123',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: Colors.orange,
)
),
);
}
}
image.png
这个时候Center
是相对于body
居中的,Center
小部件是相对于父视图居中的。
初探ListView
下面实现一个类似UITableView
的页面
- 新建
model
目录,里面创建Car.dart
模型
// <!-- Car.dart文件 -->
class Car {
// {} 表示可选,可以给Car赋值,也可以不赋值
const Car({this.name, this.imageUrl});
final String? name;
final String? imageUrl;
}
-
main.dart
文件中导入Car.dart
import 'model/Car.dart';
- ListView最终代码
import 'package:flutter/material.dart';
import 'model/car.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
// 去掉debug标识
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatelessWidget {
//_是指文件内部!!!只在main.dart文件内部可以访问
Widget _itemForRow(BuildContext context, int index) {
return Container(
color: Colors.white,
margin: const EdgeInsets.all(10),
// 组件的排列有三种,横着 竖着 叠着
child: Column(
children: <Widget>[
// 命名构造函数,图片是异步加载
Image.network(datas[index].imageUrl!),
// SizedBox用于设置图片与文字的间隔,也可以用Container设置间隔
const SizedBox(
height: 10,
),
Text(
datas[index].name!,
style: const TextStyle(
fontWeight: FontWeight.w800,
fontSize: 18.0,
// italic表示斜体
fontStyle: FontStyle.italic,
),
),
],
));
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('FlutterDemo'),
),
// listview构造函数
body: ListView.builder(
// 获取_itemForRow,上面定义的Widget
itemBuilder: _itemForRow,
itemCount: datas.length,
),
);
}
}
//引入`Car`模型数据
final List<Car> datas = [
const Car(
name: '保时捷918 Spyder',
imageUrl:
'https://img.haomeiwen.com/i2990730/7d8be6ebc4c7c95b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '兰博基尼Aventador',
imageUrl:
'https://img.haomeiwen.com/i2990730/e3bfd824f30afaac?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '法拉利Enzo',
imageUrl:
'https://img.haomeiwen.com/i2990730/a1d64cf5da2d9d99?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: 'Zenvo ST1',
imageUrl:
'https://img.haomeiwen.com/i2990730/bf883b46690f93ce?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '迈凯伦F1',
imageUrl:
'https://img.haomeiwen.com/i2990730/5a7b5550a19b8342?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '萨林S7',
imageUrl:
'https://img.haomeiwen.com/i2990730/2e128d18144ad5b8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '科尼赛克CCR',
imageUrl:
'https://img.haomeiwen.com/i2990730/01ced8f6f95219ec?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '布加迪Chiron',
imageUrl:
'https://img.haomeiwen.com/i2990730/7fc8359eb61adac0?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '轩尼诗Venom GT',
imageUrl:
'https://img.haomeiwen.com/i2990730/d332bf510d61bbc2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
const Car(
name: '西贝尔Tuatara',
imageUrl:
'https://img.haomeiwen.com/i2990730/3dd9a70b25ae6bc9?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
)
];
ListView运行效果
Container小部件
Container
是一个容器类,一个拥有绘制
、定位
、调整大小
的 widget
,在Flutter
中万物皆widget
,widget是小部件的意思
。类似于iOS
中的UIView
-
Container
组成
-
Container
的最里层的是child
元素,child
元素首先会被padding
包着,然后添加额外的constraints
限制,最后添加margin
-
Container
自身尺寸的调节分两种情况:
Container
在没有子节点(children)的时候,会试图去变得足够大。除非constraints
是unbounded
限制,在这种情况下,Container
会试图去变得足够小。
带子节点的Container
,会根据子节点尺寸调节自身尺寸,但是Container
构造器中如果包含了width
、height
以及constraints
,则会按照构造器中的参数来进行尺寸的调节。
- Container属性
-
key
:Container唯一标识符
,用于查找更新。 -
alignment
:控制child的对齐方式,如果container
或者container
父节点尺寸大于child
的尺寸,这个属性设置会起作用,有很多种对齐方式。 -
padding
:decoration
内部的空白区域,如果有child
的话,child
位于padding
内部。padding与margin的不同之处在于,padding是包含在content内
,而margin则是外部边界
,设置点击事件的话,padding区域会响应,而margin区域不会响应。 -
color
:用来设置container
背景色,如果foregroundDecoration
设置的话,可能会遮盖color
效果。
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
margin: EdgeInsets.all(10),
color: Colors.red,
alignment: Alignment(0,0),
child: Container(
margin: EdgeInsets.all(10),
color: Colors.brown,
width: 250,
height: 250,
child: Text(
'Hello World',
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 26,color: Colors.blue,backgroundColor: Colors.white),
),
),
);
}
}
运行效果
网友评论