10天学会flutter DAY7 flutter 玩转基础Widget

class Child extends StatefulWidget {

@override

_ChildState createState() => _ChildState();

}

class _ChildState extends State {

@override

Widget build(BuildContext context) {

debugPrint("child build......");

return Text('lifeCycle');

}

@override

void initState() {

super.initState();

debugPrint("child initState......");

}

///初始化时,在initState()之后立刻调用

///当依赖的InheritedWidget rebuild,会触发此接口被调用

@override

void didChangeDependencies() {

super.didChangeDependencies();

debugPrint("child didChangeDependencies......");

}

///父widget状态改变的时候会调用该方法,比如父节点调用了setState

@override

void didUpdateWidget(Child oldWidget) {

super.didUpdateWidget(oldWidget);

debugPrint("child didUpdateWidget......");

}

///当State对象从树中被移除时,会调用此回调

@override

void deactivate() {

super.deactivate();

debugPrint('child deactivate......');

}

///当State对象从树中被永久移除时调用;通常在此回调中释放资源

@override

void dispose() {

super.dispose();

debugPrint('child dispose......');

}

}




执行的输出结果显示为:



*   运行到显示



I/flutter (22218): parent initState…

I/flutter (22218): parent didChangeDependencies…

I/flutter (22218): parent build…

I/flutter (22218): child initState…

I/flutter (22218): child didChangeDependencies…

I/flutter (22218): child build…




*   点击按钮会移除Child



I/flutter (22218): parent build…

I/flutter (22218): child deactivate…

I/flutter (22218): child dispose…




*   将MyApp的代码由 `child: isShowChild ? Child() : Text("演示移除Child")`,改为 `child: Child()`,点击按钮时



I/flutter (22765): parent build…

I/flutter (22765): child didUpdateWidget…

I/flutter (22765): child build…




从这些实验中能够得出State的生命周期为:



\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rwh5gNCi-1652105029912)(图片/生命周期.png)\]



[](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)基础widget

----------------------------------------------------------------------



### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)文本显示



#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Text



`Text`是展示单一格式的文本Widget(Android `TextView`)。



import ‘package:flutter/material.dart’;

///

/// main方法 调用runApp传递Widget,这个Widget成为widget树的根

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

///

/// 1、单一文本Text

///

//创建一个无状态的Widget

class TextApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

//封装了应用程序实现Material Design所需要的一些widget

return MaterialApp(

  title: "Text演示", //标题,显示在recent时候的标题

  //主页面

  //Scaffold : Material Design布局结构的基本实现。

  home: Scaffold(

    //ToolBar/ActionBar

    appBar: AppBar(title: Text("Text")),

    body: Text("Hello,Flutter"),

  ),

);

}

}




在使用`Text`显示文字时候,可能需要对文字设置各种不同的样式,类似Android的 `android:textColor/Size`等



在Flutter中也拥有类似的属性



Widget _TextBody() {

return Text(

"Hello,Flutter",

style: TextStyle(

    //颜色

    color: Colors.red,

    //字号 默认14

    fontSize: 18,

    //粗细

    fontWeight: FontWeight.w800,

    //斜体

    fontStyle: FontStyle.italic,

    //underline:下划线,overline:上划线,lineThrough:删除线

    decoration: TextDecoration.lineThrough,

    decorationColor: Colors.black,

    //solid:实线,double:双线,dotted:点虚线,dashed:横虚线,wavy:波浪线

    decorationStyle: TextDecorationStyle.wavy),

);

}

class TextApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

  title: "Text演示", 

  home: Scaffold(

    appBar: AppBar(title: Text("Text")),

    body: _TextBody(),

  ),

);

}

}




#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)RichText



如果需要显示更为丰富样式的文本(比如一段文本中文字不同颜色),可以使用`RichText`或者`Text.rich`



Widget _RichTextBody() {

var textSpan = TextSpan(

text: "Hello",

style: TextStyle(color: Colors.red),

children: [

  TextSpan(text: "Flu", style: TextStyle(color: Colors.blue)),

  TextSpan(text: "uter", style: TextStyle(color: Colors.yellow)),

],

);

//Text.rich(textSpan);

return RichText(text: textSpan);

}




#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)DefaultTextStyle



​ 在widget树中,文本的样式默认是可以被继承的,因此,如果在widget树的某一个节点处设置一个默认的文本样式,那么该节点的子树中所有文本都会默认使用这个样式。相当于在Android中定义 Theme



Widget _DefaultStyle(){

DefaultTextStyle(

//设置文本默认样式

style: TextStyle(

  color:Colors.red,

  fontSize: 20.0,

),

textAlign: TextAlign.start,

child: Column(

  crossAxisAlignment: CrossAxisAlignment.start,

  children: <Widget>[

    Text("Hello Flutter!"),

    Text("Hello Flutter!"),

    Text("Hello Flutter!",

      style: TextStyle(

          inherit: false, //不继承默认样式

          color: Colors.grey

      ),

    ),

  ],

),

);

}




### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)图片显示



“图文”:有文字显示Widget,又怎么少的了图片呢。



#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)FlutterLogo



​ 这个Widget用于显示Flutter的logo…



Widget flutterLogo() {

return FlutterLogo(

//大小

size: 100,

//logo颜色 默认为 Colors.blue

colors: Colors.red,

//markOnly:只显示logo,horizontal:logo右边显示flutter文字,stacked:logo下面显示文字

style: FlutterLogoStyle.stacked,

//logo上文字颜色

textColor: Colors.blue,

);

}




#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Icon



主要用于显示内置图标的`Widget`



Widget icon() {

return Icon(

  //使用预定义Material icons

  // https://docs.flutter.io/flutter/material/Icons-class.html

  Icons.add,

  size: 100,

  color: Colors.red);

}




#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Image



显示图片的`Widget`。图片常用的格式主要有bmp,jpg,png,gif,webp等,Android中并不是天生支持gif和webp动图,但是这一特性在flutter中被很好的支持了。



| 方式 | 解释 |

| --- | --- |

| Image() | 使用ImageProvider提供图片,如下方法本质上也是使用的这个方法 |

| Image.asset | 加载资源图片 |

| Image.file | 加载本地图片文件 |

| Image.network | 加载网络图片 |

| Image.memory | 加载内存图片 |



##### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Iamge.asset



在工程目录下创建目录,如:assets,将图片放入此目录。打开项目根目录:pubspec.yaml



\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ilqKvFsm-1652105029913)(图片/基础Widget\_AssetsImag.png)\]



return MaterialApp(

  title: "Image演示",

  home: Scaffold(

    appBar: AppBar(title: Text("Image")),

    body: Image.asset("assets/banner.jpeg"),

  ),

);



##### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Image.file



在sd卡中放入一张图片。然后利用**path\_provider**库获取sd卡根目录(Dart库版本可以在:https://pub.dartlang.org/packages查询)。



\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NURxRVFK-1652105029914)(图片/基础Widget\_FileProvider.png)\]



**注意权限**



class ImageState extends State {

Image image;

@override

void initState() {

super.initState();

getExternalStorageDirectory().then((path) {

  setState(() {

    image = Image.file(File("${path.path}${Platform.pathSeparator}banner.jpeg"));

  });

});

}

@override

Widget build(BuildContext context) {

return MaterialApp(

  title: "Image演示",

  home: Scaffold(

    appBar: AppBar(title: Text("Image")),

    body: image,

  ),

);

}

}




##### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Image.network



直接给网络地址即可。



> Flutter 1.0,加载https时候经常出现证书错误。必须断开AS打开app



##### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)Image.memory



Future<List> _imageByte() async {

String path = (await getExternalStorageDirectory()).path;

return await File(“ p a t h path path{Platform.pathSeparator}banner.jpeg”).readAsBytes();

}

class ImageState extends State {

Image image;

@override

void initState() {

super.initState();

_imageByte().then((bytes) {

  setState(() {

    image = Image.memory(bytes);

  });

});

}

@override

Widget build(BuildContext context) {

return MaterialApp(

  title: "Image演示",

  home: Scaffold(

    appBar: AppBar(title: Text("Image")),

    body: image,

  ),

);

}

}




fit属性相当于android中的scaletype,定义如下:



| fit | 说明 | 效果 |

| --- | --- | --- |

| BoxFit.fill | 填充,忽略原有的宽高比,填满为止 | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L6mrpsBu-1652105029915)(图片/基础Widget\_Image\_Fill.png)\] |

| BoxFit.contain | 包含,不改变原有比例让容器包含整个图片,容器多余部分填充背景 | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WBcXaz3K-1652105029916)(图片/基础Widget\_Image\_Contain.png)\] |

| BoxFit.cover | 覆盖,不改变原有比例,让图片充满整个容器,图片多余部分裁剪 | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZ0c91K3-1652105029917)(图片/基础Widget\_Image\_Cover.png)\] |

| BoxFit.fitWidth | 横向图片填充 | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyoRkEkC-1652105029917)(图片/基础Widget\_Image\_FitWidth.png)\] |

| BoxFit.fitHeight | 纵向图片填充 | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RLaJsaOq-1652105029918)(图片/基础Widget\_Image\_FitHeight.png)\] |

| BoxFit.none | 原始大小居中 | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uhqvKLzm-1652105029919)(图片/基础Widget\_Image\_none.png)\] |

| BoxFit.scaleDown | 图片大小小于容器事相当于none,图片大小大于容器时缩小图片大小实现contain | \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UI08cwJt-1652105029919)(图片/基础Widget\_Image\_ScaleDown.png)\] |



#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)CircleAvatar



主要用来显示用户的头像,任何图片都会被剪切为圆形。



CircleAvatar(

  //图片提供者 ImageProvider

  backgroundImage: AssetImage("assets/banner.jpeg"),

  //半径,控制大小

  radius: 50.0,

);



#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)FadeInImage



当使用默认`Image` widget显示图片时,您可能会注意到它们在加载完成后会直接显示到屏幕上。这可能会让用户产生视觉突兀。如果最初显示一个占位符,然后在图像加载完显示时淡入,我们可以使用`FadeInImage`来达到这个目的!



image = FadeInImage.memoryNetwork(

  placeholder: kTransparentImage,

  image: 'https://flutter.io/images/homepage/header-illustration.png',

);



### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)按钮



Material widget库中提供了多种按钮Widget如RaisedButton、FlatButton、OutlineButton等,它们都是直接或间接对RawMaterialButton的包装定制,所以他们大多数属性都和`RawMaterialButton`一样。所有Material 库中的按钮都有如下相同点:



1.  按下时都会有“水波动画”。

2.  有一个`onPressed`属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。



#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)RaisedButton



"漂浮"按钮,它默认带有阴影和灰色背景



RaisedButton(

      child: Text("normal"),

      onPressed: () => {},

    )



#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)FlatButton



扁平按钮,默认背景透明并不带阴影



FlatButton(

child: Text(“normal”),

onPressed: () => {},

)




#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)OutlineButton



默认有一个边框,不带阴影且背景透明。



OutlineButton(

child: Text(“normal”),

onPressed: () => {},

)




#### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)IconButton



可点击的Icon



IconButton(

icon: Icon(Icons.thumb_up),

onPressed: () => {},

)




按钮外观可以通过其属性来定义,不同按钮属性大同小异



const FlatButton({

@required this.onPressed, //按钮点击回调

this.textColor, //按钮文字颜色

this.disabledTextColor, //按钮禁用时的文字颜色

this.color, //按钮背景颜色

this.disabledColor,//按钮禁用时的背景颜色

this.highlightColor, //按钮按下时的背景颜色

this.splashColor, //点击时,水波动画中水波的颜色

this.colorBrightness,//按钮主题,默认是浅色主题

this.padding, //按钮的填充

this.shape, //外形

@required this.child, //按钮的内容

})

FlatButton(

onPressed: () => {},

child: Text(“Raised”),

//蓝色

color: Colors.blue,

//水波

splashColor: Colors.yellow,

//深色主题,这样文字颜色会变成白色

colorBrightness: Brightness.dark,

//圆角按钮

shape: RoundedRectangleBorder(

  borderRadius: BorderRadius.circular(50)

),

)




而`RaisedButton`,默认配置有阴影,因此在配置`RaisedButton` 时,拥有一系列 elevation 属性的配置



const RaisedButton({

this.elevation = 2.0, //正常状态下的阴影

this.highlightElevation = 8.0,//按下时的阴影

this.disabledElevation = 0.0,// 禁用时的阴影

}




### [](https://docs.qq.com/doc/DSkNLaERkbnFoS0ZF)输入框



import ‘package:flutter/material.dart’;

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

class Demo1 extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

  title: "Demo1",

  home: Scaffold(

    appBar: AppBar(

      title: Text("登录"),

    ),

    //线性布局,垂直方向

    body: Column(

      children: <Widget>[

        TextField(

          //自动获得焦点

          autofocus: true,

          decoration: InputDecoration(

              labelText: "用户名",

              hintText: "用户名或邮箱",

              prefixIcon: Icon(Icons.person)),

        ),

        TextField(

          //隐藏正在编辑的文本

          obscureText: true,

          decoration: InputDecoration(

              labelText: "密码",

              hintText: "您的登录密码",

              prefixIcon: Icon(Icons.lock)),

        ),

      ],

    ),

  ),

);

}

}




这个效果非常的“系统”,我们可能大多数情况下需要将下划线更换为矩形边框,这时候可能就需要组合widget来完成:



//容器 设置一个控件的尺寸、背景、margin

Container(

margin: EdgeInsets.all(32),

child: TextField(

    keyboardType: TextInputType.emailAddress,

    decoration: InputDecoration(

        labelText: "用户名",

        hintText: "用户名或邮箱",

        prefixIcon: Icon(Icons.person),

        border: InputBorder.none //隐藏下划线

        )),

//装饰

decoration: BoxDecoration(
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值