Flutter入门系列-Widget系列-普通Widget

1. Container 容器

默认情况下是包裹内容的,如果需要宽度占满屏幕宽度,需要设定 width 为double.infinity 。

Container(
    // 按钮控件
    width: double.infinity,
    height: 48,
    margin: EdgeInsets.all(10),
    child: ...,
),

2.  ElevationButton

可以设置阴影的 Button 

ElevatedButton( //有水波纹效果
    style: ButtonStyle(
        backgroundColor: MaterialStateProperty.all<Color>(Colors.green),
        elevation: MaterialStateProperty.all<double>(10),
    ),
    onPressed: () {
        Navigator.of(context).push(MaterialPageRoute(
            builder: (BuildContext context) =>
                new CommonButtonPage()));
    },
    child: Text('按钮控件')
),

3. MaterialButton

MaterialButton(
    onPressed: () {},
    child: Text('MaterialButton占满一行'),
    minWidth: double.infinity,
    height: 50.0,
    color: Colors.blue,
    textColor: Colors.white,
),

4. SizedBox

SizedBox(
    width: double.infinity,
    height: 50.0,
    child: ElevatedButton(
    onPressed: () {},
    child: Text('SizedBox占满一行'),
    ),
),

5. InkWell

InkWell(
    overlayColor: MaterialStateColor.resolveWith((states) => Colors.green),
    onTap: () {},
    child: new Container(
        alignment: Alignment.center, // alignment将内容布局到中间
        padding: new EdgeInsets.all(10),
        child: new Text(
        'RippleView',
        style: TextStyle(backgroundColor: Colors.amber),
        ),
    ),
),

6. Image 加载网络图片

//这块要求小写驼峰命名方式来命名方法名称
_createNetworkImage() {
    var url = 'http://222.186.12.239:20011/mm8/tupai/20160122/k2xvpyl3wpl.jpg';
    return Image.network(
        url,
        //width: double.infinity,
        //fit: BoxFit.fitWidth, // 以宽度来适配
        //fit: BoxFit.scaleDown, // 以缩小来适配
        fit: BoxFit.cover, // 以整个图片贴在控件上来适配
        width: 300,
        height: 100,
    );
}

7. Image 加载Asset 图片

// 加载本地图片
// 1. 在本地根目录下创建 images 目录,同时添加图片 lovely_girl.jpg
// 2. 在pubspec.yaml 文件中的
// flutter:
//   assets:
//     - images/lovely_girl.jpg
//或者加载整个images目录下所有图片  - images/   
_createLocalImage() {
    var url = 'images/lovely_girl.jpg';
    return Image.asset(
        url,
        width: 300,
        height: 100,
    );
}

// 用AssetImage来加载图片
_createAssetImage() {
    return Image(
        image: AssetImage('images/lovely_girl.jpg'),
        width: 300,
        height: 100,
    );
}

8. Image 加载本地磁盘图片

_createFutureImage() {
    return FutureBuilder(
        future: _getLocalFile('lovely_girl.jpg'),
        builder: (BuildContext context, AsyncSnapshot<File> snapShot) {
          return snapShot.data != null
              ? Image.file(snapShot.data)
              : Container();
        });
  }

Future<File> _getLocalFile(String fileName) async {
    // String dir = (await getExternalStorageDirectory()).path;
    // String dir = (await getTemporaryDirectory()).path; // /data/user/0/com.luckyboy.flutterapp/cache
    String dir = (await getApplicationDocumentsDirectory())
        .path; // /data/user/0/com.luckyboy.flutterapp/app_flutter/lovely_girl.jpg
    print('_getLocalFile $dir');
    File f = new File('$dir/$fileName');
    return f;
}

9. Image 淡入淡出图片

_createMemoryNetworkImage() {
    const url =
        'http://222.186.12.239:20011/mm8/tupai/20160122/k2xvpyl3wpl.jpg';
    return FadeInImage.memoryNetwork(
        width: 300,
        height: 300,
        placeholder: kTransparentImage,
        image: url,
        fadeInDuration:  Duration(seconds: 2),
        fadeOutDuration: Duration(seconds: 2),
    );
}

10. GridView.Builder 网格布局

Container(
    padding: EdgeInsets.all(8),
    child: GridView.builder(
        shrinkWrap: true,
        itemCount: listItems.length,
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisSpacing: 4.0, // 水平子Widget之间的间距
            mainAxisSpacing: 4.0, // 垂直子Widget之间的间距
            childAspectRatio: 3, // 子Widget宽高比例
            crossAxisCount: 3, // 一行的Widget的数量
        ),
        itemBuilder: (context, index) {
            return _buildItem(listItems[index]);
        }),
),

_buildItem(city) {
    return Container(
        height: 40,
        alignment: Alignment.center,
        decoration: BoxDecoration(color: Colors.blue),
        child: Text(city, style: TextStyle(color: Colors.white, fontSize: 14)),
    );
}

11. 水平滚动布局

Container(
    height: 60,
    child: ListView.builder(
        scrollDirection: Axis.horizontal, //滚动方向
        itemBuilder: (context, index) {
        return _buildItem(listItems[index]);
        },
        itemCount: listItems.length,
    ),
),

12. 滑动删除列表

ListView.builder(
    itemCount: items.length,
    itemBuilder: (context, index) {
    final item = items[index];
    return Dismissible(
        key: Key(item),
        child: ListTile(
        title: Text('$item'),
        ),
        onDismissed: (direction) {
        items.removeAt(index);
        Scaffold.of(context)
            .showSnackBar(SnackBar(content: Text('$item dismissed')));
        setState(() {});
        },
        background: Container(
        color: Colors.red,
        ),
    );
}),

13. 展开子列表

class CommonListExpansionPage extends StatelessWidget {
  static const CITY_NAMES = {
    '北京': ['东城区', '西城区', '朝阳区', '海淀区', '丰台区', '昌平区', '石景山区', '顺义区'],
    '上海': ['黄浦区', '徐汇区', '长宁区', '静安区', '普陀区', '闸北区', '虹口区'],
    '广州': ['越秀', '海珠', '荔湾', '天河', '白云', '黄埔', '南沙', '番禺'],
  };

  @override
  Widget build(BuildContext context) {
    final title = '列表展开与收起';
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: ListView(children: _listExpansionWidgets()),
    );
  }

  List<Widget> _listExpansionWidgets() {
    List<Widget> widgets = [];
    CITY_NAMES.keys.forEach((city) {
      widgets.add(_buildItem(city, CITY_NAMES[city]));
    });
    return widgets;
  }

  Widget _buildItem(String city, List<String> subCitys) {
    return ExpansionTile(
      title: Text(
        city,
        style: TextStyle(color: Colors.black54, fontSize: 14),
      ),
      children: subCitys.map((subCity) => _buildSub(subCity)).toList(),
      onExpansionChanged: (bool expand) {
        print('$expand');
      },
    );
  }

  Widget _buildSub(String subCity) {
    return FractionallySizedBox(
      widthFactor: 1,
      child: Container(
        height: 50,
        margin: EdgeInsets.only(left: 16, bottom: 0),
        //decoration: BoxDecoration(color: Colors.grey),
        child: Text(subCity),
      ),
    );
  }
}

14. 列表加载更多

class CommonListLoadMorePage extends StatefulWidget {
  @override
  _CommonListLoadMorePageState createState() => _CommonListLoadMorePageState();
}

class _CommonListLoadMorePageState extends State<CommonListLoadMorePage> {
  var listItems = [
    '北京',
    '上海',
    '广州',
    '深圳',
    '杭州',
    '苏州',
    '天津',
    '武汉',
    '成都',
    '西安',
    '重庆',
    '昆明',
    '兰州',
    '乌鲁木齐',
    '太原'
  ];

  static const PAGE_SIZE = 15;

  bool disposed = false;

  ScrollController _scrollController = new ScrollController();

  final GlobalKey<RefreshIndicatorState> refreshKey = new GlobalKey();

  @override
  void initState() {
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        // 加载到最底部位置 准备加载更多数据
        _loadMoreData();
      }
    });
    Future.delayed(Duration(seconds: 0), () {
      refreshKey.currentState.show();
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final title = '列表加载更多控件';
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: RefreshIndicator(
        key: refreshKey,
        onRefresh: _handleRefresh,
        child: ListView.builder(
            // 保持ListView在任何情况下都能滚动,解决在RefreshIndicator的兼容性问题
            physics: const AlwaysScrollableScrollPhysics(),
            controller: _scrollController,
            itemCount: listItems.length >= PAGE_SIZE
                ? listItems.length + 1
                : listItems.length,
            itemBuilder: (context, index) {
              if (index == listItems.length) {
                return Container(
                  width: double.infinity,
                  height: 50,
                  margin: EdgeInsets.fromLTRB(10, 5, 10, 5),
                  child: Align(
                    child: CircularProgressIndicator(),
                  ),
                );
              }
              return _buildItem(listItems[index]);
            }),
      ),
    );
  }

  _buildItem(city) {
    return Container(
      width: double.infinity,
      height: 50,
      margin: EdgeInsets.fromLTRB(10, 5, 10, 5),
      child: ElevatedButton(
        onPressed: () {},
        child: Text(city ?? ''),
      ),
    );
  }

  Future<Null> _handleRefresh() async {
    await Future.delayed(Duration(seconds: 2));
    //1. 创建一个指定数量的List
    List<String> target = []..length = listItems.length;
    //2. 将旧数据拷贝到新的List中
    List.copyRange(target, 0, listItems);
    //3. 将新的List中元素进行修改
    List<String> targetNnew = target.map((e) => e + "A").toList();
    listItems.clear();
    //4. 添加新的数据源到列表中
    listItems.addAll(targetNnew);
    if (disposed) {
      return;
    }
    setState(() {});
    return null;
  }

  Future<Null> _loadMoreData() async {
    await Future.delayed(Duration(seconds: 1));
    listItems.add("更多城市");
    if (disposed) {
      return;
    }
    setState(() {});
    return null;
  }

  @override
  void dispose() {
    disposed = true;
    _scrollController.dispose();
    super.dispose();
  }
}

15. 具有分割线的列表

Container(
    child: ListView.separated(
        itemBuilder: (context, index) {
            return _buildItem(listItems[index]);
        },
        separatorBuilder: (context, index) {
            return Container(
            constraints: BoxConstraints.tightFor(height: 1),
            color: Colors.black45,
            );
        },
        itemCount: listItems.length),
),

16. Align 

import 'package:flutter/material.dart';
import 'dart:math' as math;

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

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

class _AlignPageState extends State<AlignPage> with SingleTickerProviderStateMixin {
  int size = 20;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('AlignPage'),),
      body: Container(
        alignment: Alignment(0, 0),
        child: Container(
          width: MediaQuery.of(context).size.width/2,
          height: MediaQuery.of(context).size.width/2,
          child: Stack(
            children: List.generate(size, (index){
               return getAlign(index.toDouble()/(size/2));
            }),
          ),
        ),
      ),
    );
  }

  Widget getAlign(double x) {
    return Align( //Center 就是默认的Align
       child: Container(
         width: 20,
         height: 20,
         decoration: BoxDecoration(
           color: Colors.grey,
           borderRadius: BorderRadius.all(Radius.circular(10))
         ),
       ),
      //注意坐标范围:x,y都在 在【-1, 1】之间,以向右为x轴正方向,向下为y轴正方向 
      // 表示该child在父布局的坐标位置 alignment
      alignment: Alignment(math.cos(x*math.pi), math.sin(x*math.pi)),
      //alignment: Alignment(x, y),
    );
  } 
}

效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值