IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter学习之认知基础组件,android插件化 -> 正文阅读

[移动开发]Flutter学习之认知基础组件,android插件化

效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w8f2YKnP-1630141808009)(https://user-gold-cdn.xitu.io/2019/2/9/168d1892b5ed3872?imageView2/0/w/1280/h/960/ignore-error/1)]

下面用一个库来加载和缓存网络图像,也可以与占位符和错误小部件一起使用,在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);
    @override
    Widget 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倍的分辨率图片。看下面例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vsndZ2Na-1630141808011)(https://user-gold-cdn.xitu.io/2019/3/13/169772a5f74137f2?imageView2/0/w/1280/h/960/ignore-error/1)]

在设备像素比率为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{

  @override
  Widget 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,//水波纹的颜色
      );

  }
} 

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvclrBLS-1630141808012)(https://user-gold-cdn.xitu.io/2019/2/9/168d269b26914f0a?imageslim)]

四、Flutter布局

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrCSfKSs-1630141808013)(https://user-gold-cdn.xitu.io/2019/2/9/168d2884d214d7c9?imageView2/0/w/1280/h/960/ignore-error/1)]

下面一一介绍简单用法:

1.Container

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tgwj4ebb-1630141808014)(https://user-gold-cdn.xitu.io/2019/2/9/168d298303fdfb1f?imageView2/0/w/1280/h/960/ignore-error/1)]

下面直接上例子:

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

  @override
  Widget 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{

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

运行效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MqnUjwi4-1630141808015)(https://user-gold-cdn.xitu.io/2019/2/9/168d2a2863ccd207?imageView2/0/w/1280/h/960/ignore-error/1)]

2.Padding

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MAuPGGG7-1630141808015)(https://user-gold-cdn.xitu.io/2019/2/9/168d2aba57b4994a?imageView2/0/w/1280/h/960/ignore-error/1)]

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

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

效果图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-loDT9Gqm-1630141808016)(https://user-gold-cdn.xitu.io/2019/2/9/168d2aeb018478b8?imageView2/0/w/1280/h/960/ignore-error/1)]

下面实现Container嵌套Padding:

//Container嵌套Padding
class ContainPaddWidget extends StatelessWidget{
  @override
  Widget 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),
        ),
      );
  }
} 

效果图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67ymLonG-1630141808016)(https://user-gold-cdn.xitu.io/2019/2/9/168d2b99879c9c29?imageView2/0/w/1280/h/960/ignore-error/1)]

3.Center

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ru5yrxz-1630141808017)(https://user-gold-cdn.xitu.io/2019/2/9/168d2b5c3704cb5d?imageView2/0/w/1280/h/960/ignore-error/1)]

//Center
class CenterWidget extends StatelessWidget{

  @override
  Widget 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),
      ),
    );
  }
} 

运行效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uVWGT2US-1630141808018)(https://user-gold-cdn.xitu.io/2019/2/9/168d2bdf82968bee?imageView2/0/w/1280/h/960/ignore-error/1)]

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

4.Stack

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DN2vr7ia-1630141808018)(https://user-gold-cdn.xitu.io/2019/2/10/168d52df573f7550?imageView2/0/w/1280/h/960/ignore-error/1)]

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

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

  @override
  Widget 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,
          ),
        ),
      ],
    );
  }
} 

运行效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVBDVcU7-1630141808019)(https://user-gold-cdn.xitu.io/2019/2/10/168d55176174ccb6?imageView2/0/w/1280/h/960/ignore-error/1)]

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

//层叠布局
class StackWidget extends StatelessWidget{

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

运行效果图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-avIJPTkX-1630141808019)(https://user-gold-cdn.xitu.io/2019/2/10/168d554154fdf2d6?imageView2/0/w/1280/h/960/ignore-error/1)]

5.Colum

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8SODSbyW-1630141808020)(https://user-gold-cdn.xitu.io/2019/2/10/168d5c29016f0ea3?imageView2/0/w/1280/h/960/ignore-error/1)]

直接上代码:

class MyHomePage extends StatelessWidget {
    ...
    body:new ColumnWidget(),
    ....
    
}
//Column布局
class ColumnWidget extends StatelessWidget {
  @override
  Widget 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,
        ),
      ],
    );
  }
} 

运行效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FImmzDlF-1630141808020)(https://user-gold-cdn.xitu.io/2019/2/10/168d5d05f1fe25b7?imageView2/0/w/1280/h/960/ignore-error/1)]

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

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

运行效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iEiBFuT3-1630141808021)(https://user-gold-cdn.xitu.io/2019/2/10/168d5e35aaa14d54?imageView2/0/w/1280/h/960/ignore-error/1)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UIDk2JnU-1630141808021)(https://user-gold-cdn.xitu.io/2019/2/10/168d5e8d49bfad1f?imageView2/0/w/1280/h/960/ignore-error/1)]

  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之前之后之间均匀的分割空闲的空间

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E8N6zpcW-1630141808022)(https://user-gold-cdn.xitu.io/2019/2/10/168d5f65b16e12a2?imageView2/0/w/1280/h/960/ignore-error/1)]

  1. CrossAxisAlignment.center这是默认值,水平居中
  2. CrossAxisAlignment.end:水平方向右侧对齐
  3. CrossAxisAlignment.start:水平方向左侧对齐
  4. CrossAxisAlignment.stretch:水平方向拉伸子child填充满布局
  5. CrossAxisAlignment.baseline:和textBaseline一起使用

6.Row

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DlCJzNEz-1630141808022)(https://user-gold-cdn.xitu.io/2019/2/10/168d67a90ebb695e?imageView2/0/w/1280/h/960/ignore-error/1)]

直接上代码:

class MyHomePage extends StatelessWidget {
  ....
  body:new RowWidget(),
  ...
}
//Row
class RowWidget extends StatelessWidget{
  @override
  Widget 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,
        ),
      ],
    );
  }
} 

效果图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4lH5D9mI-1630141808023)(https://user-gold-cdn.xitu.io/2019/2/10/168d68cc378b8c51?imageView2/0/w/1280/h/960/ignore-error/1)]

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

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

效果图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpWBAiYR-1630141808023)(https://user-gold-cdn.xitu.io/2019/2/10/168d6922d4702cbc?imageView2/0/w/1280/h/960/ignore-error/1)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zMlKMLzr-1630141808023)(https://user-gold-cdn.xitu.io/2019/2/10/168d69756a563f8f?imageView2/0/w/1280/h/960/ignore-error/1)]

  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之前之后之间均匀的分割空闲的空间 而交叉轴(垂直方向)的属性:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NN82oth6-1630141808024)(https://user-gold-cdn.xitu.io/2019/2/10/168d69dc564d0c27?imageView2/0/w/1280/h/960/ignore-error/1)]

  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),示意图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7dR6OGRB-1630141808024)(https://user-gold-cdn.xitu.io/2019/2/10/168d6b3ab4c510a4?imageView2/0/w/1280/h/960/ignore-error/1)]

class MyHomePage extends StatelessWidget {
  ....
  body:new RowWidget(),
  ...
}
class RowWidget extends StatelessWidget{
  @override
  Widget 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')),
      ],
    );
  }
} 

运行效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WiItDvuE-1630141808025)(https://user-gold-cdn.xitu.io/2019/2/10/168d78690cdb210a?imageView2/0/w/1280/h/960/ignore-error/1)]

class MyHomePage extends StatelessWidget {
  ....
  body:new RowWidget(),
  ...
}
class RowWidget extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return Row(
        children: <Widget>[
         Expanded(
         child:Container(
           color:Colors.green,
           padding:EdgeInsets.all(8),
           height: 40.0,
         ),
         flex:1,
       ),
       Expanded(
         child:Container(
           color:Colors.yellow,
           padding:EdgeInsets.all(8),
           height: 40.0,
         ),
         flex:2,
       ),
       Expanded(
         child:Container(
           color:Colors.red,
           padding:EdgeInsets.all(8),
           height: 40.0,
         ),
       ),
      ],
    );
  }
} 

上面代码设置了flex,将一行的宽度分成四等分,第一、三child占1/4的区域,第二个child占1/2区域。 效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1BmtwTs-1630141808025)(https://user-gold-cdn.xitu.io/2019/2/10/168d797afd2c9fc4?imageView2/0/w/1280/h/960/ignore-error/1)]

8.ListView

我相信这个布局在平时开发会经常用到,这是可滚动的列表控件,ListView是最常用的滚动widget,它在滚动方向上一个接一个地显示它的孩子。在纵轴上,孩子没被要求填充ListView,并且内置ListTitle,示意图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FDhCrS19-1630141808025)(https://user-gold-cdn.xitu.io/2019/2/10/168d7a145363861c?imageView2/0/w/1280/h/960/ignore-error/1)]

class MyHomePage extends StatelessWidget {
  ....
  body: new ListViewWidget(
          new List<String>.generate(1000,(i){
            return 'Item &i';
          }),
      ),
  ...
}
//ListView
class ListViewWidget extends StatelessWidget {
  final List<String> items;
  ListViewWidget(this.items);
  @override
  Widget build(BuildContext context) {
    return new ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return new ListTile(
          title: new Text('This is $index'),
        );
      },
    );
  }
} 

效果图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdnORLAI-1630141808026)(https://user-gold-cdn.xitu.io/2019/2/10/168d7bb93cdc7fb3?imageView2/0/w/1280/h/960/ignore-error/1)]

下面设置水平的ListView:

class MyHomePage extends StatelessWidget {
  ....
 body: new ListViewWidget(                       
  new List<String>.generate(1000, (i) {         
    return 'Item &i';                           
  }),                                            
),                                          
  ...
}
  Widget build(BuildContext context) {      
   return new ListView.builder(            
     itemCount: items.length,              
     //设置水平方向 
     scrollDirection:Axis.horizontal,      
     //竖直时:确定每一个item的高度 
     //水平时:确定每一个item的宽度 得要设置 不然不显示 
     itemExtent: 110.0,                    
     itemBuilder: (context, index) {       
       return new ListTile(                
         title: new Text('This is $index'),
       );                                   
     },                                    
   ); 

效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JZJHrS7N-1630141808026)(https://user-gold-cdn.xitu.io/2019/2/10/168d7c93a67be1c2?imageslim)]

9.GridView

GridView是一个网格布局的列组件。GridView继承至CustomScrollView,示意图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gwzlrw0Q-1630141808027)(https://user-gold-cdn.xitu.io/2019/2/10/168d7e30f14ad8c1?imageView2/0/w/1280/h/960/ignore-error/1)]

直接竖直上例子:

//GridView 
class GridViewWidget extends StatelessWidget{        
                                                     
  @override                                          
  Widget build(BuildContext context){                
      return new GridView.count(                     
          crossAxisCount: 3, //3列 
          children: List.generate(40,                
      (i){                                           
           return Card(                              
             child: Center(                          
               child:Text('This is $i'),             
             ),                                       
           );                                         
      })                                              
      );                                              
  }                                                  
} 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AcGe5AZn-1630141808027)(https://user-gold-cdn.xitu.io/2019/2/10/168d7ec415ccdeeb?imageView2/0/w/1280/h/960/ignore-error/1)]

下面上水平例子:

 return new GridView.count(         
      //3行 
      crossAxisCount: 3,               
      //设置水平 
      scrollDirection: Axis.horizontal,
      children: List.generate(40, (i) {
        return Card(                   
          child: Center(               
            child: Text('This is $i'), 
          ),                            
        );                              
      }),                               
    ); 

效果图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5aJQu9oo-1630141808027)(https://user-gold-cdn.xitu.io/2019/2/10/168d805ce19a63a6?imageView2/0/w/1280/h/960/ignore-error/1)]

10.TabBar

移动开发中tab切换是一个很常用的功能,那么Flutter有没有提供这个Widget呢?答案是有的,Flutter通过Material库提供了很方便的API来使用tab切换。

10.1.创建TabController

TabBarViewTabBar都有一个TabController的参数,TabbarViewTabBar就是由TabController来控制同步,点击某个Tab后,要同步显示对应的TabBarView,创建TabController有两种方式:

  1. 使用系统自带的DefaultTabController,在Scaffold套一层DefaultTabController,这种方式TabBarView会自动查找这个tabController
  2. 自己定义一个TabController,实现SingleTickerProviderStateMixin

下面就列一下第一种方式:

 @override
  Widget build(BuildContext context) {
    return new DefaultTabController();
 } 

10.2.构建Tab数据

final List<Tab> myTabs = <Tab>[
    new Tab(text: 'Android'),
    new Tab(text: 'IOS'),
    new Tab(text: 'Flutter'),
    new Tab(text: 'RN'),
    new Tab(text: 'Java'),
    new Tab(text: 'C'),
    new Tab(text: 'C++'),
    new Tab(text: 'Go'),
  ]; 

10.3.创建TabBar

TabBar在哪里都可以创建,在AppBar里有一个bottom参数可以接受TabBar,就放在AppBar下:

 //设置appbar
        appBar: new AppBar(
          //底部
          bottom: new TabBar(
            indicatorColor: Colors.red, //指示器颜色 如果和标题栏颜色一样会白色
            tabs: myTabs,//绑定数据
            isScrollable: true, //是否可以滑动
          ),
    ), 

10.4.绑定TabBar和TabBarView

class MyHomePage extends StatelessWidget {
final List<Tab> myTabs = <Tab>[
    new Tab(text: 'Android'),
    new Tab(text: 'IOS'),
    new Tab(text: 'Flutter'),
    new Tab(text: 'RN'),
    new Tab(text: 'Java'),
    new Tab(text: 'C'),
    new Tab(text: 'C++'),
    new Tab(text: 'Go'),
  ];
  @override
  Widget build(BuildContext context) {
    return new DefaultTabController(
      length: myTabs.length, //Tab长度
      child: new Scaffold(
        //设置appbar
        appBar: new AppBar(
          //底部
          bottom: new TabBar(
            indicatorColor: Colors.red, //指示器颜色 如果和标题栏颜色一样会白色
            tabs: myTabs,//绑定数据
            isScrollable: true, //是否可以滑动
          ),
         ....
        ),
          body: new TabBarView(
          //选中哪个Tabs,body就会显示
          children: myTabs.map((Tab tab) {
            return new Center(child: new Text(tab.text));
          }).toList(),
        ),
        ....
    );
  }
} 

效果如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qPkJY162-1630141808028)(https://user-gold-cdn.xitu.io/2019/2/11/168da97e44473a32?imageslim)]

11.BottomNavigationBar

BottomNavigationBar即是底部导航栏控件,显示在页面底部的设计控件,用于在试图切换,底部导航栏包含多个标签、图标或者两者搭配的形式,简而言之提供了顶级视图之间的快速导航。

11.1.构建底部标签

 //底部数据
  final Map bottomMap ={
    "首页":Icon(Icons.home),
    "朋友圈":Icon(Icons.camera),
    "信息":Icon(Icons.message),
    "其他":Icon(Icons.devices_other),
  }; 

11.2.创建导航栏

因为点击导航栏需要对应的字体显示,所以MyHomePage需要继承StatefulWidget,增加State

//用无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //主题色
      theme: ThemeData(
          //设置为红色
          primarySwatch: Colors.red),
      //这是一个Widget对象,用来定义当前应用打开的时候,所显示的界面
      home: MyHomePageWidget(),
    );
  }
}

class MyHomePageWidget extends StatefulWidget{
  @override
  State<StatefulWidget> createState(){
     return new MyHomePage();
  }
}
class MyHomePage extends State<MyHomePageWidget> {
 //底部数据
  final Map bottomMap ={
    "首页":Icon(Icons.home),
    "朋友圈":Icon(Icons.camera),
    "信息":Icon(Icons.message),
    "其他":Icon(Icons.devices_other),
  };

  int _index = 0;
 bottomNavigationBar: BottomNavigationBar(
            items: (){
              var items = <BottomNavigationBarItem>[];
              bottomMap.forEach((k,v){
                items.add(BottomNavigationBarItem(
                  title:Text(k),//取map的值
                  icon : v,//取map的图标
                  backgroundColor:Colors.red,//背景红色
                ));
              });
              return items;
            }(),
             currentIndex: _index,//选中第几个
             onTap:(position){
               Fluttertoast.showToast(
                   msg: 'text inputted: $position',
                   toastLength: Toast.LENGTH_SHORT,
                   gravity: ToastGravity.CENTER,
                   timeInSecForIos: 1,
               );
               setState(() {
                 _index = position;//状态更新
               });
             }
            ),
   } 

最终效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yltjoNjK-1630141808028)(https://user-gold-cdn.xitu.io/2019/2/11/168dafdd5610d700?imageslim)]

五、实践

下面实践Flutter中文网的例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uvFa0h65-1630141808029)(https://user-gold-cdn.xitu.io/2019/2/11/168db0f3a8ccc3b0?imageView2/0/w/1280/h/960/ignore-error/1)]

先上布局分析图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BBQlRHBd-1630141808029)(https://user-gold-cdn.xitu.io/2019/2/11/168db18086c6f6c9?imageView2/0/w/1280/h/960/ignore-error/1)]

1.实现图像

再说一下如何配置图像

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qguFGyoW-1630141808029)(https://user-gold-cdn.xitu.io/2019/2/11/168db1c21dda63da?imageView2/0/w/1280/h/960/ignore-error/1)]

class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    return MaterialApp(
       home:new MyHomeWidget(),
    );
  }
}

class MyHomeWidget extends StatelessWidget{
  @override
  Widget build(BuildContext context){
     return new Scaffold(
       //设置标题栏
       appBar: new AppBar(
           title:new Text('Flutter Demo'),
       ),
       //主体用ListView
       body:new ListView(
         children: <Widget>[
           //图片
           new Image.asset(
             'images/lake.jpg',
             width:600.0,
             height:240.0,
             //顺便设置图片属性
             fit:BoxFit.cover,
           )
         ],
       ),
     );
  }
} 

2.实现标题栏

 //实现标题栏
     Widget titleWidget = new Container(
       //内边距
       padding:const EdgeInsets.all(30.0),
       //整体是一个水平的布局
       child:new Row(
         //只有一个孩子
         children: <Widget>[
           //用Expanded 会占用icon之外剩余空间
           new Expanded(
               //垂直布局 放置两个文本
               child: new Column(
                 //设置文本一起始端对齐
                 crossAxisAlignment: CrossAxisAlignment.start,
                 //有两个孩子
                 children: <Widget>[
                   new Container(
                     //底部内边距
                     padding:const EdgeInsets.only(bottom:10.0),
                     //孩子 设置字体样式
                     child:new Text(
                       'Oeschinen Lake Campground',
                       style: new TextStyle(fontWeight: FontWeight.bold),
                     ),
                   ),
                   new Text(
                     'Kandersteg, Switzerland',
                     style: new TextStyle(
                       color:Colors.grey[450],//设置颜色透明度
                     ),
                   )
                 ],
               ),
           ),
           new Icon(
             Icons.star,
             color:Colors.red[400],
           ),

           new Text('41'),
         ],
       ),
     ); 

3.实现按钮行

因为三个按钮样式都是一样的,所以抽取公共部分:

 /**
      * 抽取button行的代码复用
      *
      */
     Column getText(IconData icon,String text){
         return new Column(
           //聚集widgets
           mainAxisSize:MainAxisSize.min,
           //child居中
           mainAxisAlignment: MainAxisAlignment.center,
           children: <Widget>[
             new Icon(icon,color:Colors.blue[500]),
             new Container(
               //上部外边距
               margin: const EdgeInsets.only(top:8.0),
               //Text内容样式设定
               child:new Text(
                 text,
                 style:new TextStyle(
                   color:Colors.blue[500],
                 ),
               ),
             )
           ],

         );

     }

     /**
      * 按钮实现
      */
     Widget buttonWidget = new Container(
       //三列
       child:new Row(
         //用MainAxisAlignment.spaceEvenly平均分配子空间
         mainAxisAlignment: MainAxisAlignment.spaceEvenly,
         //孩子们
         children: <Widget>[
           getText(Icons.call, "CALL"),
           getText(Icons.near_me, "ROUTE"),
           getText(Icons.share, "SHARE"),
         ],
       ),
     ); 

4.实现文本

 /**
      * 文本实现
      */
     Widget textWidget = new Container(
       alignment: Alignment.center,
       //设置内边距
        padding:const EdgeInsets.all(10.0),
        child:new Text(
           'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, '
               'it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, '
               'followed by a half-hour walk through pastures and pine forest, '
               'leads you to the lake, which warms to 20 degrees Celsius in the summer. '
               'Activities enjoyed here include rowing, and riding the summer toboggan run.',
          // softWrap: true,//属性表示文本是否应在软换行符(例如句点或逗号)之间断开。
          // textAlign: TextAlign.center,
         ),

     ); 

5.整合

 return new Scaffold(
       //设置标题栏
       appBar: new AppBar(
           title:new Text('Flutter Demo'),
       ),
       //主体用ListView
       body:new ListView(
         children: <Widget>[
           //图片
           new Image.asset(
             'images/lake.jpg',
             width:600.0,
             height:240.0,
             //顺便设置图片属性
             fit:BoxFit.cover,
           ),
           //标题栏
           titleWidget,
           //按钮栏
ke Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, '
               'it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, '
               'followed by a half-hour walk through pastures and pine forest, '
               'leads you to the lake, which warms to 20 degrees Celsius in the summer. '
               'Activities enjoyed here include rowing, and riding the summer toboggan run.',
          // softWrap: true,//属性表示文本是否应在软换行符(例如句点或逗号)之间断开。
          // textAlign: TextAlign.center,
         ),

     ); 

5.整合

 return new Scaffold(
       //设置标题栏
       appBar: new AppBar(
           title:new Text('Flutter Demo'),
       ),
       //主体用ListView
       body:new ListView(
         children: <Widget>[
           //图片
           new Image.asset(
             'images/lake.jpg',
             width:600.0,
             height:240.0,
             //顺便设置图片属性
             fit:BoxFit.cover,
           ),
           //标题栏
           titleWidget,
           //按钮栏
 
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 09:28:21  更:2021-08-29 09:29:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:49:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码