Flutter开发学习.md

460 阅读14分钟

为什么选择Flutter

uni-app可实现跨平台开发,目前用到的是小程序开发,同事推荐学习Flutter,开始以为Flutter也可以是实现跨小程序开发,结果只是移动端和H5开发,但是对于移动端开发人员来说还是很不错的选择。

2020.03.02

按着视频教程和文档学习

组件

  • 自定义 WidgetCenter 组件、Text 组件MaterialApp 组件Scaffold 组件

Text 组件

该 widget 可让创建一个带格式的文本。

class HomeContent extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Center(
      child: Container(
        child: Text(
          '我是一个文本,你是个傻呀呀呀呀呀呀呀啊呀呀',
          textAlign: TextAlign.left,
          overflow: TextOverflow.ellipsis,
          maxLines: 2, //文字显示最大行数
          // textDirection: TextDirection.rtl,//文本方向
          // textScaleFactor: 1.0,//文字显示倍数
          style:TextStyle( //文字样式设置
            fontSize: 30.0,
            fontWeight: FontWeight.w800,
            color: Colors.blue,
            decoration: TextDecoration.lineThrough,
            decorationColor: Colors.white,
            decorationStyle: TextDecorationStyle.dashed,//虚线
            wordSpacing: 3.0,
            letterSpacing: 1.5,
            fontStyle: FontStyle.italic
          ),
        ),
        width:300.0,
        height: 300.0,
        decoration: BoxDecoration( //文字装饰线
          color: Colors.yellow,
          border: Border.all(
            color: Colors.red,
            width: 2.0,
          ),
          borderRadius: BorderRadius.all(
            //Radius.circular(150) //圆形
            Radius.circular(8.0)
          ),
          //borderRadius: BorderRadius.circular(20) 
        ),
        // margin: EdgeInsets.all(20), //
        padding: EdgeInsets.all(20),
        // padding: EdgeInsets.fromLTRB(10, 20, 40, 5),
        // transform: Matrix4.translationValues(100, 30, 0),
        // transform: Matrix4.rotationZ(0.3),
        // transform:Matrix4.diagonal3Values(1.2, 1, 1),
        alignment: Alignment.center,//配置元素位置

      ),
    );
  }
  
}

Container 组件

容器组件,相当于 div,布局组件。可创建矩形视觉元素。

MaterialApp组件

Scaffold组件

图片组件

引入远程图片Image.network

普通引入图片

child: Image.network(
    'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/2/1709a01b029a6ef0~tplv-t2oaga2asx-image.image',
    alignment: Alignment.topLeft, 
    // color: Colors.blue,
    // colorBlendMode: BlendMode.darken, 
    fit: BoxFit.contain,
    repeat: ImageRepeat.noRepeat,
    width: 200,
    height: 200,
),

实现圆角以及实现圆形图片:

decoration: BoxDecoration( 
    color: Colors.yellow,
    borderRadius: BorderRadius.circular(150),
    image: DecorationImage(
        image: NetworkImage('https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/2/1709a01b029a6ef0~tplv-t2oaga2asx-image.image'),
    fit: BoxFit.cover
    )
),

推荐使用这一种

child: ClipOval(
    child: Image.network(
        'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/2/1709a01b029a6ef0~tplv-t2oaga2asx-image.image',
        width:100.0,
        height: 100.0,
        fit: BoxFit.cover,
    ),
),

引入本地图片Image.asset

  1. 新增images文件夹:images文件夹中包括2.0x(必须)、3.0x(必须)、4.0x、最外层的图片,如下图所示:

图一

  1. 打开 pubspec.yaml 声明一下添加的图片文件,注意要配置对,如下图所示:

图二

  1. 在代码中使用
child: Container(
    child: Image.asset( 
        'images/2.png' ,
        fit:BoxFit.cover
    ),

2020.03.03

图标组件

Material icons

new IconButton(
    icon: new Icon(Icons.menu),
    tooltip: 'Navigation menu',
    onPressed: null, // null 会禁用 button
),

ListView列表组件

ListView列表参数

名称类型说明
scrollDirectionAxisAxis.horizontal 水平列、Axis.vertical 垂直列表
paddingEdgeInsetsGeometry内边距
resolvebool组件反向排序
childrenList列表元素
  • ListView
  • ListView.builder

默认垂直列表(图文列表)

水平列表

scrollDirection:Axis.horizontal

矩阵式列表

新闻列表 :

class HomeContent extends StatelessWidget{
    // 自定义方法 加_  私有方法
    // 2.获取返回的listData数据,通过map遍历渲染数据
    List<Widget> _getData(){
  
          var tempList = listData.map((v){ //map返回结构是(xx,xx)
            return ListTile(
              leading: Image.network(v['imageUrl']),
              title: Text(v['title']),
              subtitle: Text(v['author']),
              trailing:Icon(Icons.arrow_forward_ios,color:Colors.red), 
            );
          });
    
          return tempList.toList();
    }
    
     @override
      Widget build(BuildContext context) {
        //调用遍历的方法
          return ListView(
              children: this._getData(),//调用遍历的方法
          );
          
      }
      
}

动态列表

import './res/listData.dart';

class HomeContent extends StatelessWidget{
    //把遍历的内容提取出来
      Widget _getListData(context,index){
        return ListTile(
          leading: Image.network(listData[index]['imageUrl']),
          title: Text(listData[index]['title']),
          subtitle: Text(listData[index]['author']),
          trailing:Icon(Icons.arrow_forward_ios,color:Colors.orange), 
        );
      }
      
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return ListView.builder(
           itemCount: listData.length,
           itemBuilder: this._getListData,//此处是赋值
        );
          
      }

}

ListTile组件

this.leading,
this.title,
this.subtitle,
this.trailing,

CircleAvatar组件

头像组件

 ListTile(
    // leading: Image.network('https://www.itying.com/images/flutter/2.png',fit: BoxFit.cover,),
    leading:CircleAvatar(
      backgroundImage:NetworkImage(value['imageUrl'])
    ),

    title: Text(value['title']),
    subtitle: Text(value['description'],maxLines: 2,overflow:TextOverflow.ellipsis),
  ),

GridView组件实现网格布局

名称类型说明
scrollDirectionAxis滚动方法
paddingEdgeInsetsGeometry内边距
resolvebool组件反向排序
crossAxisSpacingdouble水平子 Widget 之间间距
mainAxisSpacingdouble垂直子 Widget 之间间距
crossAxisCountint一行的 Widget 数量
childAspectRatiodouble子 Widget的宽度和高度的比例
children[ ]
gridDelegateSliverGridDelegateWithFixedCrossAxisCount(常用)、SliverGridDelegateWithMax控制布局主要用在 GridView.builder 里面

GridView.count

静态列表

class LayoutDemo extends StatelessWidget {  


  List<Widget> _getListData() {
      var tempList=listData.map((value){
          return Container(            
            child:Column(
                children: <Widget>[
                  Image.network(value['imageUrl']),
                  SizedBox(height: 12),
                  Text(
                    value['title'],
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      fontSize: 20
                    ),
                  )
                ],
            ),
            decoration: BoxDecoration(
              border: Border.all(
                color:Color.fromRGBO(233, 233,233, 0.9),
                width: 1
              )
            ),
            // height: 400,  //设置高度没有反应
          );
      });
      // ('xxx','xxx')
      return tempList.toList();
  }

  @override
  Widget build(BuildContext context) {    
    return GridView.count(
        crossAxisSpacing:10.0 ,   //水平子 Widget 之间间距
        mainAxisSpacing: 10.0,    //垂直子 Widget 之间间距
        padding: EdgeInsets.all(10),
        crossAxisCount: 2,  //一行的 Widget 数量
        // childAspectRatio:0.7,  //宽度和高度的比例
        children: this._getListData(),
    );
  }
}

GridView.builder

动态列表

class LayoutDemo extends StatelessWidget {  
  Widget _getListData (context,index) {
        return Container(            
            child:Column(
                children: <Widget>[
                  Image.network(listData[index]['imageUrl']),
                  SizedBox(height: 12),
                  Text(
                    listData[index]['title'],
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      fontSize: 20
                    ),
                  )
                ],
            ),
            decoration: BoxDecoration(
              border: Border.all(
                color:Color.fromRGBO(233, 233,233, 0.9),
                width: 1
              )
            ),
              
            // height: 400,  //设置高度没有反应
          );
  }

  @override
  Widget build(BuildContext context) {    
    return GridView.builder(
        //注意
        gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisSpacing:10.0 ,   //水平子 Widget 之间间距
          mainAxisSpacing: 10.0,    //垂直子 Widget 之间间距          
          crossAxisCount: 2,  //一行的 Widget 数量
        ),
        itemCount: listData.length,
        itemBuilder:this._getListData,
    );
  }
}

Padding()组件

有些元素没有padding时,可以外层包裹一层Padding()组件

有两个参数padding: EdgeInsets.fromLTRB(left, top, right, bottom),child: null,必写。

属性说明
paddingpadding 值, EdgeInsetss 设置填充的值
child子组件
Widget build(BuildContext context) {
    return Padding(
      padding:EdgeInsets.fromLTRB(0, 0, 10, 0),
      child: GridView.count(
        crossAxisCount: 2, //一行数量
        childAspectRatio: 1.5,//高宽比例
        children: <Widget>[
            Padding(
              padding: EdgeInsets.fromLTRB(10, 10, 0, 0),
              child:  Image.network('https://www.itying.com/images/flutter/1.png',fit: BoxFit.cover),
            ),
             Padding(
              padding: EdgeInsets.fromLTRB(10, 10, 0, 0),
              child:  Image.network('https://www.itying.com/images/flutter/2.png',fit: BoxFit.cover),
            ),
             Padding(
              padding: EdgeInsets.fromLTRB(10, 10, 0, 0),
              child:  Image.network('https://www.itying.com/images/flutter/3.png',fit: BoxFit.cover),
            )
        ],
      ),

    );
}

Row 水平布局组件

Row

属性说明
mainAxisAlignment主轴的排序方式
crossAxisAlignment次轴的排序方式
children组件子元素
return Row( //类型于flex布局 
    crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: <Widget>[
        Expanded(child: Text('Row 组件 1',textAlign: TextAlign.center,)),
        Expanded(child: Text('Row 组件 2',textAlign: TextAlign.center,)),
        Expanded(child: FittedBox(
          fit:BoxFit.contain,
          child:const FlutterLogo(),
        ))
    ],
);

Column 垂直布局组件

Column

属性说明
mainAxisAlignment主轴的排序方式 (MainAxisAlignment.spaceEvenly,MainAxisAlignment.center)
crossAxisAlignment次轴的排序方式
children组件子元素
return Container( height: 700,
    width: 500,
    color: Colors.black26, 
    child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
        children: <Widget>[
            IconContainer(Icons.home,color:Colors.red), IconContainer(Icons.search,color:Colors.blue), IconContainer(Icons.send,color:Colors.orange),
        ],
    ),
)

Expanded 类似 Web 中的 Flex 布局

属性说明
flex元素站整个父 Row /Column 的比例
child子元素

Expanded_1

Expanded_2

间距 SizedBox(height:10,width)

2020.03.04

Stack 层叠组件

属性说明
alignment配置所有子元素的显示位置 alignment: Alignment.center,
children子组件
Widget build(BuildContext context) {
    return Stack( 
        alignment: Alignment.center,
        //alignment: Alignment.topCenter,
        //alignment: Alignment(0,1),//自定义指定方位(x,y) BottomCenter
        children: <Widget>[ //Stack中children的顺序也会导致层叠
          Container(
            width:200,
            height:300,
            color:Colors.red,
          ),
          Text(
            '我是文本',
            style: TextStyle(
              fontSize:30,
              color: Colors.white
            ),
          ),
          
        ],
    );
  }

多个组件需要定位时,可以使用Stack 结合 Align 或者 Positioned 实现定位布局.

Align 组件

Stack 组件中结合 Align 组件可以控制每个子元素的显示位置

属性说明
alignment配置所有子元素的显示位置 alignment: Alignment.center
children子组件

Positioned组件

Stack 组件中结合 Positioned 组件也可以控制每个子元素的显示位置

属性说明
top子元素距离顶部的距离
bottom子元素距离底部的距离
left子元素距离左侧距离
right子元素距离右侧距离
child子组件
 Widget build(BuildContext context) {
    return Center(
      child:Container(
        width:300,
        height:400,
        color:Colors.red,
        child: Stack(
          children: <Widget>[
            Align(
              alignment: Alignment.center,
              child: Icon(Icons.home,color:Colors.white),
            ),
            Align(
              alignment: Alignment(0.5,0.5),
              child: Icon(Icons.search,color:Colors.white),
            ),
            Positioned(
              top: 20,
              left: 20,
              child:  Icon(Icons.save,color:Colors.white)
            )

          ],
        ),
       ),
    );
}

AspectRatio、Card 卡片组件

AspectRatio组件,设置图片的宽高比例

属性说明
aspectRatio宽高比(20/9)
children子组件

Card卡片组件

属性说明
margin外边距 EdgeInsets.all(20)
children子组件
ShapeCard 的阴影效果,默认的阴影效果为圆角的 长方形边。
class HomeContent extends StatelessWidget {
  
  List<Widget> _getData(){
    var tempList = listData.map((value){
        return Card(
          margin: EdgeInsets.all(20),
          child: Column(
            children: <Widget>[
              AspectRatio(
                aspectRatio: 20/9, //宽高比
                child: Image.network(value['imageUrl'],fit: BoxFit.cover,),
              ),
              ListTile(
                // leading: Image.network('https://www.itying.com/images/flutter/2.png',fit: BoxFit.cover,),
                leading:CircleAvatar(
                  backgroundImage:NetworkImage(value['imageUrl'])
                ),

                title: Text(value['title']),
                subtitle: Text(value['description'],maxLines: 2,overflow:TextOverflow.ellipsis),
              ),
            ],
            
          ),
        );
    });
    return tempList.toList();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: this._getData(),  
    
    );
  }
}

RaisedButton 定义一个按钮

class MyButton extends StatelessWidget {
  final String text;
  const MyButton(this.text,{Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return RaisedButton(
      child: Text(this.text),
      textColor:Theme.of(context).accentColor,
      color:Colors.red,
      onPressed: (){}
    );
  }
}

wrap组件实现流布局,自动换行

属性说明应用
direction主轴的方向,默认水平direction:Axis.vertical/Axis.horizontal
alignment主轴的对其方式alignment:WrapAlignment.start
spacing主轴方向上的间距spacing:10
runAlignmentrun 的对齐方式。run 可以理解为新的行或者 列,如果是水平方向布局的话,run 可以理解 为新的一行runAlignment: WrapAlignment.spaceAround
runSpacingrun 的间距runSpacing:10
textDirection文本方向
verticalDirection定义了 children 摆放顺序,默认是 down,见 Flex 相关属性介绍。

StateLessWidget 无状态组件

StatefulWidget 有状态组件

  • StatelessWidget 是无状态组件,状态不可变的 widget;
  • StatefulWidget 是有状态组件,持有的状态可能在 widget 生命周期改变。通俗的讲:如果我 们想改变页面中的数据的话这个时候就需要用到 StatefulWidget

页面上绑定数据、改变页面数据

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  int count = 1;
  List list = new List();

  get textDirection => null;

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
         RaisedButton(
          child: Text('按钮'),
          onPressed: (){
            setState(() {
              this.list.add('新增数据${this.count++}');
            });
          }
        ),
        RaisedButton(
          child: Text('清空'),
          onPressed: (){
            setState(() {
              this.list.clear();
              this.count = 1;
            });
          }
        ),
        SizedBox(
          height:20,
        ),
        Column(
          children:this.list.map((value){
            return  Padding(padding: EdgeInsets.all(10),
              child:Text(value,style: TextStyle(fontSize: 20))
            );
          }).toList(),
        ), 
      ],
    );
  }
}

2020.03.05

BottomNavigationBar 组件

BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,bottomNavigationBar 是 Scaffold 组件的参数。

属性说明
itemsList<BottomNavigationBarItem> 底 部 导 航 条按钮集合
iconSizeicon大小
currentIndex默认选中第几个
fixedColor选中的颜色
typeBottomNavigationBarType.fixed BottomNavigationBarType.shifting
onTap选中变化回调函数

底部导航就会涉及到页面切换,所以需要代码抽离,如下图:在Tabs.dart中设置。

底部导航


import 'package:flutter/material.dart';
import './tabs/HomePage.dart';
import './tabs/CategoryPage.dart';
import './tabs/SettingsPage.dart';

class HomeTabs extends StatefulWidget {
  HomeTabs({Key key}) : super(key: key);

  @override
  _HomeTabsState createState() => _HomeTabsState();
}

class _HomeTabsState extends State<HomeTabs> {

  int _currentIndex = 0;
  List _pageList=[
    HomePage(),
    CategoryPage(),
    SettingsPage()
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('Fultter demo')),
        body: this._pageList[this._currentIndex],
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: this._currentIndex,     //配置的索引值选中
          iconSize: 30.0,                       //icon大小
          fixedColor: Colors.red,               //选中的颜色
          type: BottomNavigationBarType.fixed,  //shifting默认 要设置固定fixed
          onTap:(int index){                    //此处需要改变state值,需要放到有状态组件中
            setState(() {
              this._currentIndex = index;
            });
          },
          items: [                              //底 部 导 航 条按钮集合
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text('首页')
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.category),
              title: Text('分类')
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.settings),
              title: Text('设置')
            )
          ]
        ),
      );
  }
}

2020.03.06

路由

普通路由Navigator.push 和 Navigator.pop

  1. 跳转
  2. 跳转传值
 Center(
  child: RaisedButton(
    child: Text('跳转到查询页面'),
    onPressed: (){
      Navigator.of(context).push(
        MaterialPageRoute(
           builder: (context)=>SearchPage(title:'传值查询') //传值
        ) 
      );
    },
    color: Theme.of(context).accentColor, 
    textTheme: ButtonTextTheme.primary
  ),
)

命名路由Navigator.pushNamed(context, '/form');

1. 在MaterialApp中配置routes,跳转Navigator.pushNamed(context, '/form');

return MaterialApp(
    home: HomeTabs(),
    routes: {
        '/search':(context)=>SearchPage(),
        '/form':(context)=>FormPage(),
    },
    theme: ThemeData(primarySwatch: Colors.yellow),
);

RaisedButton(
    child: Text('命名路由跳转/传值'),
    onPressed: (){
      Navigator.pushNamed(context, '/form');
    },
    color: Theme.of(context).accentColor, 
    textTheme: ButtonTextTheme.primary
),

2. 抽离路由配置并传值

(1) 新建Routes.dart文件

import 'package:flutter/material.dart';

import '../pages/Search.dart';
import '../pages/Form.dart';

//配置路由
final routes={
      '/search':(context)=>SearchPage(),
      '/form':(context,{arguments})=>FormPage(arguments:arguments),
};

//固定写法
var onGenerateRoute=(RouteSettings settings) {
      // 统一处理
      final String name = settings.name; 
      final Function pageContentBuilder = routes[name];
      if (pageContentBuilder != null) {
        if (settings.arguments != null) {
          final Route route = MaterialPageRoute(
              builder: (context) =>
                  pageContentBuilder(context, arguments: settings.arguments));
          return route;
        }else{
            final Route route = MaterialPageRoute(
              builder: (context) =>
                  pageContentBuilder(context));
            return route;
        }
      }
};

(2) main.dart引入

import 'package:flutter/material.dart';
import './pages/Tabs.dart';

import './routes/Routes.dart';

void main() => runApp(MyApp());

//自定义组件
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeTabs(),
      initialRoute: '/',     //初始化的时候加载的路由
      onGenerateRoute:onGenerateRoute,//监听路由
      theme: ThemeData(primarySwatch: Colors.yellow),
    );
  }
}

(3) Home.dart引用传值

RaisedButton(
    child: Text('命名路由跳转/传值'),
    onPressed: (){
      Navigator.pushNamed(context, '/form',arguments:{
        'id':1212
      });
    },
    color: Theme.of(context).accentColor, 
    textTheme: ButtonTextTheme.primary
),

(4) From.dart接收传值

StatelessWidget无状态组件中接收值:

class FormPage extends StatelessWidget {

   final arguments;
   FormPage({this.arguments});//构造函数

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('表单页面')),
      body:Container(
        child:  Text("表单页面${arguments != null ? arguments['id'] : '0'}"),
      )
    );
  }
}
StatefulWidget有状态组件中接收值:
class FormPage extends StatefulWidget {

  final arguments;
  FormPage({this.arguments});//构造函数

  @override
  _FormPageState createState() => _FormPageState(this.arguments);
}

class _FormPageState extends State<FormPage> {

  var arguments;

  _FormPageState(arguments){
    this.arguments = arguments;
  }//构造函数

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('表单页面')),
      body:Container(
        child: Text("表单页面${arguments != null ? arguments['id'] : '0'}"),
      )
    );
  }
}

返回到上一级页面

 Navigator.of(context).pop();

下一步

 Navigator.pushNamed(context, '/registerSecond');

路由替换

Navigator.of(context).pushReplacementNamed('/registerSecond');

返回根路由

Navigator.of(context).pushAndRemoveUntil(
  new MaterialPageRoute(builder: (context) => new Tabs()),                  
   (route) => route == null
);

指定返回哪个根路由:

Navigator.of(context).pushAndRemoveUntil(
  new MaterialPageRoute(builder: (context) => new Tabs(index:1)),                  
   (route) => route == null
);
Tabs.dart接收index参数:
import 'package:flutter/material.dart';
import './tabs/HomePage.dart';
import './tabs/CategoryPage.dart';
import './tabs/SettingsPage.dart';

class Tabs extends StatefulWidget {

  final index ;
  
  Tabs({this.index = 0 });

  @override
  _TabsState createState() => _TabsState(this.index);
}

class _TabsState extends State<Tabs> {


  int _currentIndex;
  List _pageList=[
    HomePage(),
    CategoryPage(),
    SettingsPage()
  ];
 
  _TabsState(index){
    this._currentIndex = index;
  }

  List _titleList=[
    '首页','分类','设置'
  ];
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(this._titleList[this._currentIndex])),
        body: this._pageList[this._currentIndex],
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: this._currentIndex,     //配置的索引值选中
          iconSize: 30.0,                       //icon大小
          fixedColor: Colors.red,               //选中的颜色
          type: BottomNavigationBarType.fixed,  //shifting默认 要设置固定fixed
          onTap:(int index){                    //此处需要改变state值,需要放到有状态组件中
            setState(() {
              this._currentIndex = index;
            });
          },
          items: [                              //底 部 导 航 条按钮集合
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text('首页')
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.category),
              title: Text('分类')
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.settings),
              title: Text('设置')
            )
          ]
        ),
      );
  }
}

AppBar组件

自定义顶部样式

属性描述
leading在标题前面显示的一个控件,在首页通常显示应用 的 logo;在其他界面通常显示为返回按钮
title标题,通常显示为当前界面的标题文字,可以放组 件
actions通常使用 IconButton 来表示,可以放按钮组
bottom通常放 tabBar,标题下面显示一个 Tab 导航栏
backgroundColor导航背景颜色
iconTheme图标样式
textTheme文字样式
centerTitle标题是否居中显示
Widget build(BuildContext context) {
    return Scaffold(
      appBar:AppBar(
        title: Text('AppBarPage',style:TextStyle(color:Colors.white)),
        backgroundColor: Colors.blue,
        // leading: Icon(Icons.menu,color: Colors.white),
        leading: IconButton( //在首页通常显示应用 的 logo;在其他界面通常显示为返回按钮
            icon: Icon(Icons.menu,color: Colors.white), 
            onPressed: (){
              print('menu');
            }
        ),
        actions: <Widget>[//按钮组
           IconButton(
              icon: Icon(Icons.search,color: Colors.white), 
              onPressed: (){
                print('search');
              }
           ),
            IconButton(
              icon: Icon(Icons.settings,color: Colors.white), 
              onPressed: (){
                print('settings');
              }
           ),
        ],
        centerTitle:true,//始终居中显示
      ),
      body: Container(
       child: Text('appbar'),
      ),
    );
  }

自定义 TabBar 实现顶部 Tab 切换

TabBar 常见属性:

属性描述
tabs显示的标签内容,一般使用 Tab 对象,也可以是其他 的 Widget
controllerTabController 对象
isScrollable是否可滚动
indicatorColor指示器颜色
indicatorWeight指示器高度
indicatorPadding底部指示器的 Padding
indicator指示器 decoration,例如边框等
indicatorSize指示器大小计算方式,TabBarIndicatorSize.label 跟文 字等宽,TabBarIndicatorSize.tab 跟每个 tab 等宽
labelColor选中 label 颜色
labelStyle选中 label 的 Style
labelPadding每个 label 的 padding 值
unselectedLabelColor未选中 label 颜色
unselectedLabelStyle未选中 label 的 Style
class _AppBarPageState extends State<AppBarPage> {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2, //必须配置
      child: Scaffold(
        appBar:AppBar(
          title: Text('AppBarPage',style:TextStyle(color:Colors.white)),
          backgroundColor: Colors.blue,
          // leading: Icon(Icons.menu,color: Colors.white),
          leading: IconButton( //在首页通常显示应用 的 logo;在其他界面通常显示为返回按钮
              icon: Icon(Icons.menu,color: Colors.white), 
              onPressed: (){
                print('menu');
              }
          ),
          // actions: <Widget>[//按钮组
          //   IconButton(
          //       icon: Icon(Icons.search,color: Colors.white), 
          //       onPressed: (){
          //         print('search');
          //       }
          //   ),
          //     IconButton(
          //       icon: Icon(Icons.settings,color: Colors.white), 
          //       onPressed: (){
          //         print('settings');
          //       }
          //   ),
          // ],
          centerTitle:true,//始终居中显示
          bottom: TabBar(
            indicatorColor:Colors.orange,
            labelColor:Colors.white,
            indicatorSize:TabBarIndicatorSize.label,
            tabs: <Widget>[
              Tab(text:'热门'),
              Tab(text:'推荐'),
            ],
          ),
        ),
        body: TabBarView(children: <Widget>[
            ListView(children: <Widget>[
              ListTile(
                title:Text('第一个tab')
              ),
              ListTile(
                title:Text('第一个tab')
              ),
              ListTile(
                title:Text('第一个tab')
              ),

            ],
           ),
            ListView(children: <Widget>[
                ListTile(
                  title:Text('第二个tab')
                ),
                ListTile(
                  title:Text('第二个tab')
                ),
                ListTile(
                  title:Text('第二个tab')
                ),
              ],
           ),
          ]
        ),
      ),
    );
  }
}

TabBar 放在导航最顶部

  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 4, 
      child:Scaffold(
        appBar:AppBar(
          title: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Expanded(
                flex:1,
                child: TabBar(//因为 ategoryPage外层也有一层Scaffold,所以用title取代bottom 
                indicatorColor:Colors.red,
                // labelColor:Colors.white,
                indicatorSize:TabBarIndicatorSize.label,
                tabs: <Widget>[
                  Tab(text:'热门'),
                  Tab(text:'推荐'),
                  Tab(text:'热销'),
                  Tab(text:'优惠'),
                ],
              )
            )
          ]),
        ),
        body: TabBarView(children: <Widget>[])
    )
}

TabController实现Tabs切换

AppBar 中自定义 TabBar 实 现 Tabs 的另一种方法。

import 'package:flutter/material.dart';

class TabBarControllerPage extends StatefulWidget {
  TabBarControllerPage({Key key}) : super(key: key);

  @override
  _TabBarControllerPageState createState() => _TabBarControllerPageState();
}

//1 添加 with SingleTickerProviderStateMixin
class _TabBarControllerPageState extends State<TabBarControllerPage> with SingleTickerProviderStateMixin{

  //2 定义_tabController
  TabController _tabController;

  //3 初始化
  @override
  void initState(){ //生命周期函数
    super.initState();
    _tabController = new TabController(vsync: this,length: 2);

    _tabController.addListener((){//6 监听tab切换事件
      print(_tabController.index);
    });
  }

   @override
   void dispose(){ //销毁的生命周期
     super.dispose();
     _tabController.dispose(); //销毁
   }
   
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:AppBar(
        title:Text('TabBarController'),
        bottom: TabBar(
          controller: this._tabController,//4 在TabBar中配置controller
          tabs: <Widget>[
            Tab(text:'热销'),
            Tab(text:'推荐')
          ],
        ),
      ),
      body:TabBarView(
        controller: this._tabController,//5 在TabBarView中配置controller
        children: <Widget>[
          Center(child:Text('热销')),
          Center(child:Text('推荐')),
        ],
      )
    );
  }
}

Drawer抽屉组件

Drawer 侧边栏

return Scaffold(
    appBar: AppBar(
        title: Text("Flutter App"), ),
    drawer: Drawer(
        child: Text('左侧边栏'),
    ),
    endDrawer: Drawer(
        child: Text('右侧侧边栏'), 
    ),
);

DrawerHeader头部

属性描述
decoration设置顶部背景颜色
child配置子元素
padding内边距
margin外边距

UserAccountsDrawerHeader用户信息头部

属性描述
decoration设置顶部背景颜色
accountName账户名称
accountEmail账户邮箱
currentAccountPicture用户头像
otherAccountsPictures用来设置当前账户其他账户头像
margin外边距

侧边栏路由跳转

onTap: (){ 
    Navigator.of(context).pop();
    Navigator.pushNamed(context, '/search'); 
}
Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(this._titleList[this._currentIndex])),
      body: this._pageList[this._currentIndex],
      drawer: Drawer(//抽屉Text('左侧抽屉栏')
        child: Column(
          children: <Widget>[
            Row(
              children: <Widget>[
                Expanded(
                  // child: DrawerHeader(
                  //   child: Text('你好,flutter'),
                  //   decoration: BoxDecoration(
                  //       color: Colors.yellow,
                  //       image: DecorationImage(
                  //           image: NetworkImage(
                  //               'https://www.itying.com/images/flutter/2.png'),
                  //           fit: BoxFit.cover)),
                  // ),

                  child: UserAccountsDrawerHeader(
                    accountName: Text('苗苗'), 
                    accountEmail: Text('miaomiao@123.com'), 
                    currentAccountPicture: CircleAvatar(
                      backgroundImage: NetworkImage('https://www.itying.com/images/flutter/4.png'),
                    ),
                    decoration: BoxDecoration( //背景图片
                        image: DecorationImage(
                            image: NetworkImage( 'https://www.itying.com/images/flutter/2.png'), fit: BoxFit.cover)
                    ),
                  ),
                )
              ],
            ),
            
            ListTile(
                leading: CircleAvatar(child: Icon(Icons.home)),
                title: Text('我的空间'),
                onTap: (){
                  Navigator.of(context).pop();//隐藏侧边栏
                  Navigator.pushNamed(context, '/login');
                },
            ),
            Divider(),
            ListTile(
                leading: CircleAvatar(child: Icon(Icons.phone)),
                title: Text('用户中心')),
            Divider(),
            ListTile(
                leading: CircleAvatar(child: Icon(Icons.settings)),
                title: Text('设置中心'))
          ],
        ),
      ),
      endDrawer: Drawer(child: Text('右侧抽屉栏')),
    );
  }

2020.03.09

按钮组件

常见的按钮组件有:RaisedButton、FlatButton、IconButton、OutlineButton、ButtonBar、FloatingActionButton 等。

  • RaisedButton :凸起的按钮,其实就是 Material Design 风格的 Button
  • FlatButton :扁平化的按钮
  • OutlineButton:线框按钮
  • IconButton :图标按钮
  • ButtonBar:按钮组 FloatingActionButton:浮动按钮
属性名称值类型属性值
onPressedVoidCallback ,一般接收一个 方法必填参数,按下按钮时触发的回调,接收一个 方法,传 null 表示按钮禁用,会显示禁用相关 样式
childWidget文本控件
textColorColor文本颜色
colorColor按钮的颜色
disabledColorColor按钮禁用时的颜色
disabledTextColorColor按钮禁用时的文本颜色
splashColorColor点击按钮时水波纹的颜色
highlightColorColor点击(长按)按钮后按钮的颜色
elevationdouble阴影的范围,值越大阴影范围越大
padding内边距
shape设置按钮的形状RoundedRectangleBorde(borderRadius:BorderRadius.circular(10),)
class _ButtonPageState extends State<ButtonPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('按钮组件')),
      body:Container(
        // padding: EdgeInsets.all(20),
        child:Column(children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
               Container(         //设置RaisedButton的高宽可以放置在Container中设置
                 width: 200,
                 height: 60,
                 child: RaisedButton(
                    child: Text('普通按钮'),
                    onPressed: (){
                      print('按钮');
                    },
                    textColor:Colors.orangeAccent,      //文本颜色
                    color:Colors.white,                 //按钮的颜色
                    // padding: EdgeInsets.fromLTRB(50, 10, 50, 10),//内边距
                    shape: RoundedRectangleBorder(            //设置按钮的形状
                      borderRadius:BorderRadius.circular(20)
                    ),
                    // shape: CircleBorder( //圆形
                    //   // side:BorderSide(color:Colors.red)
                    // ),
                    splashColor: Colors.blue,          //点击按钮时水波纹的颜色
                    highlightColor:Colors.red,        //点击(长按)按钮后按钮的颜色
                    elevation: 3.0,
                    // disabledColor:Colors.grey,           //按钮禁用时的颜色
                    // disabledTextColor:Colors.black,      //按钮禁用时的文本颜色
                  )
                ),
              ]),
              SizedBox(height: 50,),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Expanded( //
                    child: 
                      Container(         //设置RaisedButton的高宽可以放置在Container中设置
                        height: 60,
                        margin: EdgeInsets.all(20),
                        child: RaisedButton(
                            child: Text('全屏按钮--Expanded'),
                            color: Colors.blue,
                            textColor: Colors.white,
                            onPressed: (){
                              print('全屏按钮');
                            },
                          )
                      ),
                  )
              ]),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Expanded( //
                    child: 
                      Container(         //设置RaisedButton的高宽可以放置在Container中设置
                        height: 60,
                        margin: EdgeInsets.all(20),
                        child: FlatButton(
                            child: Text('扁平化按钮,无阴影'),
                            color: Colors.blue,
                            textColor: Colors.white,
                            onPressed: (){
                            },
                          )
                      ),
                  )
              ]),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Expanded( //
                    child: 
                      Container(        
                          child:ButtonBar(children: <Widget>[
                            Icon(Icons.home),
                            Icon(Icons.people),
                            Icon(Icons.wallpaper),
                            Icon(Icons.query_builder),
                          ],
                          alignment: MainAxisAlignment.spaceAround,
                          mainAxisSize:MainAxisSize.max,
                          buttonPadding: EdgeInsets.all(30),
                       )
                      ),
                  )
              ]),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Expanded( //
                    child: 
                      Container(         //设置RaisedButton的高宽可以放置在Container中设置
                        height: 60,
                        margin: EdgeInsets.all(20),
                        child: OutlineButton(
                            child: Text('线框按钮'),
                            onPressed: (){
                            },
                          )
                      ),
                  )
              ]),

        ],)
      ),
      //浮动按钮
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add,color: Colors.yellow,size: 44,),
        onPressed: (){},
        backgroundColor: Colors.red,
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

自定义按钮组件

FloatingActionButton浮动按钮组件

属性名称属性值
child子视图,一般为 Icon,不推荐使用文字
tooltipFAB 被长按时显示,也是无障碍功能
backgroundColor背景颜色
elevation未点击的时候的阴影
hignlightElevation点击时阴影值,默认 12.0
onPressed点击事件回调
shape可以定义 FAB 的形状等
mini是否是 mini 类型默认 false

FloatingActionButton简称FAB ,可以实现浮动按钮,也可以实现类似闲鱼app的地步凸 起导航

  • 浮动按钮:floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
  • 实现闲鱼 app 底部凸起按钮

Scaffold()里实现

//floatingActionButton的位置
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, 
//FloatingActionButton 实现闲鱼 app 底部凸起按钮
floatingActionButton:Container(
    width: 60,
    height: 60,
    // padding: EdgeInsets.all(10),
    margin: EdgeInsets.only(top:15),
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(40),
      color: Colors.red,
    ),
    // color: Colors.red,
    child: FloatingActionButton(
      child: Icon(Icons.add,size: 44,),
      backgroundColor: this._currentIndex == 1 ? Colors.red :Colors.blue,//背景颜色
      elevation: 0.0, //未点击的时候的阴影
      highlightElevation: 12.0 ,//点击时阴影值,默认 12.0
      onPressed: (){//点击事件回调
        print('FloatingActionButton');
        setState(() { 
          this._currentIndex = 1;
        });
      },
      // tooltip:'9900' ,//FAB 被长按时显示,也是无障碍功能
      // shape:RoundedRectangleBorder( //可以定义 FAB 的形状等
      //      borderRadius: BorderRadius.circular(10), //自定义
      // ),
      // shape: CircleBorder( //圆形
      //   side: BorderSide(
      //       color: Colors.white,
      //   )
      // ),
),

tooltip长按效果:

tooltip长按效果

宽度自适应:width:double.infinity 宽度自适应

表单

TextField 单行文本框,TextField 多行文本框

属性描述
maxLines设置此参数可以把文本框改为多行文本框
onChanged文本框改变的时候触发的事件
decorationhintText:类似 html 中的 placeholder;
-border:配置文本框边框 OutlineInputBorder 配合使用
-labelText :lable 的名称
-labelStyle:配置 lable 的样式
obscureText把文本框框改为密码框
controllercontroller 结合 TextEditingController()可以配置表单默认显示的内容

CheckBox、CheckboxListTile多选框组件

Radio、RadioListTile单选框组件

Switch、SwitchListTile

Checkbox ,Radio,Switch常见属性:

属性描述
valueCheckbox(true 或者 false);Radio(0/1);Switch(true 或者 false)
onChanged改变的时候触发的事件
activeColor选中的颜色、背景颜色
checkColor选中的颜色、Checkbox 里面对号的颜色

CheckboxListTile 常见属性:

属性描述
valuetrue 或者 false
onChanged改变的时候触发的事件
activeColor选中的颜色、背景颜色
title标题
subtitle二级标题
secondary配置图标或者图片
selected选中的时候文字颜色是否跟着改变

表单

学习暂且告一段落~