Flutter從入門到奔潰(五):擼一些UI交互以及動態頁面

[toc]android

Flutter從入門到奔潰(五):擼一些UI交互以及動態頁面

前記

咱們以前粗略介紹了基礎以及佈局:git

Flutter從入門到奔潰(一):擼一個登陸界面github

Flutter從入門到奔潰(二):擼一個我的界面web

Flutter從入門到奔潰(三):擼一個App基礎框架json

# Flutter從入門到奔潰(四):擼一個包含列表刷新以及網絡請求的首頁api

總算是脫離了無聊的靜態頁面,涉及到了一部分網絡交互,今天咱們接着進行UI交互的學習(由於開源中國的api感受不太好用,咱們改用wananzhuo的api,這個也是咱們安卓狗練手的必備項目了,這裏感謝鴻洋大神)。cookie

頁面交互

登陸界面

image.png

登陸界面使用咱們以前繪製的靜態頁面,在這裏咱們進行UI交互:網絡

  1. 拿到用戶輸入的數據
  2. 對數據進行必要的驗證
  3. 提交用戶數據到後臺
  4. 根據接口成功與否進行頁面交互以及數據更新

接下來咱們分步進行上述操做:app

拿到用戶輸入的數據

咱們頁面是用了基礎的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。

互勉

一塊兒玩吧

相關文章
相關標籤/搜索