谷歌移動UI框架Flutter教程之Widget
引言
在之間我已經介紹了關於Flutter的下載安裝以及配置,還有開發工具Android Studio的配置,還不知道的同學可以看看我這篇部落格——谷歌移動UI框架Flutter入門。這裡為什麼非要用Android Studio,我可以解釋一下。Android Studio是Google的親兒子,由谷歌一手開發,而Flutter也是谷歌推出的技術,所以在支援和相容問題上,Android Studio是非常有優勢的。老話說得好,肥水不流外人田,谷歌內部肯定是將Android Studio對Flutter的優化做到最佳的。
Widget基本元件
那麼話不多說,我們先來熟悉一下關於Flutter的Widget元件,在Flutter中,一切皆元件,TextView、Image、Row、Column等等,都統稱元件。
1.文字元件(Text)
首先,我們就來瞭解一下文字元件(Text)。學過前端的同學對UI部分應該都很瞭解,那Flutter當然也沒有什麼特別的,無非也就是文字內容、大小、字型樣式、顏色等等的設定,那麼首先我們就先來編寫一個案例。找到lib目錄下的main.dart,我們將在這個檔案中編寫程式碼。
import 'package:flutter/material.dart';
void main() {
runApp(MyTextApp());
}
/**
* 文字元件(Text)的使用
*/
class MyTextApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text Demo',home: Scaffold(
appBar: AppBar(title: Text('文字控制元件的使用'),),body: Center(
child: Text(
'這是一個文字控制元件',//文字內容
textAlign: TextAlign.center,//居中
maxLines: 1,//最大顯示行數
style: TextStyle(
fontSize: 25.0,//字型大小
color: Colors.lightBlue,//字型顏色
),//樣式
),);
}
}複製程式碼
有語言基礎的同學相信可以很好理解這些程式碼,第一行匯入了Material相關的類庫。程式會先執行main()方法,該方法又執行了runApp()方法,並將MyTextApp類作為引數傳遞。而MyTextApp類就是我們自定義的一個類,該類需要去繼承StatelessWidget,並重寫build()方法,該方法需要返回一個元件。具體的程式碼我就不一一介紹了,可以先不用理解每一行程式碼的意思。其中的Text便是文字元件,只需將值寫入括號,便可以在文字框中顯示,然後是文字框的一些屬性。接下來我們執行起來看一下。
2.圖片元件(Image)
接下來是圖片元件,圖片元件的作用無非就是顯示圖片,在Flutter中,Image有四種方式顯示圖片,我只介紹一種,就是顯示網路圖片,其它三種方式沒有太大差別。
import 'package:flutter/material.dart';
void main() {
runApp(MyImageApp());
}
/**
* 圖片元件(Image)的使用
*/
class MyImageApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text Demo',home: Scaffold(
appBar: AppBar(title: Text('圖片元件的使用')),body: Center(
child: Image.network(
'https://www.baidu.com/img/baidu_jgylogo3.gif',//圖片地址
scale: 1.0,//縮放比
),);
}
}複製程式碼
執行效果如下:
3.列表元件(ListView)
列表元件在移動端的開發中使用非常頻繁,那麼在Flutter中,該如何使用ListView呢?
import 'package:flutter/material.dart';
void main() {
runApp(MyListViewApp());
}
/**
* 列表元件(List)的使用
*/
class MyListViewApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text Demo',body: Center(
child: Container(
height: 200.0,child: ListView(
scrollDirection: Axis.horizontal,//列表方向(縱向)
children: <Widget>[
Container(
width: 180.0,color: Colors.lightBlue,Container(
width: 180.0,color: Colors.amber,color: Colors.deepOrange,color: Colors.deepPurple,//Container
],//Widget[]
),);
}
}複製程式碼
有些同學看到這樣的程式碼可能驚呆了,這麼多層的巢狀維護起來豈不是很麻煩,其實這也是Dart語法的特點,避免不了,但是還是有辦法的,我們可以把ListView單獨抽出來,這樣主體的程式碼將會簡潔很多。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlutterApp',home: Scaffold( //主頁
appBar: AppBar(title: Text('FlutterDemo')),//標題
body: Center(
child: Container(
height: 200.0,child: MyList(),//ListView
),//Container
),//主體
),//Scaffold
); //MaterialApp
}
}
class MyList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,children: <Widget>[
Container(
width: 180.0,Container(
width: 180.0,//Container
],//Widget[]
);
}
}複製程式碼
現在執行看一下效果。當然,這樣編寫列表在實際開發中是不現實的,我們應該讓列表活起來,所以,下面介紹如何實現動態列表。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List < String>.generate(1000,(i) => "Item $i")
)
);
}
class MyApp extends StatelessWidget {
final List<String> items;
MyApp({Key key,@required this.items}) :super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlutterApp',//標題
body: ListView.builder(
itemCount: items.length,itemBuilder: (context,index) {
return ListTile(
title: Text('${items[index]}'),);
},//Scaffold
); //MaterialApp
}
}複製程式碼
這樣就實現了動態列表,只不過這個資料還是自己提供的,只需要後期通過網路獲取資料再封裝成集合然後傳遞即可。不懂Dart語法的同學對於裡面的某些程式碼可能會覺得難以理解,但是不用擔心。即使沒有一點Dart語言基礎的同學也是可以很容易地學會Flutter的,只不過在某些Dart語法上就只能死記了,記住它,不用管為什麼。那麼現在來執行看下效果。
4.列表元件(GridView)
第二個列表元件,網格元件,該元件在如今的移動應用中也非常常見,最典型的便是系統相簿。那麼我們關心的是在Flutter中該如何去使用GridView呢?通過一個例子來瞭解一下。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlutterApp',home: Scaffold( //主頁
appBar: AppBar(title: Text('FlutterDemo')),//標題
body: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,mainAxisSpacing: 2.0,//縱軸邊距
crossAxisSpacing: 2.0,//橫軸邊距
childAspectRatio: 0.7 //縮放比例(寬高比)
),children: <Widget>[
Image.network(
'http://img5.mtime.cn/mg/2019/05/31/163641.36482297_270X405X4.jpg',fit: BoxFit.cover),Image.network(
'http://img5.mtime.cn/mg/2019/07/01/091243.35485139_270X405X4.jpg',Image.network(
'http://img5.mtime.cn/mg/2019/06/28/141449.40971533_270X405X4.jpg',Image.network(
'http://img5.mtime.cn/mg/2019/05/31/163641.36482297_270X405X4.jpg',],//Widget[]
) //GridView
),//Scaffold
); //MaterialApp
}
}複製程式碼
網格元件其實也非常的簡單,和ListView其實沒有什麼差別,最主要的就是它獨特的屬性,這些屬性在官網檔案中都有解釋和示例。那麼這段程式碼執行的效果如何呢?我們看一下:
佈局
Flutter中基本的一些元件就介紹完了,但是光知道如何編寫元件可遠遠不夠,UI設計中的佈局管理也尤為重要,那麼,我們繼續深入,瞭解一下Flutter中的佈局。
1.水平佈局(Row)
經過前面基本元件的學習,會發現Flutter無非就是一些元件的巢狀,但注意巢狀級別,不要被自己的程式碼搞暈了,那麼佈局其實是一樣的。我們看一個例子。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Row Widget Demo',home: Scaffold(
appBar: AppBar(
title: Text('水平方向佈局'),//AppBar
body: Row(
children: <Widget>[
RaisedButton(
onPressed: () {},color: Colors.redAccent,child: Text('Red Button'),RaisedButton(
onPressed: () {},color: Colors.orangeAccent,child: Text('Orange Button'),child: Text('Blue Button'),//Widget[]
),//Row
),//Scaffold
); //MaterialApp
}
}複製程式碼
Row即是水平佈局,那麼水平佈局中我們放置了三個按鈕,現在,執行看效果。會發現 ,這個按鈕的右邊空出了一塊,這是為什麼呢?其實是因為我們使用的是一個不靈活的水平佈局,那麼既然有不靈活的水平佈局,那就肯定會有靈活的水平佈局。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Row Widget Demo',//AppBar
body: Row(
children: <Widget>[
Expanded(child: RaisedButton(
onPressed: () {},)),Expanded(child: RaisedButton(
onPressed: () {},//Scaffold
); //MaterialApp
}
}複製程式碼
我們並沒有對程式碼進行過多的修改,只是在每個按鈕外部包了一個Expanded元件,那麼現在我們來看一下執行效果:會發現,按鈕成功自適應螢幕了,這才是我們想要的效果。
2.垂直佈局(Column)
既然有水平佈局,當然就有垂直佈局。現在通過一個例子來理解一下垂直佈局。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Row Widget Demo',home: Scaffold(
appBar: AppBar(
title: Text('水平方向佈局'),//AppBar
body: Column(
children: <Widget>[
Text('Column 1'),Text('This is Column 2'),Text('Column 3'),//Widget
) //Column
),//Scaffold
); //MaterialApp
}
}複製程式碼
應該不難理解,道理是一樣的,現在看一下效果:細心的同學會發現,它預設會有一個居中的對齊方式。但有同學提出疑問了,這也沒居中啊,這不還是在螢幕的左側嗎?其實這個對齊是相對Column來說的,這個Column的大小是由最長的Text元件決定的。通過crossAxisAlignment屬性可以設定Column的對齊方式。
3.層疊佈局(Stack)
使用水平佈局和垂直佈局雖然可以實現大部分的佈局效果,但是如果要在一張圖片上顯示一段文字,這兩種佈局將無法實現。所以,這裡我們學習一種層疊佈局,它能夠很輕鬆地實現這個效果。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
var stack = Stack(
alignment: const FractionalOffset(0.5,0.8),children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(
'https://i0.hdslb.com/bfs/archive/79c30cf5850cb9ec9d6129b200145e1644f696f8.jpg@880w_440h.jpg'),radius: 100.0,//CircleAvatar
Container(
decoration: BoxDecoration(
color: Colors.lightBlue
),padding: EdgeInsets.all(5.0),child: Text('層疊佈局'),)
],//Widget[]
); //Stack
return MaterialApp(
title: 'Row Widget Demo',//AppBar
body: Center(
child: stack,)
),//Scaffold
); //MaterialApp
}
}複製程式碼
我們首先建立一個元件變數,將我們的圖片和文字都定義在裡面,然後通過alignment屬性可以決定文字元件的相對位置,看一下效果:
4.卡片佈局(Card)
最後一個佈局,卡片佈局。來看例子。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
var card = Card(
child: Column(
children: <Widget>[
ListTile(
title: Text(
'江西省南昌市青雲譜區',style: TextStyle(fontWeight: FontWeight.w500),subtitle: Text('Temptation:123456789'),leading: Icon(Icons.account_box,new Divider(),ListTile(
title: Text(
'北京市海淀區中國科技大學',ListTile(
title: Text(
'河南省濮陽市百姓辦公樓',) //ListTile
],//Widget[]
),//Column
); //Card
return MaterialApp(
title: 'Row Widget Demo',//AppBar
body: Center(
child: card
)
),//Scaffold
); //MaterialApp
}
}複製程式碼
執行看效果:篇幅有限,關於Flutter的元件和佈局就介紹到這裡,接下來還會有一篇關於Flutter的進階部落格,感興趣的同學可以看一看。