Flutter 学习与总结

该文章主要讲述自己两个月以来 通过闲暇时间编写 简单学习Dart 和 编写 Flutter 的知识点总结和心得,可能不够系统并且有点乱。仅供个人回忆和思考。

update time 2019年10月25日21:28:53

备注: Flutter 中万物皆为 Widget

Dart 简单了解

这边我主要通过 Flutter 中文官网学习 Flutter 中文官网

学习Dart 中 主要查阅的中文博客 Dart 讲解
上述文章 已经将Dart 基础讲解的很透彻了,相信学习过java 和 kotlin 的您应该很好上手。

Flutter 基础配置

本人mac 所以 参考的是 Mac 配置Flutter 配置

因为需要 Xcode 所以对Mac 是有一定要求的。

Flutter 总结

在Flutter 中一切都是 Widget ,接下来我将通过自己编写商城的 两个月时间学到的东西简单的进行一次总结。

本人Flutter 商城GitHub 地址

商城开始

注 :build中设置 debugShowCheckedModeBanner: false, 可以去掉右上角 Debug标签

在欢迎界面中 使用runApp() 来设置app 的启动首页,我在这里使用了 动画来完成 欢迎界面的 动画 及结束事件。

因为欢迎界面存在变动的 View,则我们创建的时候需要使用 快捷键 ‘stful’ 来创建 StatefulWidget,
部分代码

// 动画的声明
AnimationController controller;
Animation animation;

// 一般在初始化/设置状态 的时候使用
@override
void initState() {
    super.initState();
    controller = AnimationController(vsync:this,duration:Duration(milliseconds:2000));
    animation = Tween(begin: 0.0,end:1.0).animate(controller);
    /// 检测动画结束,就跳转到首页
    animation.addStatusListener((status){
      if(status == AnimationStatus.completed){
        // 页面的跳转
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(builder: (context)=>MyApp()),
                (route)=> route==null);
      }
    });
    /// 开始动画
    controller.forward();
}

@override
Widget build(BuildContext context) {
    return FadeTransition(
        opacity: animation,
        child: Image.network(  //网络图片
          'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec='
              '1546851657199&di=fdd278c2029f7826790191d59279dbbe&imgtype=0&src='
              'http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F0112cb554438090000019ae93094f1.jpg'
              '%401280w_1l_2o_100sh.jpg',
          scale: 2.0,  //进行缩放
          fit:BoxFit.cover  // 充满父容器
      ),
    );
}

状态管理

由于首页采用 四个分页,这里选择了BottomNavigationBarItem ,由于需要时刻保持界面变化 及View 的修改,这里引入 第三方库 ’Provide‘ 用来保存状态

Provide 初始化部分

// Provide初始化部分需要放在 main()函数中
var currentIndexProvide = CurrentIndexProvide();
var providers  =Providers();

providers.provide(Provider.value(currentIndexProvide));
runApp(ProviderNode(child: SplashPage(), providers: providers));

Provide 声明部分

class CurrentIndexProvide with ChangeNotifier{

  int currentIndex=0;

  changeIndex(int newIndex){
    currentIndex=newIndex;
    notifyListeners();
  }
}

首页编写

上文我们已经简单设置编写了 Flutter 中的状态管理,这里我们就可以学习状态的另外一种用法(代码注释中也会介绍 另一个第三方库 主要用于界面的适配 ‘ScreenUtil’ )

首页部分主要代码

// 界面
final List<Widget> tabBodies = [
    HomePage(),CategoryPage(),CartPage(),MemberPage()];

@override
Widget build(BuildContext context) {
    ///初始化 宽高适配工具
    ScreenUtil.instance = ScreenUtil(width: 750, height: 1280)..init(context);
    // Provide的使用 可以在CurrentIndexProvide 数据发生变化时候实时更新
    return Provide<CurrentIndexProvide>(
      builder: (context, child,value,){
        int currentIndex= Provide.value<CurrentIndexProvide>(context).currentIndex;
        return Scaffold(
            bottomNavigationBar: BottomNavigationBar(
              type: BottomNavigationBarType.fixed,
              currentIndex: currentIndex,
              items: bottomBars,
              onTap: (index){
                /// 改变 Provide 下标状态
                Provide.value<CurrentIndexProvide>(context).changeIndex(index);
              },
            ),
            /// 为了可以保存状态 需要嵌套一个 IndexedStack (堆栈需要 传入tab列表和下标)
            body: IndexedStack(
                index: currentIndex,
                /// 列表需要的对象是 list<Widget> 需要及时更正对象类型是否正确
                children: tabBodies
            )
        );
      }
    );
}

indexPage 界面简单就这样。(如果有不懂得可以移步到 Github 中查看代码)

Home 界面

其实首页 分类 购物车更多的 就是 布局的编写、业务逻辑的编写和 对js胖提供的json 数据解析展示。

body:FutureBuilder(
          future: getHomePageContent(),
          builder: (context,snapshot){
            if(snapshot.hasData){
              var data=json.decode(snapshot.data.toString());
              print('总体数据${data['data']}');
              /// 获取轮播图资源
              List<Map> swiperDataList = (data['data']['slides'] as List).cast();
              /// 获取类别列表
              List<Map> navigatorList =(data['data']['category'] as List).cast();
              List<Map> recommendList = (data['data']['recommend'] as List).cast(); // 商品推荐
              /// ScrollView 同android  => 改为 EasyRefresh ,可提供上拉加载更多
              return EasyRefresh(
                footer: MaterialFooter(
                  backgroundColor: Colors.white,

                ),
                child: ListView(
                  children: <Widget>[
                    SwiperDiy(swiperDataList:swiperDataList ),   //页面顶部轮播组件
                    TopNavigator(navigatorList:navigatorList),  //导航组件
                    AdBanner(advertesPicture : advertesPicture),  //广告组件
                    LeaderPhone(leaderImage:leaderImage,leaderPhone: leaderPhone),  // 拨打电话

                    Recommend(recommendList:recommendList),// 推荐列表
                    /// 热门商品 列表部分
                    hotTitle,
                    _hotWrapList(),
                  ],
                ),
                onLoad: () async {
                  print('上拉记载更多:pageindex:$page');
                  _getHotGoods();
                },

              );
            }else{
              return Center(
                child: Text('加载中'),
              );
            }
          },
        )

上述代码中我么您使用到了 上拉加载,下拉刷新的控件 ‘EasyRefresh’ ,通过 ‘onLoad’ 的方法来加载 下一页数据。顶部的 滑动控件用的第三方的 ‘Swiper’。

导航界面使用的组合是 GridView ,item 中通过 InkWell 包裹Child,可以添加OnTap 方法。

联系店长 这一块主要就是一个图片,但是点击图片后 引用第三方库 ‘url_launcher’ 可以实现拨打电话的功能,真机可以已测试,模拟器可能不行。

分类界面

分类界面由于有 一级 和二级 分类,所以这里左侧使用的 ListView 。右侧顶部 则使用的 横向的 ListView ,

// listview 方向设置
scrollDirection: Axis.horizontal,

在列表中 也要制造分割线 介绍新的控件使用方法

return Container(
            height: ScreenUtil().setHeight(90),
            width: ScreenUtil().setWidth(570),
            // 设置底部 分割线
            decoration: BoxDecoration(
                color: Colors.white,
                border: Border(
                    bottom: BorderSide(width: 0.2,color: Colors.black12)
                )
            ),
            child: ListView.builder(
                itemCount: childCategory.childCategoryList.length,
                scrollDirection: Axis.horizontal,
                itemBuilder: (context, index){
                  return _rightInkWell(index,childCategory.childCategoryList[index]);
                }
            ),);

根据 json 实现 一级列表和 二级列表的联动,剩下的就是展示商品信息的 右下方 商品详情列表,因为存在上拉加载更多的选项,我们依然采用‘Expanded’ 来展示数据。

商品详情

从项目的效果图不难看出,顶部我们直接就是一个 Image 来展示 商品的 大图,下方则为 几个Text,在下边则为两个状态的 Tab,我们这里使用 自定义的 Widget ,下段代码将展示右侧的 编写,左侧雷同。

/// 右侧的 Tab Bar
Widget _myTabBarRight(BuildContext context,bool isRight){
    return InkWell(
      onTap: (){
        Provide.value<DetailsInfoProvide>(context).changeLeftAndRight('right');
      },
      child: Container(
        padding:EdgeInsets.all(10.0),
        alignment: Alignment.center,
        width: ScreenUtil().setWidth(375),
        decoration: BoxDecoration(
            color: Colors.white,
            border: Border(
                bottom: BorderSide(
                    width: 1.0,
                    color: isRight?Colors.pink:Colors.black12
                )
            )
        ),
        child: Text(
          '评论',
          style: TextStyle(
              color:isRight?Colors.pink:Colors.black
          ),
        ),
      ),
    );
}

通过 Provide 来控制两个tab 的状态。接下来我们使用 一个可以通过 html代码本文展示 Html 界面的 第三方库: ‘flutter_html’,使用范例:

return Container(
          child: Html(
          // goodsDetail 为网页代码字符串
          data:goodsDetail
       ),
    );

至于最后的 我的界面 这里就一笔略过了.... ,最后说一下 dio 的使用 代码:

/// 公用 post dio请求方法
/// 参数使用{}包裹,表示该参数可以不需要传。
Future requestPost(url,{formData})async{
  try{
    Response response;
    Dio dio = new Dio();
    dio.options.contentType="application/x-www-form-urlencoded";
    if(formData==null){
      response = await dio.post(servicePath[url]);
    }else{
      response = await dio.post(servicePath[url],data:formData);
    }
    if(response.statusCode==200){
      return response.data;
    }else{
      throw Exception('后端接口出现异常,请检测代码和服务器情况.........');
    }
  }catch(e){
    return print('ERROR:======>$e');
  }
}

总结

针对两个月以来 利用空闲时间 编写的 Flutter 简单商城Demo,自我认为在有Java 和 kotlin 的基础上 还是比较简单好学的,学习的比较多的 就是Flutter 中的各种各样的 Widget使用 及其方法,还有第三方库 (Provide dio 的使用),总结比较简单,暂时就写到这里。 魔都大白(●—●)... bye

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容