fish-redux(三):Component

今天通過一個實例講解一下Component的使用闲询。下面完成下圖的個人信息界面涤浇。該界面分為基本信息界面和工作信息界面宙拉。兩塊信息通過兩個不同的網(wǎng)絡(luò)請求獲取的笨触,工作信息塊可以點擊右邊的按鈕來展開或收縮詳情萨西,點擊右下角可刷新基本信息界面。

捕獲.PNG

1. 不使用component的實現(xiàn)

  • 新建info_page文件夾旭旭,實現(xiàn)page
class InfoPage extends Page<PageState, Map<String, dynamic>> {
  InfoPage() :super(
    initState: initState,
    effect: buildEffect(),
    view: buildView,
    reducer: buildReducer(),
  );
}

接下來添加state,action葱跋,effect持寄,view,reducer文件

  • state.dart
class PageState implements Cloneable<PageState> {

  String avatar;
  String name;
  int age;

  String company;
  String job;
  String detail;

  PageState();

  @override
  PageState clone() {
    return PageState()..avatar = avatar
    ..name = name
      ..age = age
      ..company = company
      ..job = job
      ..detail = detail
    ;
  }

}

PageState initState(Map<String, dynamic> params) {
  return PageState();
}
  • action.dart
enum PageAction {
updateBase, //更新基本信息
updateJob, //更新工作信息
onRefresh //刷新事件
}

class PageActionCreator {

  static Action updateBaseAction(String avatar, String name, int age) {
    return Action(
      PageAction.updateBase,
      payload: <String, dynamic>{'avatar': avatar, 'name': name, 'age': age},
    );
  }

  static Action updateJobAction(String company, String job, String detail) {
    return Action(
      PageAction.updateJob,
      payload: <String, dynamic>{'company': company, 'job': job, 'detail': detail},
    );
  }

  static Action onRefreshAction() {
    return Action(
      PageAction.onRefresh,
    );
  }

}
  • view.dart
Widget buildView(PageState state,  dispatch, ViewService viewService) {
  print('_buildView');
  return Scaffold(
    appBar: AppBar(title: Text('個人信息'),),

    body: Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        Card(
          margin: EdgeInsets.all(15),
          child: Padding(
            padding: EdgeInsets.all(20),
            child: Row(
              children: <Widget>[
                FadeInImage.assetNetwork(
                  placeholder: 'images/timg.jpg',
                  image: state.avatar ?? '',
                  height: 60,
                  width: 60,
                ),
                Padding(
                  padding: EdgeInsets.only(left: 30),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Text(state.name ?? ''),
                      Padding(
                        padding: EdgeInsets.only(top: 10),
                        child: Text(state.age == null ? '' : state.age.toString()),
                      )
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),

        Card(
          margin: EdgeInsets.all(15),
          child: Padding(
            padding: EdgeInsets.all(20),
            child: MyExpand(
              <Widget>[
                Text('公司:${state.company}'),
                Padding(
                  padding: EdgeInsets.only(top: 10),
                  child: Text('職位:${state.job}'),
                ),
                Padding(
                  padding: EdgeInsets.only(top: 10),
                  child: Text('詳情:${state.detail}'),
                )
              ],
            ),
          ),
        ),

      ],
    ),

    floatingActionButton: FloatingActionButton(
        child: Icon(Icons.refresh),
        onPressed: (){
          dispatch(PageActionCreator.onRefreshAction());
        }
        ),
  );
}
  • 這里MyExpand 是我們自定義的一個可收縮伸展的控件
import 'package:flutter/material.dart';

class MyExpand extends StatefulWidget {

  final List<Widget> widgets;

//  MyExpand(this.widgets):super(){
//    assert(widgets != null && widgets.length > 2);
//  };

  MyExpand(this.widgets);

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return MyExpandState();
  }
}

class MyExpandState extends State<MyExpand> {

  bool expand = false;
  List<Widget> widgets = <Widget>[];

  @override
  void initState() {
    super.initState();
//    widgets = widget.widgets;
  }

  @override
  Widget build(BuildContext context) {
    if(expand == true) {
      widgets.clear();
      widgets.addAll(widget.widgets);
    } else {
      widgets.clear();
      widgets.add(widget.widgets[0]);
      widgets.add(widget.widgets[1]);
    }
    return Stack(
      children: <Widget>[
        Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: widgets,
        ),
        Align(
          alignment: Alignment.topRight,
          child: IconButton(
            icon: Icon(expand == true ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down),
            onPressed: () {
              setState(() {
                expand = !expand;
              });
            },
          ),
        ),

      ],
    );
  }

}
  • effect.dart
Effect<PageState> buildEffect() {
  return combineEffects(<Object, Effect<PageState>>{
    Lifecycle.initState: _init,
    PageAction.onRefresh: _onRefresh,
  });
}


void _init(Action action, Context<PageState> ctx) {
  println("Effect: _init");

  _getBaseInfo().then((_){
    ctx.dispatch(PageActionCreator.updateBaseAction(_.avatar, _.name, _.age));
  });

  _getJobInfo().then((_){
    ctx.dispatch(PageActionCreator.updateJobAction(_.company, _.job, _.detail));
  });


}

Future<BaseInfo> _getBaseInfo() async { //模擬通過網(wǎng)絡(luò)獲取基本信息
  return BaseInfo('http://b-ssl.duitang.com/uploads/item/201510/08/20151008192345_uPC5U.jpeg', '小恐龍', 24);
}

Future<JobInfo> _getJobInfo() async { //模擬通過網(wǎng)絡(luò)獲取工作信息
  return JobInfo('xxx傳媒有限公司', '設(shè)計師', 'woshixiangqing');
}

void _onRefresh(Action action, Context<PageState> ctx) {
  _getBaseInfo().then((_){
    ctx.dispatch(PageActionCreator.updateBaseAction(_.avatar, _.name, _.age));
  });
}
  • 添加兩個model類
class BaseInfo {
  String avatar;
  String name;
  int age;
  BaseInfo(this.avatar, this.name, this.age);
}

class JobInfo {
  String company;
  String job;
  String detail;
  JobInfo(this.company, this.job, this.detail);
}

實現(xiàn)效果如下


2. 使用component的實現(xiàn)

下面使用Component進(jìn)行改造

2.1 改造基本信息

2.1.1 添加BaseComponent

在info_page 文件夾下面添加base_component文件夾娱俺,由于基本信息塊只顯示信息沒有動作事件稍味,只需添加state, component, view三個文件

  • Component與Page類似,實際上Page是Component的子類
class BaseComponent extends Component<BaseState> {

  BaseComponent():super(
    view: buildView,
  );
}
  • BaseState只有頭像荠卷,名稱模庐,年齡三個屬性
class BaseState implements Cloneable<BaseState> {

  String avatar;
  String name;
  int age;

  BaseState();

  @override
  BaseState clone() {
    return BaseState()..avatar = avatar
    ..name = name
      ..age = age
    ;
  }

}


BaseState initState(Map<String, dynamic> params) {
  return BaseState();
}
  • view從Page的view中抽取
Widget buildView(
  BaseState state,
  Dispatch dispatch,
  ViewService viewService,
) {
  return Card(
    margin: EdgeInsets.all(15),
    child: Padding(
      padding: EdgeInsets.all(20),
      child: Row(
        children: <Widget>[
          FadeInImage.assetNetwork(
            placeholder: 'images/timg.jpg',
            image: state.avatar ?? '',
            height: 60,
            width: 60,
          ),
          Padding(
            padding: EdgeInsets.only(left: 30),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(state.name ?? ''),
                Padding(
                  padding: EdgeInsets.only(top: 10),
                  child: Text(state.age == null ? '' : state.age.toString()),
                )
              ],
            ),
          ),
        ],
      ),
    ),
  );
}

2.1.2 實現(xiàn)BaseComponent與Page的連接

在info_page下的state文件實現(xiàn)BaseConnector,BaseConnector繼承自ConnOp油宜,復(fù)寫get和set方法掂碱,get方法數(shù)據(jù)從page傳到Component怜姿,set方法數(shù)據(jù)從Component傳到page。

class BaseConnector extends ConnOp<PageState, BaseState> {
  @override
  BaseState get(PageState page) {
    final BaseState sub = BaseState();
    sub.avatar = page.avatar;
    sub.name = page.name;
    sub.age = page.age;
    return sub;
  }

  @override
  void set(PageState page, BaseState sub) {
    page.avatar = sub.avatar;
    page.name = sub.name;
    page.age = sub.age;
  }
}

在info_page的page文件下添加dependencies

class InfoPage extends Page<PageState, Map<String, dynamic>> {
  InfoPage() :super(
    initState: initState,
    effect: buildEffect(),
    view: buildView,
    reducer: buildReducer(),
    dependencies: Dependencies<PageState>(
        slots: <String, Dependent<PageState>>{
          'base': BaseConnector() + BaseComponent()
        }),
  );
}

在info_page的view文件下疼燥,將剛剛基本信息塊用下面的代碼代替

viewService.buildComponent('base'),

重啟應(yīng)用沧卢,效果還是和原來一樣

2.2 改造工作信息塊

與2.1基本相同
未完待續(xù)...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市醉者,隨后出現(xiàn)的幾起案子但狭,更是在濱河造成了極大的恐慌,老刑警劉巖撬即,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件立磁,死亡現(xiàn)場離奇詭異,居然都是意外死亡剥槐,警方通過查閱死者的電腦和手機(jī)唱歧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來才沧,“玉大人迈喉,你說我怎么就攤上這事∥略玻” “怎么了挨摸?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岁歉。 經(jīng)常有香客問我得运,道長,這世上最難降的妖魔是什么锅移? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任熔掺,我火速辦了婚禮,結(jié)果婚禮上非剃,老公的妹妹穿的比我還像新娘置逻。我一直安慰自己,他們只是感情好备绽,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布券坞。 她就那樣靜靜地躺著,像睡著了一般肺素。 火紅的嫁衣襯著肌膚如雪恨锚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天倍靡,我揣著相機(jī)與錄音猴伶,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛他挎,可吹牛的內(nèi)容都是我干的筝尾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼雇盖,長吁一口氣:“原來是場噩夢啊……” “哼忿等!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起崔挖,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤贸街,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后狸相,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體薛匪,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年脓鹃,在試婚紗的時候發(fā)現(xiàn)自己被綠了逸尖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瘸右,死狀恐怖娇跟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情太颤,我是刑警寧澤苞俘,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站龄章,受9級特大地震影響吃谣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜做裙,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一岗憋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锚贱,春花似錦仔戈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卦绣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間飞蚓,已是汗流浹背滤港。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溅漾。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓山叮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親添履。 傳聞我的和親對象是個殘疾皇子屁倔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354