写点什么

Flutter 学习之认知基础组件,android 手机开发教程

用户头像
Android架构
关注
发布于: 刚刚

alignment: Alignment.center,//Text 控件 child: new Text(//Dart 语法中 ?? 表示如果 text 为空,就会返回??号的内容 text ?? "没改变数值",textDirection: TextDirection.ltr,//需要加上这句不然报 RichText widgets require a Directionality widget ancestor.),


);}}


上面例子可以知道知道:在State可以动态更改数据,在调用setState后,改变的数据会除法Widget重新构建,上面代码还写了三个生命周期方法,这里简单说一下:


  • initState:初始化操作

  • didChangeDependencies:在initState之后调用,可以获取其他State

  • dispose:销毁


平时开发中在build实现布局的摆放,把数据添加Widget,通过setState改变数据。那如果很高频率取改变数据,性能肯定受影响,以下三点可以减少重新构建有状态控件的影响:


  1. 树根上尽量不用状态控件,因为如果数据有变化树根每次都更新,那就是整棵树都要重建,把状态用在树叶上,这样更新的时候只会更新自己。

  2. 减少build方法所创建的节点数量和控件数量。

  3. 利用缓存,如果子树中不更改,将子树中缓存起来,每次使用其子树时重新使用它,学会重用思想。

  4. 尽可能使用const修饰控件。 怎么去选择有状态和无状态,最简单就是可以跟用户进行交互应该使用StatefulWidget,例如:点击,滑动屏幕信息流数据更新,如果只是仅仅显示数据,那就可以选择使用StatelessWidget创建一个无状态控件。

三、Flutter 页面

Flutter 有显示的Widget和完整页面呈现的Widget,常见的有MaterialAppScaffoldAppbarTextImageFlatButton,下面以表格形式简单列一下:



下面一个个简单上例子介绍:

1.MaterialApp

import 'package:flutter/material.dart';//使用flutter/material.dart 目的是使用 Matrial 风格的小控件 void main(){//运行程序 runApp(MyApp());}


//用无状态控件显示 class MyApp extends StatelessWidget{


@overrideWidget build(BuildContext context){return MaterialApp(//标题 title:'Widget_Demo',//主题色 theme:ThemeData(//设置为蓝色 primarySwatch: Colors.blue),//这是一个 Widget 对象,用来定义当前应用打开的时候,所显示的界面 home:MyHomePage(),);}}


class MyHomePage extends StatelessWidget{


@overrideWidget build(BuildContext context){return Scaffold(//设置 appbarappBar:new AppBar(title:new Text('This is a Demo'),),//主体 body:new Center(//在屏幕中央显示一个文本 child:new Text('Hello'),),);}}


效果如下图:



上面可以看到MaterialApp作为了主界面入口。

2.Scaffold

上面例子home:MyHomePage()这里返回了ScaffoldWidget,而这个Widget正是我们所看到的页面,看到Scaffold包含了appBarbody,一开始说到,Scaffold也包含Drawers,下面实现一下:


@overrideWidget build(BuildContext context){return Scaffold(//设置 appbarappBar:new AppBar(title:new Text('This is a Demo'),),//主体 body:new Center(//在屏幕中央显示一个文本 child:new Text('Hello'),),//左侧抽屉 drawer:Drawer(//添加一个空的 ListViewchild:ListView(),),);}


效果如下:



下面往抽屉里添加点东西,就添加ListView,代码如下:


//左侧抽屉 drawer:Drawer(child:ListView(//设置 paddingpadding:EdgeInsets.zero,children: <Widget>[//据说这里可以替换自定义的 header//userHeader,ListTile(//标题内容 title: Text("This is Item_one"),//前置图标 leading: new CircleAvatar(child:new Icon(Icons.scanner),),),ListTile(//标题内容 title: Text("This is Item_two"),//前置图标 leading: new CircleAvatar(child:new Icon(Icons.list),),),ListTile(//标题内容 title: Text("This is Item_three"),//前置图标 leading: new CircleAvatar(child:new Icon(Icons.score),),),],),),


运行效果就是抽屉里加了三行内容的ListView

3.AppBar

下面设置一些AppBar属性,玩玩:


//设置 appbarappBar: new AppBar(//AppBar 内容显示 title: new Text('This is a Demo'),//前置图标 leading: new Icon(Icons.home),//背景颜色 改为红色 backgroundColor: Colors.red,//设置为标题内容居中 centerTitle: true,//一个 Widget 列表,代表 Toolbar 中所显示的菜单,// 对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单 actions: <Widget>[//IconButtonnew IconButton(//图标 icon: new Icon(Icons.add_a_photo),//提示 tooltip: 'Add photo',//点击事件 onPressed: () {},),//菜单弹出按钮 new PopupMenuButton<String>(itemBuilder: (BuildContext context) {return <PopupMenuItem<String>>[new PopupMenuItem<String>(value: "one", child: new Text('This one')),new PopupMenuItem<String>(value: "two", child: new Text('This two')),];},//选择点击事件 onSelected: (String action) {switch (action) {case "one"://增加点击逻辑 break;case "two"://增加点击逻辑 break;}},),],),


效果如下:



可以看到,上面Appbar上加了前置图标、拍照图标、菜单弹出按钮、阴影。

4.Text

下面用Text来展示文本,把上面例子用文本显示中间的Hello单独抽出来,如下:


//主体 body: new Center(//在屏幕中央显示一个文本 改为自定义样式 child: new CustomTextStyle('This is a Text'),),


//单独文本样式 class CustomTextStyle extends StatelessWidget{String text;//构造函数 参数外部传进来 CustomTextStyle(this.text);@overrideWidget build(BuildContext context){return Text(text ?? "Hello");


}}


下面把文本字体大小修改,字体样式修改,背景颜色改改:


//文本 : 单独文本样式 class CustomTextStyle extends StatelessWidget {Paint pg = Paint();String text;


//构造函数 参数外部传进来 CustomTextStyle(this.text);


@overrideWidget build(BuildContext context) {//设置画笔颜色为黑色 pg.color = Color(0xFF000000);return Text(text ?? "Hello",style: TextStyle(//颜色 color: Colors.blue,//字体大小 fontSize: 14,//字体加粗 fontWeight: FontWeight.bold,//文本背景颜色 background: pg),);}}


上面效果是:



还有很多的属性,根据需要去设置就行:


const TextStyle({this.inherit = true,this.color,//文本样式 this.fontSize,//字体大小 this.fontWeight,//绘制文本时的字体粗细 this.fontStyle,//字体变体 this.letterSpacing,//水平字母之间的空间间隔(逻辑像素为单位),可以负值 this.wordSpacing,//单词之间添加的空间间隔(逻辑像素为单位),可以负值 this.textBaseline,//对齐文本的水平线 this.height,//文本行与行的高度,作为字体代销的倍数 this.locale,//用于选择区域定字形的语言环境 this.foreground,//文本的前景色,不能与 color 共同设置 this.background,//文本背景色 this.shadows,//Flutter Decoration 背景设定(边框,圆角,阴影,渐变等)this.decoration,//绘制文本装饰,添加上下划线,删除线 this.decorationColor,//文本装饰的颜色 this.decorationStyle,//文本装饰的样式,控制画虚线,点,波浪线 this.debugLabel,String fontFamily,//使用字体的名称 String package,})

5.RichText

这是显示丰富样式的文本,这什么意思呢?Text只能显示一种样式的文字,如果想在一段文字中显示多种样式,就好像Android里面的SpannableString,就需要使用RichText,直接上例子:


//富文本样式 class RichWidget extends StatelessWidget {@overrideWidget build(BuildContext context) {return RichText(text: TextSpan(text: 'This is RichText',style: new TextStyle(//false 的时候不显示 inherit: true,//字体大小 fontSize: 16,//黑色 color: Colors.black),children: <TextSpan>[new TextSpan(text: 'Android 艺术探索',style: new TextStyle(color: Colors.redAccent,//字体粗细 fontWeight: FontWeight.bold,),


),


new TextSpan(text: '第一行代码'),new TextSpan(text: 'Android 进阶之光',style: new TextStyle(color: Colors.indigo,//字体样式 fontSize: 20,),)],));}}


//屏幕中间改为富文本 widget//主体 body: new Center(//Text 在屏幕中央显示一个文本 改为自定义样式//child: new CustomTextStyle('This is a Text'),//富文本 child:new RichWidget()),


效果如下:


6.TextField

下面看看文本输入框,文本输入框平时会经常用到:


body: new Center(//Text 在屏幕中央显示一个文本 改为自定义样式//child: new CustomTextStyle('This is a Text'),//富文本//child:new RichWidget()//文本输入框 child:new TextFieldWidget()),


//文本输入框 class TextFieldWidget extends StatelessWidget{@overrideWidget build(BuildContext context){return TextField();}}


上面例子只能输入文本内容,如果想要获取输入框内容,就要添加一个controller,通过这个controller添加通知来获取TextField的值,我们一般点击按钮或者需要跟后台交互就要读取controller.text的值:


class MyHomePage extends StatelessWidget {//获取 TextEditingControllerfinal editController = TextEditingController();//IconButtonnew IconButton(//图标 icon: new Icon(Icons.add_a_photo),//提示 tooltip: 'Add photo',//点击事件 onPressed: () {//输出 print('text inputted: {editController.text}',toastLength: Toast.LENGTH_SHORT,gravity: ToastGravity.CENTER,timeInSecForIos: 1,);},),....//主体 body: new Center(//Text 在屏幕中央显示一个文本 改为自定义样式//child: new CustomTextStyle('This is a Text'),


//富文本//child:new RichWidget()


//文本输入框 以构造函数传递 controllerchild:new TextFieldWidget(editController)),}//文本输入框 class TextFieldWidget extends StatelessWidget{


final controller;//构造函数传值 TextFieldWidget(this.controller);@overrideWidget build(BuildContext context){return TextField(controller: controller,);}}


注意上面用到了ToastToast库这里很简单需要两步:


  1. pubspec.yaml添加依赖库fluttertoast: ^2.1.1

  2. 导入import 'package:fluttertoast/fluttertoast.dart';


重新运行即可,热重载可能会出现异常。运行在 iOS 模拟器需要装brewCocoaPods,有问题运行flutter doctor,它真是如名字一样,就是帮你诊断有没有错误信息,会显示具体信息。效果如下:



下面改一下样式:


return TextField(controller: controller,//最大长度,右下角会显示一个输入数量的字符串 maxLength: 26,//最大行数 maxLines: 1,//是否自动更正 autocorrect: true,//是否自动对焦 autofocus: true,//设置密码 true:是密码 false:不是秘密 obscureText: true,//文本对齐样式 textAlign: TextAlign.center,


);


效果如下:


7.Image

Image很好理解就是在界面上区域显示一张图片,而这张图片的来源可以是:本地,网络,资源图片等。下面一一演示一下:

7.1.项目图片资源

首先新建一个资源目录:



pubspec.yaml中配置图片路径,来识别应用程序所需的 assets:



class MyHomePage extends StatelessWidget {//主体 body: new Center(.....//图片加载 child:new ImageWidget()),}//图片 class ImageWidget extends StatelessWidget{@overrideWidget build(BuildContext context){//项目资源图片 方式一 return Image(image: new AssetImage('images/Image_fluttericon.jpeg'),);//项目资源图片 方式二// return Image.asset('images/Image_fluttericon.jpeg');}}


效果如下:


7.2.网络图片加载

下面进行网络图片加载,也是很简单:


class MyHomePage extends StatelessWidget {//图片路径 String image_url = "https://ws1.sinaimg.cn/large/0065oQSqgy1fze94uew3jj30qo10cdka.jpg";//主体 body: new Center(.....//图片加载 child:new ImageWidget(image_url)),}//图片 class ImageWidget extends StatelessWidget{String image_url;ImageWidget(this.image_url);@overrideWidget build(BuildContext context){return Image.network(image_url);}}


效果如下:



下面用一个库来加载和缓存网络图像,也可以与占位符和错误小部件一起使用,在pubspec.yaml添加依赖cached_network_image: ^0.4.1+1,在Dart文件导入这个库import 'package:cached_network_image/cached_network_image.dart';


//图片 class ImageWidget extends StatelessWidget{


String image_url;ImageWidget(this.image_url);@overrideWidget build(BuildContext context){return new CachedNetworkImage(imageUrl: image_url,//占位符 placeholder: new CircularProgressIndicator(),//加载错误时显示的图片 errorWidget: new Icon(Icons.error),//宽高 width:200,height: 200,);}}


当图片还没加载出来的时候会显示占位符,当如果加载出错会显示errorWidget的图片。

7.3.声明分辨率相关的图片

另外 Flutter 可以为当前设备添加合适其分辨率的图像,其实对于 Android 原生来说,就是在不同分辨率目录下放置不同分辨率的图片,只不过 flutter 并不是创建drawable-xxdpi文件,而是创建以下文件夹:


.../logo.png.../Mx/logo.png.../Nx/logo.png


其中 M 和 N 是数字标识符,对应于其中包含的图像分辨率,它们指定不同素设备像比例的图片,主资源默认对应于 1.0 倍的分辨率图片。看下面例子:



在设备像素比率为 1.8 的设备上,images/2.0x/logo.png 将被选择。对于 2.7 的设备像素比率,images/3.0x/logo.png将被选择。如果未在 Image 控件上指定渲染图像的宽度和高度,以便它将占用与主资源相同的屏幕空间量(并不是相同的物理像素),只是分辨率更高。 也就是说,如果images/logo.png是 72px 乘 72px,那么images/3.0x/logo.png应该是 216px 乘 216px; 但如果未指定宽度和高度,它们都将渲染为 72 像素×72 像素(以逻辑像素为单位)。pubspec.yaml中 asset 部分中的每一项都应与实际文件相对应,但主资源项除外。当主资源缺少某个资源时,会按分辨率从低到的顺序去选择,也就是说 1.0x 中没有的话会在 2.0x 中找,2.0x 中还没有的话就在 3.0x 中找。


return Image(// 系统会根据分辨率自动选择不同大小的图片 image: AssetImage('images/logo.png'),// ...),

8.FlatButton

Flutter预先定义了一些按钮控件,如FlatButtonRaisedButtonOutlineButtonIconButton


  1. FlatButton:扁平化按钮,继承自MaterialButton

  2. RaisedButton:凸起按钮,继承自MaterialButton

  3. OutlineButton:带边框按钮,继承自MaterialButton

  4. IconButton:图标按钮,继承自StatelessWidget


下面看看FlatButton,其他的只是样式稍微不一样,大致用法一样。


//按钮 class FlatButtonWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return FlatButton(onPressed: (){Fluttertoast.showToast(msg:'你点击了 FlatButton',toastLength: Toast.LENGTH_SHORT,gravity: ToastGravity.CENTER,timeInSecForIos: 1,);},child: Text('FlatButton'),color: Colors.blue,//按钮背景色 textColor: Colors.white,//文字的颜色 onHighlightChanged: (bool b){//水波纹变化回调


},disabledColor: Colors.black,//按钮禁用时的显示的颜色 disabledTextColor: Colors.black38,//按钮被禁用的时候文字显示的颜色 splashColor: Colors.white,//水波纹的颜色);


}}


上面也设置了一些属性,效果图如下:


四、Flutter 布局

Flutter中拥有 30 多种预定义的布局widget,常用的有ContainerPaddingCenterFlexRowColumListViewGridView。用一个表格列出它们的特性和使用。



下面一一介绍简单用法:

1.Container

一个拥有绘制、定位、调整大小的widget,示意图如下:



下面直接上例子:


class MyHomePage extends StatelessWidget {....body:new ContainWidget(),...}//Container 布局 class ContainWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return Container(child:Text("My name is Knight"),color: Colors.indigo,width:200,//宽 height:200,//高 margin:EdgeInsets.fromLTRB(5,5,5,5),//设置外边距 padding:EdgeInsets.all(30),//内边距);}}


下面设置边框,添加圆角:


//Container 布局 class ContainWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return Container(....padding:EdgeInsets.all(30),//内边距 decoration: BoxDecoration(//设置边框//背景色 color:Colors.redAccent,//圆角 borderRadius: BorderRadius.circular(6),),);}}


运行效果如下:


![Contianer 圆角](https://user-gold-cdn.xitu.io/2019/2/9/168d2a2863ccd207?imageView2/0/w/1280/h/960/ign


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ore-error/1)

2.Padding

一个Widget,会给其子Widget添加指定的填充,示意图如下:



class MyHomePage extends StatelessWidget {....body: new PaddingWidget(),...}//Padding 布局 class PaddingWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return Padding(//设置左上右下内边距为 4,10,6,8padding:EdgeInsets.fromLTRB(4, 10, 6, 8),child: Text('My name is Knight'),);}}


效果图如下:



下面实现Container嵌套Padding:


//Container 嵌套 Paddingclass ContainPaddWidget extends StatelessWidget{@overrideWidget build(BuildContext context){return Container(width:200,//宽 height:200,//高 child: Padding(padding:EdgeInsets.fromLTRB(4, 10, 6, 8),child: Text("My name is Knight"),),decoration: BoxDecoration(//设置边框//背景色 color:Colors.redAccent,//圆角 borderRadius: BorderRadius.circular(6),),);}}


效果图如下:


3.Center

将其子widget居中显示在自身内部的widget,示意图:



//Centerclass CenterWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return Container(width:200,//宽 height:200,//高 child: Center(child: Text("My name is Knight"),),decoration: BoxDecoration(//设置边框//背景色 color:Colors.redAccent,//圆角 borderRadius: BorderRadius.circular(6),),);}}


运行效果如下:



Center作为Container的孩子,Text所以在布局的中间。

4.Stack

可以允许其子Widget简单的堆叠在一起,层叠布局,示意图:



下面直接上代码,把之前的布局全部用上试试:


class MyHomePage extends StatelessWidget {....body:new Center(child:new StackWidget()),...}//层叠布局 class StackWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return Stack(children: <Widget>[new Image.network('https://ws1.sinaimg.cn/large/0065oQSqgy1fze94uew3jj30qo10cdka.jpg',width:300.0,//宽 height:300.0,//高),new Opacity(opacity: 0.6,//不透明度 child:new Container(width:100.0,height:100.0,color:Colors.redAccent,),),new Opacity(opacity: 0.6,child:new Container(width: 200.0,height:200.0,color:Colors.indigo,),),],);}}


运行效果:



可以看到控件都按Stack左上角对齐,叠在一起,下面改一下显示位置:


//层叠布局 class StackWidget extends StatelessWidget{


@overrideWidget build(BuildContext context){return Stack(//Aliginment 的范围是[-1,1],中心是[0,0].注释有写//和 Android 一样,左移的取值是往 1 取,右移是往-1 取//这里注意,它是取 stack 里范围最大的布局为基准,下面是以 Container 为//基准对齐 alignment: new Alignment(-0.6, -0.6),...);}}


运行效果图:


5.Colum

在垂直方向上排列子Widget,示意图如下:



直接上代码:


class MyHomePage extends StatelessWidget {...body:new ColumnWidget(),....


}//Column 布局 class ColumnWidget extends StatelessWidget {@overrideWidget build(BuildContext context) {return Column(children: <Widget>[Container(color:Colors.blue,width: 50,height: 50,),Container(color:Colors.black,width:50,height:50,),Container(color:Colors.green,width:50,height:50,),],);}}


运行效果:



下面简单设置一下排列方式属性:


return Column(//设置垂直方向的对齐方式 mainAxisAlignment: MainAxisAlignment.spaceEvenly,...);


运行效果如下:



垂直方向(主轴上)属性:



  1. MainAxisAlignment.start 这是默认值:垂直方向顶部对齐

  2. MainAxisAlignment.end:垂直方向底部对齐

  3. MainAxisAlignment.center:垂直方向居中对齐

  4. MainAxisAlignment.spaceBetween:垂直方向平分剩余空间

  5. MainAxisAlignment.spaceAround:放置控件后,剩余空间平分成 n 份,n 是子widget的数量,然后把其中一份空间分成 2 份,放在第一个 child 的前面,和最后一个 child 的后面,也就是子widget的之前之后之间均匀分割空闲的一半空间

  6. MainAxisAlignment.spaceEvenly:放置控件后,把剩余空间平分 n+1 份,然后平分所有的空间,在子widget之前之后之间均匀的分割空闲的空间


下面列一下水平方向(交叉轴)的属性:



  1. CrossAxisAlignment.center 这是默认值,水平居中

  2. CrossAxisAlignment.end:水平方向右侧对齐

  3. CrossAxisAlignment.start:水平方向左侧对齐

  4. CrossAxisAlignment.stretch:水平方向拉伸子child填充满布局

  5. CrossAxisAlignment.baseline:和textBaseline一起使用

6.Row

在水平方向上排列子widget的列表,示意图:



直接上代码:


class MyHomePage extends StatelessWidget {....body:new RowWidget(),...}//Rowclass RowWidget extends StatelessWidget{@overrideWidget build(BuildContext context){return Row(children: <Widget>[Container(color:Colors.blue,width: 50.0,height:50.0,),Container(color:Colors.black,width:50.0,height:50.0,),Container(color:Colors.green,width:50.0,height:50.0,),],);}}


效果图:



下面简单设置一些属性,和Column没多大差别:


return Row(//把剩余空间平分 n+1 份,然后平分所有的空间 mainAxisAlignment: MainAxisAlignment.spaceEvenly,...);


效果图:



水平方向上(主轴上)属性:



  1. MainAxisAlignment.start 这是默认值,水平方向顶部对齐

  2. MainAxisAlignment.center:水平方向居中对齐

  3. MainAxisAlignment.end:水平方向底部对齐

  4. MainAxisAlignment.spaceBetween:水平方向上平分剩余空间

  5. MainAxisAlignment.spaceAround:放置控件后,剩余空间平分成 n 份,n 是子widget的数量,然后把其中一份空间分成 2 份,放在第一个 child 的前面,和最后一个 child 的后面,也就是子widget的之前之后之间均匀分割空闲的一半空间

  6. MainAxisAlignment.spaceEvenly:放置控件后,把剩余空间平分 n+1 份,然后平分所有的空间,在子widget之前之后之间均匀的分割空闲的空间 而交叉轴(垂直方向)的属性:



  1. CrossAxisAlignment.center 这是默认,垂直居中

  2. CrossAxisAlignment.end:垂直方向右侧对齐

  3. CrossAxisAlignment.start:垂直方向左侧对齐

  4. CrossAxisAlignment.stretch:垂直方向拉伸子child填充满布局

  5. CrossAxisAlignment.baseline:和textBaseline一起使用

7.Expanded

Expanded组件可以使RowColumnFiex等子组件在其主轴上方向展开并填充可用的空间,这里注意:Expanded组件必须用在RowColumnFiex内,并且从Expanded到封装它的RowColumnFlex的路径必须只包括StatelessWidgets或者StatefulWidgets(不能是其他类型的组件,像RenderObjectWidget,它是渲染对象,不再改变尺寸,因此Expanded不能放进RenderObjectWidget),示意图如下:



class MyHomePage extends StatelessWidget {....body:new RowWidget(),...}class RowWidget extends StatelessWidget{@overrideWidget build(BuildContext context){return Row(children: <Widget>[new RaisedButton(onPressed: (){


},color:Colors.green,child:new Text('绿色按钮 1')),new Expanded(child:new RaisedButton(onPressed: (){


},color:Colors.yellow,child:new Text('黄色按钮 2')),),new RaisedButton(onPressed:(){


},color:Colors.red,child:new Text('黑色按钮 3')),],);}}


运行效果如下:



class MyHomePage extends StatelessWidget {....

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Flutter学习之认知基础组件,android手机开发教程