Flutter从入门到奔溃(五):撸一些UI交互以及动态页面

[toc]

Flutter从入门到奔溃(五):撸一些UI交互以及动态页面

前记

我们之前粗略介绍了基础以及布局:

Flutter从入门到奔溃(一):撸一个登录界面
Flutter从入门到奔溃(二):撸一个个人界面
Flutter从入门到奔溃(三):撸一个App基础框架
# Flutter从入门到奔溃(四):撸一个包含列表刷新以及网络请求的首页

总算是脱离了无聊的静态页面,涉及到了一部分网络交互,今天我们接着进行UI交互的学习(因为开源中国的api感觉不太好用,我们改用wananzhuo的api,这个也是我们安卓狗练手的必备项目了,这里感谢鸿洋大神)。

页面交互

登录界面

image.png

登录界面使用我们之前绘制的静态页面,在这里我们进行UI交互:

  1. 拿到用户输入的数据
  2. 对数据进行必要的验证
  3. 提交用户数据到后台
  4. 根据接口成功与否进行页面交互以及数据更新

接下来我们分步进行上述操作:

拿到用户输入的数据

我们页面是用了基础的TextField,所以我们通过controller来进行数据获取,(如果是用form表单的格式的话,还有另外一种方式,在onsave方法里面保存,这里按下不表)。

 onPressed: () {
 _postLogin(
          _userNameController.text, _userPassController.text);
    },

我们很容易可以知道上述代码的作用是通过2个对应的controller拿到了username,userpass2个参数,并把他们作为参数提供给了私有方法_postLogin

对数据进行必要的验证

这里对数据并没有太大的要求,只要是非空,我们就默认是有效数据,所以我们做了简单的判断:

_postLogin(String userName, String userPassword) {
    if (userName.isNotEmpty && userPassword.isNotEmpty) {
        //    do some   
    } else {
      TsUtils.showShort('请输入用户名和密码');
    }
  }

这里我们稍微讲下使用的一个插件:** fluttertoast: ^2.0.7**,很明显就是一个android的Toast方法,(这里还有另外一种做法是用原生提供桥接,让flutter调用原生方法进行交互,这里也按下不表,后续我们更新这部分的内容),

import 'package:fluttertoast/fluttertoast.dart';
class TsUtils{
  static showShort(String msg){
    Fluttertoast.showToast(
        msg: msg,
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.CENTER,
        timeInSecForIos: 1,
        bgcolor: "#63CA6C",
        textcolor: '#ffffff'
    );
  }
}

提交用户数据到后台

玩安卓的api接口是典型的三段式接口:

{
    "data": ...,
    "errorCode": 0,
    "errorMsg": ""
}
  1. 判断成功与否用errorCode
  2. 显示信息用errorMsg
  3. 拿数据用data

所以我们对应进行了比较拙略的封装:

//  post请求
  static Future<Map> post(String url,
      {Map<String, String> params, bool saveCookie = false}) async {
    if (params == null) {
      params = new Map();
    }
    String _url = Api.BASE_URL + url;
    if (OsApplication.cookie != null) {
      params['Cookie'] = OsApplication.cookie;
    }
    http.Response res = await http.post(_url, body: params);
    return _dealWithRes(res, saveCookie: saveCookie);
  }
static Map<String, dynamic> _dealWithRes(var res, {bool saveCookie}) {
    if (res.statusCode == 200) {
      var cookie = res.headers['set-cookie'];
      if (saveCookie) {
        SpUtils.saveCookie(cookie);
        OsApplication.cookie = cookie;
      }
      String body = res.body;
      var jsonStr = json.decode(body);
      print('the jsonStr is $jsonStr');
      int errCode = jsonStr['errorCode'];
      if (errCode == 0) {
        var data = jsonStr['data'];
        return data;
      } else {
        TsUtils.showShort(jsonStr['errorMsg']);
        return null;
      }
    } else {
      TsUtils.showShort('您的网络好像不太好哟~~~///(^v^)\\\~~~');
      return null;
    }
  }

这里需要注意的是一个**cookie **,我们用来进行登录的凭证,这里的思路是:

  1. 登录的时候拿到cookie,保存到OsApplication类中,并且持久化
  2. 启动app的时候从持久化中获取,保存到OsApplication类中,
  3. 调用接口的时候根据是否要保存,重新进行保存,并携带cookie传到后台
    (存在一个问题是内存被杀死后,要重新从持久化中获取)

我们完整的登录方法应该是:

_postLogin(String userName, String userPassword) {
    if (userName.isNotEmpty && userPassword.isNotEmpty) {
      Map<String, String> params = new Map();
      params['username'] = userName;
      params['password'] = userPassword;
      Http.post(Api.USER_LOGIN, params: params,saveCookie: true).then((result) {
        SpUtils.map2UserInfo(result).then((userInfoBean){
          if(userInfoBean!=null){
            OsApplication.eventBus.fire(new LoginEvent(userInfoBean.username));
            SpUtils.saveUserInfo(userInfoBean);
            Navigator.pop(context);
          }
        });
      });
    } else {
      TsUtils.showShort('请输入用户名和密码');
    }
  }

这里我们是不是看到了一个熟悉的名词呢=> eventBus,hahahahahahahahhahahahahhaha,它是我们下一个步骤的主角。

根据接口成功与否进行页面交互以及数据更新

我们登录后,要怎么通知其他页面,我已经登录了呢?

  1. 把栈里所有activity都出栈,重新new出新的带登录信息的activity再压栈进去
  2. 通过其他手段通知需要更新状态的页面:爷爷我登录了,你赶紧地更新页面!!

我觉得第二种比较划算!而在安卓中,我们可以通过原生的广播,第三方的EventBus来实现,而在flutter,我们可以考虑用插件event_bus: ^1.0. 1来实现。

它的实现方式和安卓版的类似:

  1. 写event类
  2. 事件源发出event
  3. 接受源接受event,并作出对应处理

登录事件源发出消息

    OsApplication.eventBus.fire(new LoginEvent(userInfoBean.username));

个人中心接受源接收消息

OsApplication.eventBus.on<LoginEvent>().listen((event) {
      setState(() {
        if (event != null && event.userName != null) {
          userName = event.userName;
          userAvatar = 'http://www.wanandroid.com/resources/image/pc/logo.png';
        } else {
          userName = null;
          userAvatar = null;
        }
      });
    });

设置页面-退出登录发送logout事件源

这里不能说用户一点退出就立马噌噌噌地退出了,要有一个交互的过程--AlertDialog

_showDialog() {
    showDialog(
        builder: (context) => new AlertDialog(
              title: new Text('提示'),
              content: new Text('是否要退出登录'),
              actions: <Widget>[
                new FlatButton(
                    onPressed: () {
                      Navigator.pop(context);
                    },
                    child: new Text('取消')),
                new FlatButton(
                    onPressed: () {
                      SpUtils.cleanUserInfo();
                      OsApplication.eventBus.fire(new LoginEvent(null));
                      Navigator.pop(context);
                    },
                    child: new Text('是的'))
              ],
            ),
        context: context);
  }

在确定按钮中,我们清除了用户信息(包括保存保存于内存和持久化的userName,token,id,cookie),
并且发出了一个null的event,由接受源代码可以知道,会显示未登录状态。

丑丑的体系页面

UI “鉴赏”

接下来做好准备!!! 你将会受到视觉的冲击!!! 一大波钢铁直男的粗糙审美将会冲击你!
我很自豪地认为要是有审美选丑比赛,我肯定可以夺得第一!

image.png

image.png

image.png

页面拆解

一级页面

一级页面没有什么难度,我们仍然有多种方案来实现它:

  1. listView
  2. CustomScrollView
  3. ScrollView

这里我们选用CustomScrollView,具体代码可以:
体系页面
如果有人有兴趣的话,可以试试自己动手写一个呢。

二级页面

二级页面用安卓来实现肯定就是:tabLayout+ViewPager,有趣的是flutter只用一个控件就可以实现了DefaultTabController

 @override
  Widget build(BuildContext context) {
    widgetsUtils = new WidgetsUtils(context);
    return new Scaffold(
      appBar: new AppBar(
        title: widgetsUtils.getAppBar(_title),
        iconTheme: new IconThemeData(color: Colors.white),
      ),
      body: new DefaultTabController(
        child: new Scaffold(
            appBar: new TabBar(
              isScrollable: true,
              tabs: _initTabs(),
            ),
            body: new TabBarView(children: _initBody())),
        length: classList.length,
      ),
    );
  }

其中的TabBar类似于tabLayout;
其中的TabBarView类似于ViewPager;

这里有一个需要注意的点,TabBarView的children每次划到的时候都会重新走一次initState(),而如果我们在那里请求接口的话,就会每次都请求一次,这样无论是UI还是性能还是体验都不是我们要的
而解决方案是在children(也就是类似fragment)的State加上 with AutomaticKeepAliveClientMixin

class _SystemChildPageState extends State<SystemChildPage>
    with AutomaticKeepAliveClientMixin{

  @override
  bool get wantKeepAlive => true;
}

见名知意,这个是用于标志是否保持状态的tag。

三级

三级没了... 就一个webview

总结

陈词

草草地说,好像也没什么好写了,接下去做的都是重复性的劳动:

  1. 接接口
  2. 写数据
  3. 画UI

但是

但是flutter不止这么些可以玩的,动画,2端交互,其其他他零零总总的,还有很多好玩的控件,嗯...接下来继续慢慢玩flutter。

互勉

一起玩吧

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

推荐阅读更多精彩内容