Flutter - 基础控件

996 阅读5分钟

四、Flutter基础

4.1 flutter入口函数

main(List<String> args) {
  runApp(myApp());
}
​
class myApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(
              "标题",
              style: TextStyle(
                fontSize: 30.0,
                color: HexColor("999999"),
              ),
            ),
        ),
        body: content(),  
      ),
      theme: ThemeData(
        primaryColor: Colors.white,
      ),
    );
  }
}
​
class content extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Text(
          "居中显示",
          textDirection: TextDirection.ltr,
          style: TextStyle (fontSize: 40.0, color: Colors.red),
        ),
    );
  }
}

4.2 Text

 child: Text(
    "这里是标签内容",
    textAlign: TextAlign.right,
    overflow: TextOverflow.ellipsis,
    maxLines: 1,
    textScaleFactor: 1.5,
    style: TextStyle(
      color: HexColor("333333"),
      fontSize: 14.0,
      fontWeight: FontWeight.w800, // 加粗
    ),
  ),

4.3 Container

child: Container(
  width: 200.0,
  height: 300.0,
  
  // 布局
  alignment: Alignment.topRight,
  
  // 边距
  padding: EdgeInsets.all(20),
  // padding: EdgeInsets.fromLTRB(16, 16, 10, 8),
  margin: EdgeInsets.all(20),
​
  // 位移动  x, y, z
  transform: Matrix4.translationValues(10, 20, 30),
  
  // 设置。背景颜色、 边框、圆角
  decoration: BoxDecoration( 
    color: HexColor("ff0000"),
    border: Border.all(
      color: Colors.blue,
      width: 2.0
    ),
    borderRadius: BorderRadius.circular(10.0)
  ),
)

4.4 Image

  • 直接显示的图片

    child: Image.network(
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.ssl.qhimg.com%2Fdr%2F...",
      alignment: Alignment.topLeft,
      fit: BoxFit.cover, // 全部填充并剪切
    ),
    
  • 圆形图片

    child: ClipOval(
      child: Image.network(
        "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.s",
        fit: BoxFit.cover,
      ),
    ),
    
  • 切圆角

    child: Container(
      width: 300.0,
      height: 300.0,
      decoration: BoxDecoration(
        color: Colors.yellow,
        borderRadius: BorderRadius.circular(15),
        image: DecorationImage(
          image: NetworkImage(
            "https://gimg2.baidu.com/image_s",
          ),
          fit: BoxFit.cover
        ),
      ),     
    )
    ​
    // 如下这里如果换成本地
    image: DecorationImage(
      image: Image.asset("images/master_head_bgImage"),
    ),
    // 换成下面这种方式
    image: DecorationImage(
      // image: Image.asset("images/master_head_bgImage"),
      image: AssetImage("images/master.png"),
      fit: BoxFit.cover
    ),
    
  • 头像显示

    ListTile(
      leading: CircleAvatar( // 专门用于处理头像的控件
      backgroundImage: NetworkImage(this.listData[1]["imageUrl"]),
      ),
    title: Text(this.listData[1]["title"]),
      subtitle: Text(this.listData[1]["subTitle"], maxLines: 1, overflow: TextOverflow.ellipsis,),
    )
    
  • 加载本地图片

    1. 在本地 ios 和 安卓同级别目录下建文件夹 images

    2. 建立 2.0x 和 3.0x 图片文件夹。 1.0x 的放外面

    3. 在 pubspec.yaml 中引入图片。

      flutter:
        uses-material-design: true
        assets:
          - images/master.png
          - images/2.0x/master.png
          - images/3.0x/master.png
      
    4. 这里也可以直接引入。 而不区分2.x 3.x 那其实就是直接加载图片不区分

      assets:
          - images/
      

4.5 ListView

return ListView(
      scrollDirection: Axis.vertical,
      children: [
        ListTile(title: Text("这是标题"), subtitle: Text("这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容."),),
        ListTile(title: Text("这是标题"), subtitle: Text("这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容."),),
        ListTile(
          title: Text("这是标题"), 
          subtitle: Text("这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容."),
          trailing: Image.network("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.n63.com%2Fphotodir%2Fimg.php%2Fthumbnail%2Fchina%2Fyizhenyu%2Fwww.n63.com_dz_f_e_th_fi_f_s_ll.jpg&refer=http%3A%2F%2Fwww.n63.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1632968753&t=6ffdade4c316ba562cde8445890fc692"),
        ),
        ListTile(
          title: Text("这是标题"), 
          subtitle: Text("这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容, 这是描述内容."),
          leading: Image.network("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.n63.com%2Fphotodir%2Fimg.php%2Fthumbnail%2Fchina%2Fyizhenyu%2Fwww.n63.com_dz_f_e_th_fi_f_s_ll.jpg&refer=http%3A%2F%2Fwww.n63.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1632968753&t=6ffdade4c316ba562cde8445890fc692"),
        ),
      ],
    );

4.6 ListView.builder 动态列表

class Content extends StatelessWidget {
  List listData = [
    {"title" : "ani", "subTitle" : "你终于还是。。。"},
    {"title" : "timi", "subTitle" : "你终于还是。。。"},
    {"title" : "kangkang", "subTitle" : "你终于还是。。。"},
  ];
  // 这里是练习一下。初始化数据
  Content() {
    listData.add({"title" : "这是本类创建的时候初始化的数据", "subTitle" : "你终于还是。。。"});
  }
  // 封装方法
  Widget _getListItem(context, index) {
    return ListTile(
      title: Text(this.listData[index]["title"]),
      subtitle: Text(this.listData[index]["subTitle"] + "$index"),
    );
  }
​
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: this.listData.length,      
      // itemBuilder: (context, index) {
      //   return ListTile(
      //     title: Text(this.listData[index]["title"]),
      //     subtitle: Text(this.listData[index]["subTitle"] + "$index"),
      //   );
      // },
      // 下面的就是帮上面的给封装起来
      itemBuilder: this._getListItem
    );
  }
}

4.7 GridView

return GridView.count(
      crossAxisCount: 2,
      mainAxisSpacing: 10, // y 轴艰巨
      crossAxisSpacing: 10, // x 艰巨
      padding: EdgeInsets.all(10),
      children: [
        Text("----"),
        Text("----"),
        Text("----"),
        Text("----"),
        Text("----"),
        Text("----"),
        Text("----"),
      ],
    );
  }
return GridView.builder(
  padding: EdgeInsets.all(10),
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    mainAxisSpacing: 15.0,
    crossAxisSpacing: 15.0
  ), 
  itemCount: this.listData.length,
    
  itemBuilder: (context, index) {
    return Container(
      decoration: BoxDecoration(
        border: Border.all(
          color: Colors.red,
          width: 1.5
        )
      ),
      child: Column(
        children: [
          Container(
            height: 100,
            width: 100,
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: Colors.blue,
            ),
            child: Text(this.listData[index]["title"]),
          ),
          SizedBox(height: 10,),
          Text(this.listData[index]["subTitle"], style: TextStyle(fontSize: 20, color: Colors.red),)
        ],
      ),
    );
  }
);
Widget _gridViewItem(context, index) {
    return Container(
            decoration: BoxDecoration(
              border: Border.all(
                color: Colors.red,
                width: 1.5
              )
            ),
            child: Column(
              children: [
                Container(
                  height: 100,
                  width: 100,
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    color: Colors.blue,
                  ),
                  child: Text(this.listData[index]["title"] + "  $index"),
                ),
                SizedBox(height: 10,),
                Text(this.listData[index]["subTitle"], style: TextStyle(fontSize: 20, color: Colors.red),)
              ],
            ),
          );
  }

4.8 Icon Row

  • 注意 Row 的 children 是需要宽度的不然不显示

    Row 需要设置 width

    Column 需要设置高度

    @override
      Widget build(BuildContext context) {
        return Container(
          width: 414,
          height: 600,
          padding: EdgeInsets.all(10),
          decoration: BoxDecoration( 
            color: HexColor("dbdbdb")
          ),
          child: Row(
            // mainAxisAlignment: MainAxisAlignment.center, //居中显示
            // mainAxisAlignment: MainAxisAlignment.spaceBetween, // 左右靠边。中间居中
            // mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 等分
            mainAxisAlignment: MainAxisAlignment.spaceAround, // 两边边距 = 中间间距 / 2
            crossAxisAlignment: CrossAxisAlignment.start, // 副轴对齐方式
            children: [
              JCIcon(Icons.home, bgColor: Colors.blue),
              JCIcon(Icons.home, bgColor: Colors.yellow),
              JCIcon(Icons.home, bgColor: Colors.orange),
              // JCIcon(Icons.home, bgColor: Colors.blue),
              // JCIcon(Icons.home, bgColor: Colors.yellow),
              // JCIcon(Icons.home, bgColor: Colors.orange)
            ],
          ),
        );
      }
      
      class JCIcon extends StatelessWidget {
      IconData icon;
      Color bgColor;
      JCIcon(this.icon, {this.bgColor = Colors.blue});
      @override
      Widget build(BuildContext context) {
        return Container(
          width: 100.0,
          height: 100.0,
          color: this.bgColor,
          child: Icon(this.icon, color: Colors.red, size: 30,),
        );
      }
    }
    

4.9 布局 Expanded

child: Row(
  children: [
    Expanded(
      flex: 1,
      child: JCIcon(Icons.home, bgColor: Colors.yellow)
    ),
    SizedBox(width: 10,),
    Expanded(
      flex: 2,
      child: JCIcon(Icons.search, bgColor: Colors.blue,)
    )
  ]
)

4.10 布局 Stack Align Positioned

  • Stack Align

    child: Stack(
        // alignment: Alignment.center,
        // alignment: Alignment(1, 1),
        children: [          
          Align(alignment: Alignment.topLeft, child: Container(width: 100, height: 100, color: Colors.red,),),
          Align(alignment: Alignment.center, child: Container(width: 100, height: 100, color: Colors.blue,),),
          Align(alignment: Alignment.bottomRight, child: Container(width: 100, height: 100, color: Colors.yellow,),),
        ],
    )
    
  • Stack Positioned

    child: Stack(
      children: [          
        Positioned(child: Container(width: 100, height: 100, color: Colors.red,), left: 0,),
        Positioned(child: Container(width: 100, height: 100, color: Colors.blue,), right: 0, top: 0,),
        Positioned(child: Container(width: 100, height: 100, color: Colors.yellow,), left: 200, top: 200,),
      ],
    )
    

4.11 Card AspectRatio. CircleAvatar

child: ListView(
    children: [
      Card(
        margin: EdgeInsets.all(10),
        child: Column(
          children: [
            AspectRatio( // 处理 宽/长 比例显示的图片
              aspectRatio: 20/9.0, 
              child: Image.network(this.listData[1]["imageUrl"], fit: BoxFit.cover,),
            ),
            ListTile(
              leading: CircleAvatar( // 专门用于处理头像的控件
                backgroundImage: NetworkImage(this.listData[1]["imageUrl"]),
              ),
              title: Text(this.listData[1]["title"]),
              subtitle: Text(this.listData[1]["subTitle"], maxLines: 1, overflow: TextOverflow.ellipsis,),
            )
          ],
        ),
      ),
    ],
  )
);

4.12 列表动态加载数据

child: ListView(
  children: this.listData.map((item){
    return Card(
      margin: EdgeInsets.all(10),
      child: Column(
        children: [
          AspectRatio( // 处理 宽/长 比例显示的图片
            aspectRatio: 20/9.0, 
            child: Image.network(item["imageUrl"], fit: BoxFit.cover,),
          ),
          ListTile(
            leading: CircleAvatar( // 专门用于处理头像的控件
              backgroundImage: NetworkImage(item["imageUrl"]),
            ),
            title: Text(item["title"]),
            subtitle: Text(item["subTitle"], maxLines: 1, overflow: TextOverflow.ellipsis,),
          )
        ],
      ),
    );
  }).toList(),
)
class _MineState extends State<Mine> {
  List listIcon = [Icon(Icons.task), Icon(Icons.settings)];
  List listTitle = [    {"title" : "我的任务", "icon" : Icon(Icons.task)},    {"title" : "我的钱包", "icon" : Icon(Icons.money)},    {"title" : "设置中心", "icon" : Icon(Icons.settings)},  ];
  @override
  Widget build(BuildContext context) {
    return Container(
       child: ListView(
         children: this.listTitle.map((item) {
           return Column(
             children: [
                ListTile(
                  leading: item["icon"],
                  title: Text(item["title"]),
                  trailing: Icon(Icons.keyboard_arrow_right),
                  horizontalTitleGap: 1,
                  onTap: () {
                    if (item["title"] == "设置中心") {
                      JCRouter.push(context, Setting(titleString: "设置中心",));
                    }
                  },
                ),
                Divider(height: 0.5, color: HexColor.lineColor,indent: 16,endIndent: 16,)
             ],
            );
         }).toList(),
       ),
    );
  }
}

4.13 Wrap

child: Wrap(
        spacing: 10,
        runSpacing: 0.0001,
        children: [
          MyButton("这是一个按钮"),
          MyButton("个按钮"),
          MyButton("这是一个按钮个按钮"),
          MyButton("这是一个按钮"),
          MyButton("这是一个按钮个按钮"),
          MyButton("这是个按钮一个按钮"),
          MyButton("这是一个按钮"),
          MyButton("这是一个按钮"),
          MyButton("这是一个按钮"),
        ],
      )
    );

4.14 常用统计

  1. children 是数组

    • Row Column 适用于横向布局,切子视图不能超过父视图宽度。
    • ListView 如果横向布局,或者纵向布局超过需要滑动的都是需要使用 ListView
    • GridView 相当于 CollectionView 矩阵式布局
    • Wrap 和 Row 差不多,横向布局超出父视图宽度的时候,会自动换行
    • Stack 他是一种绝对定位的方式处理子视图
  2. children 是对象的容器

    • Expanded 适用于左边固定,右边弹性拉伸的横向布局。
    • Card 卡片式列表
    • ListTile 最常见的 cell 列表
    • AspectRatio 控制长宽比