本文的目的在于:介紹快速入門Flutter的知識(shí)诸老,學(xué)習(xí)本篇后你能更好的理解Flutter的框架結(jié)構(gòu)窒典。打好基礎(chǔ)后倍靡,你可以選擇把本文介紹到的每一項(xiàng)更深入的學(xué)習(xí)叮盘,以便完成更加復(fù)雜的功能猜绣。本文會(huì)以知識(shí)點(diǎn)加例子的方式來展開灰殴。本文將flutter的widget稱為控件。
你將學(xué)到
1.常用控件的使用和介紹
2.常用添加手勢(shì)的方法
3.根據(jù)用戶操作動(dòng)態(tài)改變控件狀態(tài)
4.控件的一些簡(jiǎn)單生命周期事件
項(xiàng)目開篇介紹
一個(gè)Flutter項(xiàng)目從main函數(shù)中的runApp
調(diào)用開始途事。在ranApp函數(shù)中所接收的控件會(huì)成為整個(gè)屏幕的根控件验懊,并覆蓋在整個(gè)屏幕。(可以將這個(gè)控件理解成iOS中的rootViewController或android中在manifest文件中配置的mainActivity的界面)尸变。而其他的控件(widget)都是在這個(gè)根控件上添加的义图。
舉個(gè)例子:在屏幕上顯示一句hello world的代碼:
這樣一個(gè)效果的代碼:
import 'package:flutter/material.dart';
void main() {
runApp( // 接收的是根的widget
new Center( //根的widget,Center可以在屏幕中心顯示控件
child: new Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
常用的控件
Text
:該 widget 可讓創(chuàng)建一個(gè)帶格式的文本召烂。Row
碱工、Column
: 這些具有彈性空間的布局類Widget可讓您在水平(Row)和垂直(Column)方向上創(chuàng)建靈活的布局。Stack
: 取代線性布局 (譯者語(yǔ):和Android中的LinearLayout相似)奏夫,Stack
允許子 widget 堆疊怕篷, 你可以使用Positioned
來定位他們相對(duì)于Stack
的上下左右四條邊的位置。Stacks是基于Web開發(fā)中的絕度定位(absolute positioning )布局模型設(shè)計(jì)的酗昼。Container
:Container
可讓您創(chuàng)建矩形視覺元素廊谓。container 可以裝飾為一個(gè)BoxDecoration
, 如 background、一個(gè)邊框麻削、或者一個(gè)陰影蒸痹。Container
也可以具有邊距(margins)春弥、填充(padding)和應(yīng)用于其大小的約束(constraints)。另外叠荠,Container
可以使用矩陣在三維空間中對(duì)其進(jìn)行變換匿沛。
舉例,使用簡(jiǎn)單控件自定義一個(gè)AppBar:
分析:
- 用container來作為appbar的矩形框榛鼎,設(shè)置了height(高度)逃呼,padding(內(nèi)邊距),decoration(背景)等屬性者娱。在矩形內(nèi)部添加了橫向控件Row抡笼,分別添加了IconButton、Expanded和另一個(gè)IconButton分別代表左側(cè)的圖標(biāo)肺然、中間的標(biāo)題和右邊的圖標(biāo)蔫缸。
- 這里定義了一個(gè)title屬性,它在Expanded中被使用际起。title的值由外部通過參數(shù)傳入拾碌。這里告訴我們,widget可以被當(dāng)作參數(shù)傳遞街望。
原文鏈接
更多教程
使用 Material 組件
雖然我們可以自定義很多控件校翔,但是Flutter還是預(yù)定義了很多的組件可以方便的直接使用。例如:
-
Navigator
管理由字符串標(biāo)識(shí)的Widget棧灾前,可以讓您的應(yīng)用程序在頁(yè)面之間的切換防症。
看一個(gè)例子:
分析:
1.Material應(yīng)用程序以
MaterialApp
widget開始。 是否使用MaterialApp
完全是可選的哎甲,但是使用它是一個(gè)很好的做法蔫敲。2.
AppBar
中,我們給參數(shù)leading炭玫、actions奈嘿、title分別傳一個(gè)widget3.FloatingActionButton是右下角的按鈕
此外,
Scaffold
也是一個(gè)widget吞加,可以接收許多不同的widget的作為參數(shù)裙犹,其中的每一個(gè)被放置在Scaffold
布局中相應(yīng)的位置。
添加手勢(shì)處理
可以使用手勢(shì)檢測(cè)器 GestureDetector
添加手勢(shì)處理衔憨。例如自定義按鈕的點(diǎn)擊事件處理:
代碼中的 GestureDetector
widget并不具有顯示效果叶圃,只能檢測(cè)由用戶做出的手勢(shì)。 當(dāng)用戶點(diǎn)擊Container
時(shí)践图, GestureDetector
會(huì)調(diào)用它的onTap
回調(diào)掺冠, 在回調(diào)中,將消息打印到控制臺(tái)码党。您可以使用GestureDetector
來檢測(cè)各種輸入手勢(shì)赫舒,包括點(diǎn)擊悍及、拖動(dòng)和縮放。
常見的手勢(shì)事件如下:
- Tap
- onTapDown 指針已經(jīng)在特定位置與屏幕接觸
- onTapUp 指針停止在特定位置與屏幕接觸
- onTap tap事件觸發(fā)
- onTapCancel 先前指針觸發(fā)的onTapDown不會(huì)在觸發(fā)tap事件
- 雙擊
- onDoubleTap 用戶快速連續(xù)兩次在同一位置輕敲屏幕.
- 長(zhǎng)按
- onLongPress 指針在相同位置長(zhǎng)時(shí)間保持與屏幕接觸
- 垂直拖動(dòng)
- onVerticalDragStart 指針已經(jīng)與屏幕接觸并可能開始垂直移動(dòng)
- onVerticalDragUpdate 指針與屏幕接觸并已沿垂直方向移動(dòng).
- onVerticalDragEnd 先前與屏幕接觸并垂直移動(dòng)的指針不再與屏幕接觸接癌,并且在停止接觸屏幕時(shí)以特定速度移動(dòng)
- 水平拖動(dòng)
- onHorizontalDragStart 指針已經(jīng)接觸到屏幕并可能開始水平移動(dòng)
- onHorizontalDragUpdate 指針與屏幕接觸并已沿水平方向移動(dòng)
- onHorizontalDragEnd 先前與屏幕接觸并水平移動(dòng)的指針不再與屏幕接觸,并在停止接觸屏幕時(shí)以特定速度移動(dòng)
稍微復(fù)雜點(diǎn)的例子扣讼,listView多狀態(tài)處理
效果:
整個(gè)效果分兩部分講解:
- 1.listview部分
- 2.cell部分(listview中的每一行)
ListView
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: 'Shopping App',
home: new ShoppingList(
products: <Product>[
new Product(name: 'Eggs'),
new Product(name: 'Flour'),
new Product(name: 'Chocolate chips'),
],
),
));
}
class ShoppingList extends StatefulWidget {
ShoppingList({Key key, this.products}) : super(key: key);
final List<Product> products; //接收main函數(shù)中傳遞過來的數(shù)據(jù)
@override
_ShoppingListState createState() => new _ShoppingListState();
}
class _ShoppingListState extends State<ShoppingList> {
Set<Product> _shoppingCart = new Set<Product>();
void _handleCartChanged(Product product, bool inCart) {
setState(() { //調(diào)用setState會(huì)觸發(fā)重新構(gòu)建界面
if (inCart)
_shoppingCart.add(product);
else
_shoppingCart.remove(product);
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Shopping List'),
),
body: new ListView(
padding: new EdgeInsets.symmetric(vertical: 8.0),
children: widget.products.map((Product product) { //遍歷父控件的值構(gòu)建ListView
return new ShoppingListItem( //構(gòu)建cell
product: product,
inCart: _shoppingCart.contains(product), //傳遞inCart值
onCartChanged: _handleCartChanged, //傳遞點(diǎn)擊函數(shù)
);
}).toList(),
),
);
}
}
Cell部分
class Product {
const Product({this.name});
final String name;
}
typedef void CartChangedCallback(Product product, bool inCart);
class ShoppingListItem extends StatelessWidget {
ShoppingListItem({Product product, this.inCart, this.onCartChanged}) //接收父控件傳遞過來的值
: product = product,
super(key: new ObjectKey(product));
final Product product;
final bool inCart;
final CartChangedCallback onCartChanged;
Color _getColor(BuildContext context) {
return inCart ? Colors.black54 : Theme.of(context).primaryColor; //根據(jù)inCart不同值顯示不同顏色
}
TextStyle _getTextStyle(BuildContext context) {
if (!inCart) return null;
return new TextStyle(
color: Colors.black54,
decoration: TextDecoration.lineThrough,
);
}
@override
Widget build(BuildContext context) {
return new ListTile( //構(gòu)造cell
onTap: () { //點(diǎn)擊方法缺猛,調(diào)用父控件傳遞過來的方法
onCartChanged(product, !inCart);
},
leading: new CircleAvatar(
backgroundColor: _getColor(context),
child: new Text(product.name[0]),
),
title: new Text(product.name, style: _getTextStyle(context)),
);
}
}