安裝/配置
遇到問題
配置創建第一工程過程中,可能會回到一步在卡在gradle這一步:
Running 'gradle assembleDebug
語法
入口函數
方式一
main(){
}
方式二
void main(){
}
變量
dart是一門強大的腳步類語言,可以不預先定位變量的類型,會自動推斷類型
var s1 = ‘hello’
String s2 = ‘hello’
注:var後不要加類型,寫了類型就不要加var
類裏的變量加上下劃線(_)可以使之變爲私有的,如同private關鍵字
命名規則
- 變量命名必須有數字、字母、下劃線和美元符號($)組成
- 標識符開頭不能是數字
- 標識符不能是保留字和關鍵字
- 變量名字是區分大小寫的
常量
final(運行時變量)
開始可以不賦值,只賦值一次
const(編譯是變量)
值不變,一開始就賦值
數據類型(常用)
- Number(數值)
int
double - String(字符)
String,單引號,雙引號,三個單引號(適用於多行),三個雙引號(適用於多行)
拼接使用s1 $s2’ //hello world
String s4 = s1 + s2 //hello world - Booleans
bool - List(數組)
Dart中,數組是列表對象 - Maps(字典)
map初始化方式一
var map1 = {
“key1”:“value1”,
“key2”:“value2”,
“key3”:“value3”
}初始化方式二
var map2 = new Map()
map2[‘key1’] = ‘value1’;
map2[‘key2’] = ‘value2’;
map2[‘key3’] = ‘value3’;
map2.keys;//獲取所有的key
map.values;//獲取所有的value
類型判斷(is)
var s1 = ‘hello’;
if(s1 is String){
}
運算符(與java基本類似)
賦值運算符 = ??=
String s1;
s1 ??= ‘hello’;//表示如果s1爲空的話,把’hello’賦值給s1
for循環
- (var i = 0;i < length;i++){}
- for(var item in list){}
- list.forEach((value){});
- map.forEach((key,value){});
- newList = list.map((value){//返回原集合中個元素*2的組成新的集合
return value * 2;
}) - newList = list.where((value){//返回原集合中大於10的元素組成新的集合
return value > 10;
}) - newList = list.any((value){//判斷原集合中的元素是否有大於10的
return value > 10;
}) - newList = list.every((value){//判斷原集合中的元素是否都大於10
return value > 10;
})
函數(方法)
- 函數內部可以嵌套函數
- 可選參數使用中括號,如
void func(int a,[int b=1,int c]){} //其中,b,c爲可選參數
3.命名參數使用大括號,如
void func(int a,{int b,int c}){} //其中,b,c爲命名參數
調用
func(1,b=2,c=4)
閉包
概念:函數嵌套函數,嵌套的函數會調用外部函數的變量或參數,變量或參數不會被系統回收
寫法:函數嵌套函數,並return裏面的函數,這樣就形成閉包
類
?條件運算符(同kotlin),如:
Object ob;
ob?.toString()
as 類型轉換
is 類型判斷
… 級聯操作(連綴)
class User{
int age;
String name;
}
User user = new User();
user..age=10
..name="Tim";
初始化列表(執行構造函數前執行)
class User{
int age;
String name;
User()in age=11,name='Tim'{
}
}
class SubUser extend User{
SubUser():supter(){}
}
複寫
@override可寫可不寫
類似多繼承(mixins)
class B{}
class C{}
class A with B,C{
}
注:使用mixins時,B、C類不能有構造函數,B、Clei不能繼承其他類
網絡請求
async: 讓方法變成一部
void test() async {}
await 等待異步方法執行完成
只有在使用async時,才能使用await
getDataFromSever() async {
var httpClient =new HttpClient();
var uri = new Uri.http("http:xxxx");
var request = await httpClient.getUrl(uri);
var respone = await request.close();
return respone.transForm(utf8.decoder).join();
}
第三方模塊
託管:統一託管在pub上,如
dev/packages
fluter-io
dartlang
flutter工程
目錄
程序入口
main(){
runApp(myApp())
}
或
main() => runApp(myApp())
組件
Widget
對應Android中的View
MaterialApp
作爲Widget的頂層組件
home(主頁)
title(標題)
color(顏色)
theme(主題)
routes(路由,相當Activity)
Scaffold 是Meterial Design的佈局的基本實現
有以下幾個屬性
appBar
顯示在界面頂部的AppBar
body
當前界面所顯示的主要內容 Widget
drawer
抽屜菜單類型
…
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
'我是標題欄'
),
),
body: MyCenter(),
),
theme: ThemeData(
primarySwatch:Colors.red //主題顏色
),
);
}
}
class MyCenter extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(
'hello',
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.red,
fontSize: 32
),
)
);
}
}
//class MyApp extends StatelessWidget {
//
// @override
// Widget build(BuildContext context) {
// return new MaterialApp(
// title: 'my First flutter',
// home: new Scaffold(
// appBar: new AppBar(
// title: new Text('I am appBar 哈哈233'),
// ),
// body: new Center(
// child: new Text('Hello World!!!2'),
// ),
// ),
// );
// }
//}
//void main() {
// runApp(
// new Center(
// child: new Text(
// 'Hello, world!',
// textDirection: TextDirection.ltr,
// ),
// ),
// );
//}
Container(容器)
也是集成與StateLessWidget
Image
本地圖片 Image.asset
- 先在工程目錄下創建存放圖片的目錄,如:
images根目錄爲標準圖片
images/2.0x爲2.0倍
images/3.0x爲3.0倍
以上三個目錄比配放置圖片 - 在pubspec.yaml配置該圖片路徑
assets:
- images/bg.png
- images/2.0x/bg.png
- images/3.0x/bg.png
- 最後引用
Image.asset('images/bg.png');
網絡圖片 Image.network(picUrl)
圓角及圓形圖片
圓形
- 利用Container的borderRadius
Container(
width: 400,
height: 400,
decoration: BoxDecoration(
color: Colors.yellow,
// borderRadius: BorderRadius.all(Radius.circular(60))
borderRadius: BorderRadius.circular(60),
image: DecorationImage(
image: NetworkImage('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg'),
fit: BoxFit.cover
))
- 利用Container的ClipOval屬性
child: ClipOval(
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 300,
height: 300,),
),
ListView
ListView內部不能嵌套ListView
ListView(
padding: EdgeInsets.all(15.0),
scrollDirection: Axis.vertical,
children: <Widget>[
ListTile(
leading: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
trailing: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
),
//或者其他Widget
],
);
ListView.builder
import 'package:flutter/material.dart';
class MyListView extends StatelessWidget {
var list = new List();
MyListView(){
for(var i = 0;i < 20;i++){
list.add('第$i條數據');
}
}
@override
Widget build(BuildContext context) {
// return ListView(
// padding: EdgeInsets.all(15.0),
// scrollDirection: Axis.vertical,
// children: _getStaticData(),
// );
return ListView.builder(
itemCount: this.list.length,
itemBuilder: (context,index){
return ListTile(
title: Text(this.list[index]),
);
}
);
}
}
List<Widget> _getStaticData(){
return <Widget>[
ListTile(
leading: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
trailing: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
),
ListTile(
leading: Icon(Icons.accessibility),
title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
),
ListTile(
leading: Image.asset('images/bg.png',width: 44,height: 44,),
title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
)
];
}
GridView
實現方式
GridView.count
GridView.count(
scrollDirection: Axis.vertical,//方向
crossAxisCount: 3, //一行幾列
crossAxisSpacing: 8,//水平間隔
mainAxisSpacing: 8,//垂直間隔
children: _getStaticData(),
)
GridView.builder
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 5,
mainAxisSpacing: 5
),
itemCount: this.list.length,
itemBuilder: (context,index){
return Container(
// height: 120,
child: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg",
fit: BoxFit.cover),
);
}
)
Padding、 Row Column、Expanded
Padding–間距組件
Row–水平組件
Row(
mainAxisAlignment: MainAxisAlignment.end,//主軸(水平)排列方式
children: <Widget>[
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,)
],
)
Column–垂直組件
Column(
mainAxisAlignment: MainAxisAlignment.end,//主軸(垂直)排列方式
children: <Widget>[
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
width: 50,
height: 50,)
],
)
Expanded
類似web中的flex佈局
Row(
children: <Widget>[
Expanded(
flex: 2,
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
height: 100,),
),
Expanded(
flex: 1,
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover,
height: 100,)
)],
)
Stack
頁面層疊組件,類似於RelativeLayout佈局
屬性
alignment 配置所有子元素顯示的位置
Stack(
children: <Widget>[
Align( //相對位置
alignment: Alignment(0,0.5),//(0.0)爲中心
child: Icon(Icons.home,size:60,color: Colors.red),
),
Align(
alignment: Alignment.bottomLeft,
child: Icon(Icons.save,size:60,color: Colors.yellow),
),
Positioned(//絕對位置)
left: 0,//左上角
// top: 0,
// right: 0,
bottom: 100,
child: Icon(Icons.settings,size:60,color: Colors.yellow),
)
],
)
注意:(0.0)爲中心
position
children 子組件
Positioned(//絕對位置)
left: 0,//左上角
// top: 0,
// right: 0,
bottom: 100,
child: Icon(Icons.settings,size:60,color: Colors.yellow),
)
Container(
height: 400,
width: 400,
color: Colors.blue,
alignment: Alignment(0,1),
child: new Stack(
children: <Widget>[
Align( //相對位置
alignment: Alignment(0,0.5),//(0.0)爲中心
child: Icon(Icons.home,size:60,color: Colors.red),
),
Align(
alignment: Alignment.bottomLeft,
child: Icon(Icons.save,size:60,color: Colors.yellow),
),
Positioned(//絕對位置)
left: 0,//左上角
// top: 0,
// right: 0,
bottom: 100,
child: Icon(Icons.settings,size:60,color: Colors.yellow),
)
],
),
)
AspectRadio、Card
AspectRadio
作用:可以設置調整child子元素的寬高比
AspectRatio(
aspectRatio: 2/1,//寬/高
child: Container(
color: Colors.blue
),
)
Card
屬性
- margin 外邊距
- child 子組件
- shape 卡片的陰影效果,默認是圓角的長方形
Card(
margin: EdgeInsets.all(10),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
child: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 16/9,
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
fit: BoxFit.cover),
),
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg"),
),
title: Text('name'),
subtitle: Text('subContent'),
)
],
)
)
RaisedButton
child
onPressed
Wrap
實現流佈局,相對於FloxBoxLayout
import 'package:first_flutter_app/MyRaisedButton.dart';
import 'package:flutter/material.dart';
class MyWrap extends StatelessWidget {
var list = new List();
MyWrap(){
for(var i = 0;i < 20;i++){
list.add('第$i條數據');
}
}
@override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.horizontal,//方向
spacing: 5,//主軸間距
runSpacing: 5,//副軸間距
alignment: WrapAlignment.center,//主軸方向對其方式
children: _getWidgets()
);
}
List<Widget> _getWidgets(){
return list.map((value) {
return MyRaisedButton(value);
}).toList();
}
}
StatefulWidget
有狀態組件
關鍵點
- MyWidget 繼承 StatefulWidget
- 並繼承State
- 改變狀態是,在state類裏調用setState函數
import 'package:flutter/material.dart';
class MySatefulWidget extends StatefulWidget {
@override
_MySatefulWidgetState createState() {
return _MySatefulWidgetState();
}
}
class _MySatefulWidgetState extends State<MySatefulWidget>{
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
SizedBox(
height: 10,
),
Text('Hi ${this.count}'),
SizedBox(
height: 10,
),
RaisedButton(
child: Text('click'),
onPressed: (){
setState(() {
this.count++;
});
},
)
],
);
}
}
BottomNavigationBar
自定義底部導航條
屬於Scaffold
常見屬性
- items 底部導航條按鈕組合(List)
- iconSize
- currentIndex
- onTap 選中變化回調的函數
- fixedColor 選中的顏色,如果不設置,默認跟主題顏色一樣
- type
1).BottomNavigationBar.fixed
2).BottomNavigationBar.shifting
Scaffold(
appBar: AppBar(
title: Text('我是標題欄'),
),
body: this._pages[this._currentIndex],
bottomNavigationBar:BottomNavigationBar(
currentIndex: this._currentIndex,
iconSize: 22.0,//icon大小
fixedColor:Colors.blue, //選中的顏色,如果不設置,默認跟主題顏色一樣
type: BottomNavigationBarType.fixed, //解決多個tabItem時,不顯示的配置
onTap: (int index) {
setState(() {
this._currentIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('首頁')
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
title: Text('消息')
),
BottomNavigationBarItem(
icon: Icon(Icons.departure_board),
title: Text('發現')
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('我的')
),
// BottomNavigationBarItem(
// icon: Image.asset('/images/bg.png'),
// title: Text('發現')
// )
],
))
路由
也就是頁面跳轉,通過navigator來管理路由導航,並提供了堆棧的管理方法,如,Navigator.push()–跳轉下一級,Navigator.pop(),返回上一級
配置方式
基本路由
跳轉
RaisedButton(
child: Text("去搜索"),
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SearchPage()//目標頁
)
);
},
)
返回
Navigator.of(context).pop()
命名路由
定義在MaterialApp裏,相當於Android的manifest文件裏配置的Activity
調用步驟
- 先在MaterialApp註冊頁面信息
MaterialApp(
//註冊裏一個搜索,一個設置頁面
routes: {
'/search':(context) => SearchPage(),
'/setting':(context) => SettingPage(),
},
)
- 在點擊跳轉的時候執行
Navigator.pushNamed(context, "/search");
或
Navigator.pushNamed(context, "/setting");
傳值
//配置頁面,類似Androd裏Manifest.xml配置的Activity
final _routes = {
'/search':(context,{arguments}) => SearchPage(arguments: arguments,),
'/setting':(context,{arguments}) => SettingPage(arguments: arguments)
};
//傳值固定配置函數
Route onGenerateRoute(RouteSettings settings) {
final String name = settings.name;//點擊跳轉是輸入的name//Navigator.pushNamed(context, "/search");name爲"/search"
final Function pageBuilder = _routes[name];//跳轉的函數//(context,{arguments}) => SearchPage(arguments: arguments,)
if (pageBuilder != null) {
if (settings.arguments != null) {
// 如果透傳了參數
return MaterialPageRoute(
builder: (context) =>
pageBuilder(context, arguments: settings.arguments));
} else {
// 沒有透傳參數
return MaterialPageRoute(builder: (context) => pageBuilder(context));
}
}
return null;
}
路由替換
頁面1→頁面2→頁面3 點擊返回到→頁面1,
在頁面2點擊跳轉的時候,執行以下跳轉方法
Navigator.pushReplacementNamed(conext,name)
返回根路由
//相當於跳轉到根頁面,然後把之前的棧清空
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => RootPage()),
(route) => route = null);
跳轉方式
- 路由直接跳轉到下一個頁面
Navigator.pushNamed(context,"/nextPage");
2. 跳轉的下一個頁面,替換當前的頁面Navigator.of(context).pushReplacementNamed('/nextPage')
3. 返回上一個頁面Navigator.of(context).pop()
4. 返回到指定的頁面(指定的頁面必須已經在棧裏)
Navigator.of(context).popUntil(ModalRoute.withName(MyRoute.TABS))
5. 跳轉新頁面並清空堆棧路由或者返回指定的路由Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute(builder: (context) => new MyTextFiled()), (route) => route == null //rootRoute()指定返回的路由 );
AppBar
頂部導航
屬性
屬性 | 描述 |
---|---|
leading | 標題前的一個控件,通常首頁顯示應用的logo,其他頁面顯示返回鍵 |
title | 標題 |
actions | 通常使用IconButton表示,可以放置按鈕組 |
buttom | 通常放tabBar,標題下面顯示一個Tab 導航欄 |
comTheme | 圖標樣式 |
titleTheme | 文字樣式 |
centerTitle | 標題是否居中顯示 |
backgroundColor | 背景欄顏色 |
Scaffold(
appBar: AppBar(
title: Text('myAppbar'),
centerTitle: true,//標題是否居中
backgroundColor: Colors.black,
// leading: Icon(Icons.accessibility),//標題左邊,沒有點擊事件的
leading: IconButton(
icon: Icon(Icons.beach_access),
onPressed: () {
Navigator.pop(context);
},
), //標題左邊,有點擊事件的
actions: <Widget>[ //導航右側圖標
Icon(Icons.settings),
Icon(Icons.departure_board)
],
),
body: Center(
child: Text('內容'),
),
)
AppBar裏的TabBar
常見屬性
屬性 | 描述 |
---|---|
tabs | 顯示的標籤內容,一般用Tab對象,也可以用其他Widget |
controller | TabController對象 |
isScrollable | 是否可以滾動 |
indicatorColor | 指示器(下劃線)顏色 |
indicatorSize | 指示器長度 |
label | 選擇文字的顏色 |
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: <Widget>[
Tab(text: '熱門',),
Tab(text: '推薦',),
],
),
title: Text('myAppbar'),
centerTitle: true,//標題是否居中
backgroundColor: Colors.black,
// leading: Icon(Icons.accessibility),//標題左邊,沒有點擊事件的
leading: IconButton(
icon: Icon(Icons.beach_access),
onPressed: () {
Navigator.pop(context);
},
), //標題左邊,有點擊事件的
actions: <Widget>[ //導航右側圖標
Icon(Icons.settings),
Icon(Icons.departure_board)
],
),
body: TabBarView(
children: <Widget>[
Text('熱門內容'),
Text('推薦內容')
],
),
),
)
切換
- 代碼配置
body: TabBarView(
children: <Widget>[
Text('熱門內容'),
Text('推薦內容')
],
),
2.TabContoller
import 'package:flutter/material.dart';
class MyTabBarCtrlPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyTabBarCtrlPageState();
}
}
class _MyTabBarCtrlPageState extends State<MyTabBarCtrlPage> with SingleTickerProviderStateMixin{
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(
vsync:this,
length:3
);
_tabController.addListener(() {
print('index= ${_tabController.index}');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MyTabBarCtrlPage'),
bottom: TabBar(
controller: this._tabController,//注意,必須要加
tabs: <Widget>[
Tab(text: '熱門'),
Tab(text: '推薦'),
Tab(text: '更多')
],
),
),
body: TabBarView(
controller: this._tabController,//注意,必須要加
children: <Widget>[
Center(
child: Text('熱門內容'),
),
Center(
child: Text('推薦內容'),
),
Center(
child: Text('更多內容'),
)
],
),
);
}
}
Drawer
抽屜組價、側邊欄
左側欄
Drawer()
右側欄
endDrawer()
側欄普通頭部
DrawerHeader
側欄用戶頭部
UserAccountsDrawerHeader()
caffold(
appBar: AppBar(
title: Text('MyDrawer'),
),
body: Center(
child: Text('內容'),
),
drawer: Drawer(
child: Column(
children: <Widget>[
DrawerHeader(
child: Text('左側標題'),
),
Divider(),
Text('左側邊欄內容'),
],
)
),
endDrawer: Drawer(
child: Center(
child: Text('右側邊欄內容'),
),
),
)
按鈕組件
名稱 | 描述 |
---|---|
RaisedButton | 凸起按鈕 |
FlatButton | 扁平化按鈕 |
OutlineButton | 線框按鈕 |
IconButton | 圖標按鈕 |
ButtonBar | 按鈕組 |
FlatingActionButton | 浮動按鈕 |
表單
TextFiled
文本框組件(Editext)
TextField(
obscureText: true,//密碼框
maxLines: 1,
decoration: InputDecoration(
icon: Icon(Icons.people),
hintText: '請輸入內容',
labelText: '用戶名',//顯示在輸入框左上角
border: OutlineInputBorder(),//變邊框的
),
)
獲取TextFiled裏的值
監聽onChanged()方法
TextField(
// obscureText: true,//密碼框
maxLines: 1,
decoration: InputDecoration(
icon: Icon(Icons.people),
hintText: '請輸入內容',
labelText: '用戶名',//顯示在輸入框左上角
border: OutlineInputBorder(),//變邊框的
),
onChanged: (value){
},
)
CheckBox
Checkbox(
value: this._checkFlag,
onChanged: (value) {
setState(() {
this._checkFlag = value;
});
},
activeColor: Colors.yellow,//選擇的顏色
)
CheckBoxListTile
CheckboxListTile(
value: this._checkFlag,
title: Text('標題'),
subtitle: Text('內容'),
secondary: Icon(Icons.settings),//左側加圖片
onChanged: (value) {
setState(() {
this._checkFlag = value;
});
},
)
Radio
Radio(
value: 1,
onChanged: (v){
setState(() {
this._radioValue = v;
});
},
groupValue: this._radioValue,//radio組選擇的值
)
RadioListTile
類似RadioListTile的用法
本地化語言設置
- 引入依賴
在pubspec.yaml文件中配置
dependencies:
flutter_localizations:
sdk: flutter
- 在入口處
MaterialApp(
//配置本地化
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
supportedLocales: [
const Locale('zh', 'CH'),
const Locale('en', 'US')
],
)
日期組件
官方控件
日期
showDatePicker(
context: context,
initialDate: _nowDate,
firstDate: DateTime(1970),
lastDate: DateTime(2021)
).then((result){
})
時間
showTimePicker(
context: context,
initialTime: TimeOfDay.now()
).then((result){
});
Swiper(第三方輪播圖組件)
輪播圖組件
new Swiper(
itemCount: 3,
itemBuilder: (BuildContext context,int index){
return Image.network(
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2628977794,1833531909&fm=26&gp=0.jpg',
fit: BoxFit.cover,);
},
pagination: SwiperPagination(),//指示器(點下。。。)
control: SwiperControl(),//配置左右箭頭
),
)
AlertDialog
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('標題'),
content: Text('內容'),
actions: <Widget>[
FlatButton(
child: Text('取消'),
onPressed: (){
Navigator.pop(context);
},
),
FlatButton(
child: Text('確定'),
onPressed: (){
Navigator.pop(context);
},
),
],
)
SimpleDialog
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: Text('標題'),
children: <Widget>[
SimpleDialogOption(
child: Text('option 1'),
onPressed: (){},
),
SimpleDialogOption(
child: Text('option 2'),
onPressed: (){},
),
SimpleDialogOption(
child: Text('option 3'),
onPressed: (){
Navigator.pop(context,'3');//其中參數'3'可以當結果返回
},
),
],
);
ShowBottomSheet
showModalBottomSheet(
context: context,
builder: (context){
return Container(
height: 160,
child: Column(
children: <Widget>[
Text('選項一'),
Divider(),
Text('選項二'),
Divider(),
Text('選項三'),
Divider(),
Text('選項四'),
],
),
);
},
);
Toast(FlutterToast)
第三方庫
Fluttertoast.showToast(
msg: 'hello toast',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.black,
timeInSecForIos: 1,// only iOS
textColor: Colors.white,
fontSize: 15,
);
自定義Dialog
步驟
- 寫一個組件extend Dialog
import 'package:flutter/material.dart';
class MyCustomDialog extends Dialog{
@override
Widget build(BuildContext context) {
return Material(//注意點
type: MaterialType.transparency,//設置透明
child: Center(
child: Container(
height: 180,
width: 320,
color: Colors.white,
child: Text('自定義dialog'),
)
)
);
}
}
- 調用的地方
showDialog(
context: context,
builder: (context){
return MyCustomDialog(); //此處
}
);
網絡請求
Json數據與Map類型的轉換
需要引入 import ‘dart:convert’
Map轉Json字符串
Map map = {
'年齡':'21',
'性別':'男',
'地址':'xxxx',
};
String jsonStr = json.encode(map);
print('jsonStr= $jsonStr');
Json.encode(Map)
Json字符串轉Map
Json.decode(jsonStr)
String jsonStr2 = '{"年齡":"21","性別":"男","地址":"xxxx"}';
Map map2= json.decode(jsonStr2);
print('map2[年齡]= ${map2["年齡"]}');
get請求
String url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3';
http.Response respone = await http.get(url);//異步請求
print('http_code= ${respone.statusCode}');
if (respone.statusCode == 200) {
print('http_body= ${respone.body}');
setState(() {
this._result = respone.body;
});
Map map = convert.jsonDecode(respone.body);//轉換爲map
}
post請求
print('http_getData');
String url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3';
http.Response respone = await http.post(url,body:this._map);//異步請求
print('http_code= ${respone.statusCode}');
if (respone.statusCode == 200) {
print('http_body= ${respone.body}');
setState(() {
this._result = respone.body;
});
Map map = convert.jsonDecode(respone.body);//轉換爲map
}
Flutter與原生的混合集成
主要有以下兩種
源碼集成 | AAR(andriod),framework(iOS)集成 | |
---|---|---|
優點 | 1. 簡單快捷 2. 和原生交互較多或需要依賴原生的數據環境時,使用該方式調試方便 | 1. 不影響原生項目 2. 不參與Flutter開發的人員處於無感狀態 3. 無需對先原生環境做修改 |
缺點 | 1. 團隊所有人需要安裝Flutter環境 2. 需要對現在編譯發佈體現做修改 | 1. 複雜度較高 2. 與原生調試不是很方便 |
源碼集成
- 在原APP Native工程項目裏,添加flutter_module
- 安裝flutter相關開發插件
AAR集成
- 創建單獨的flutter工程並創建flutter_module
- 開發完成,打包成aar
執行flutter builde aar完成後,控制檯會提示配置以下信息
1. Open <host>/app/build.gradle
2. Ensure you have the repositories configured, otherwise add them:
repositories {
maven {
url '/Users/wangpingtao/yuxun/exitApp/flutter_module/build/host/outputs/repo' //new
}
maven {
url 'http://download.flutter.io' //new
}
}
3. Make the host app depend on the Flutter module:
dependencies {
debugImplementation 'exit.wpt.com.flutter_module:flutter_debug:1.0 //new
profileImplementation 'exit.wpt.com.flutter_module:flutter_profile:1.0 //new
releaseImplementation 'exit.wpt.com.flutter_module:flutter_release:1.0 //new
}
4. Add the `profile` build type:
android {
buildTypes {
profile { //new
initWith debug //new
} //new
}
}
- 在app/build.gralde文件配置aar相關信息:配置aar相關信息