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 tabBodies = [
    HomePage(),CategoryPage(),CartPage(),MemberPage()];

@override
Widget build(BuildContext context) {
    ///初始化 宽高适配工具
    ScreenUtil.instance = ScreenUtil(width: 750, height: 1280)..init(context);
    // Provide的使用 可以在CurrentIndexProvide 数据发生变化时候实时更新
    return Provide(
      builder: (context, child,value,){
        int currentIndex= Provide.value(context).currentIndex;
        return Scaffold(
            bottomNavigationBar: BottomNavigationBar(
              type: BottomNavigationBarType.fixed,
              currentIndex: currentIndex,
              items: bottomBars,
              onTap: (index){
                /// 改变 Provide 下标状态
                Provide.value(context).changeIndex(index);
              },
            ),
            /// 为了可以保存状态 需要嵌套一个 IndexedStack (堆栈需要 传入tab列表和下标)
            body: IndexedStack(
                index: currentIndex,
                /// 列表需要的对象是 list 需要及时更正对象类型是否正确
                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 swiperDataList = (data['data']['slides'] as List).cast();
              /// 获取类别列表
              List navigatorList =(data['data']['category'] as List).cast();
              List recommendList = (data['data']['recommend'] as List).cast(); // 商品推荐
              /// ScrollView 同android  => 改为 EasyRefresh ,可提供上拉加载更多
              return EasyRefresh(
                footer: MaterialFooter(
                  backgroundColor: Colors.white,

                ),
                child: ListView(
                  children: [
                    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(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

你可能感兴趣的:(Flutter 学习与总结)