当前位置:   article > 正文

Unity基于UIWidgets的UI入门(四简单的入门 Redux 架构应用实践)_unity ui weight

unity ui weight

Redux架构 是根据flutter来的

然后这节课是学习 TodoListApp 配置 Redux

添加 类TodoViewState

  1. public class TodoViewState
  2. {
  3. public TodoListApp.TodoListPageMode toDoListPageMode = TodoListApp.TodoListPageMode.List;
  4. }

然后修改 TodoListApp 类中的 createWidget方法

  1. protected override Widget createWidget()
  2. {
  3. var appWidget = new MaterialApp(home:
  4. new Scaffold(
  5. appBar: new AppBar(title: new Center(child: FQ.Text.Data("My App").SetSize(20).EndText()),
  6. backgroundColor: Color.black,
  7. // leading: new Icon(Icons.home),
  8. actions: new List<Widget>(){
  9. new IconButton(icon: new Icon(Icons.image,color:Colors.white)),
  10. new IconButton(icon: new Icon(Icons.image,color:Colors.white)),
  11. new PopupMenuButton<Choice>(
  12. onSelected: (choice)=> { Debug.Log(choice.title); },
  13. itemBuilder: (BuildContext subContext) => {
  14. List<PopupMenuEntry<Choice>> popupItems = new List<PopupMenuEntry<Choice>>();
  15. for (int i = 0; i < Choice.choices.Count; i++) {
  16. popupItems.Add(new PopupMenuItem<Choice>(
  17. value: Choice.choices[i],
  18. child: new Text(Choice.choices[i].title)));
  19. }
  20. return popupItems;
  21. }
  22. )
  23. }),
  24. drawer: new Drawer(
  25. child: FQ.ListView.Padding(EdgeInsets.zero).
  26. Child(new Divider()).
  27. Child(new ListTile(leading: new Icon(Icons.list),
  28. title: FQ.Text.Data("代办事项").EndText(), onTap: () =>
  29. {
  30. ViewState.todoListPageMode = TodoListPageMode.List;
  31. Debug.Log("点击了待办事项");
  32. ViewState.OnStateChange.Invoke();
  33. })).
  34. Child(new Divider()).
  35. Child(new ListTile(
  36. leading: new Icon(Icons.check_box),
  37. title: FQ.Text.Data("已完成事项").EndText(), onTap: () =>
  38. {
  39. Debug.Log("点击了已完成");
  40. ViewState.todoListPageMode = TodoListPageMode.Finished;
  41. ViewState.OnStateChange.Invoke();
  42. })
  43. ).Child(new Divider())
  44. .EndListView()
  45. ),
  46. body: new TodoListPage(),
  47. floatingActionButton: new FloatingActionButton(
  48. backgroundColor: Colors.redAccent,
  49. child: new Icon(Unity.UIWidgets.material.Icons.add_alert),
  50. onPressed: () => { Debug.Log("OnbuttonClick"); }
  51. )
  52. ));
  53. var store = new Store<TodoViewState>(reducer: (TodoViewState previousState, object action) =>
  54. {
  55. return previousState;
  56. }, initialState: new TodoViewState());
  57. var provider = new StoreProvider<TodoViewState>(store: store, child: appWidget);
  58. return provider;
  59. //return appWidget;
  60. }

现在就编译通过啦!

接着我们学习 使用 Redux 重构列表间的切换功能

这节课有点难理解

记住这样用就行 改的地方有点多 TodolistApp类的 createWidget方法

和 TodoListState的 build方法 我先把代码贴出来

这个类用来扩展UIWidgets

  1. using System;
  2. using System.Globalization;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Unity.UIWidgets.gestures;
  6. using Unity.UIWidgets.painting;
  7. using Unity.UIWidgets.widgets;
  8. using UnityEngine;
  9. using Color = Unity.UIWidgets.ui.Color;
  10. using Unity.UIWidgets.foundation;
  11. using Unity.UIWidgets.material;
  12. namespace MyTestUIWidgets.UIWidgets
  13. {
  14. public class FQ
  15. {
  16. public static ContainerBuild Container => new ContainerBuild();
  17. public static TextBuilder Text => new TextBuilder();
  18. public static ListViewBuilder ListView => new ListViewBuilder();
  19. public static EditableTextBuilder EditableText => new EditableTextBuilder();
  20. }
  21. public class ContainerBuild
  22. {
  23. private Widget mChild { get; set; }
  24. private Alignment mAlignment { get; set; }
  25. private Color mColor { get; set; }
  26. private EdgeInsets mMargin = EdgeInsets.zero;
  27. //可空参数
  28. private float? mWidth = null;
  29. private float? mHeight = null;
  30. public static ContainerBuild GetBuilder()
  31. {
  32. return new ContainerBuild();
  33. }
  34. public ContainerBuild Child(Widget _child)
  35. {
  36. mChild = _child;
  37. return this;
  38. }
  39. public ContainerBuild Color(Color _color)
  40. {
  41. mColor = _color;
  42. return this;
  43. }
  44. public ContainerBuild Margin(EdgeInsets _edgInsets)
  45. {
  46. mMargin = _edgInsets;
  47. return this;
  48. }
  49. public ContainerBuild Width(float _width)
  50. {
  51. mWidth = _width;
  52. return this;
  53. }
  54. public ContainerBuild Height(float height)
  55. {
  56. mHeight = height;
  57. return this;
  58. }
  59. public ContainerBuild Alignment(Alignment _alignment)
  60. {
  61. mAlignment = _alignment;
  62. return this;
  63. }
  64. private Color mBorderColor = null;
  65. public ContainerBuild Dec(Color color)
  66. {
  67. mBorderColor = color;
  68. return this;
  69. }
  70. public Container EndContainer()
  71. {
  72. return new Container(child: mChild,
  73. alignment: mAlignment,
  74. color: mColor,
  75. width: mWidth,
  76. height:mHeight,
  77. margin: mMargin,
  78. decoration:
  79. mBorderColor != null ? new BoxDecoration(border: Border.all(mBorderColor)) : null);
  80. }
  81. }
  82. public class TextBuilder
  83. {
  84. private string mData { get; set; }
  85. private TextStyle mStyle { get; set; } = new TextStyle();
  86. private int mFontSize { get; set; }
  87. public static TextBuilder GetBuilder()
  88. {
  89. return new TextBuilder();
  90. }
  91. public TextBuilder Data(string _data)
  92. {
  93. mData = _data;
  94. return this;
  95. }
  96. public TextBuilder SetTextStyle(TextStyle _style)
  97. {
  98. mStyle = _style;
  99. return this;
  100. }
  101. public TextBuilder SetSize(int _fountSize)
  102. {
  103. mFontSize = _fountSize;
  104. return this;
  105. }
  106. public Text EndText()
  107. {
  108. if (mFontSize == 0)
  109. {
  110. return new Text(data: mData);
  111. }
  112. else
  113. {
  114. return new Text(data: mData, style: new TextStyle(fontSize: mFontSize));
  115. }
  116. }
  117. }
  118. public class ListViewBuilder
  119. {
  120. List<Widget> mChildren = new List<Widget>();
  121. EdgeInsets mPadding = null;
  122. public static ListViewBuilder GetBuilder()
  123. {
  124. return new ListViewBuilder();
  125. }
  126. public ListViewBuilder Padding(EdgeInsets _madding)
  127. {
  128. mPadding = _madding;
  129. return this;
  130. }
  131. public ListViewBuilder Child(List<Widget> _children)
  132. {
  133. mChildren = _children;
  134. return this;
  135. }
  136. public ListViewBuilder Child(Widget _child)
  137. {
  138. mChildren.Add(_child);
  139. return this;
  140. }
  141. public ListViewBuilder Child(params Widget[] _childeen)
  142. {
  143. mChildren.AddRange(_childeen);
  144. return this;
  145. }
  146. public ListView EndListView()
  147. {
  148. return new ListView(children: mChildren, padding: mPadding);
  149. }
  150. }
  151. public static class GestureDetectorExtension
  152. {
  153. public static GestureDetector OnTap(this Widget _widget, GestureTapCallback onTap)
  154. {
  155. return new GestureDetector(child: _widget, onTap: onTap);
  156. }
  157. }
  158. public class EditableTextBuilder
  159. {
  160. private TextEditingController mInputController = new TextEditingController(text: "");
  161. private FocusNode mFocusNode = new FocusNode();
  162. public TextStyle mStyle = new TextStyle();
  163. public Color mCursorColor = Color.black;
  164. public float mFontSize;
  165. ValueChanged<string> mOnValueChanged = null;
  166. ValueChanged<string> mOnSubmit = null;
  167. public EditableTextBuilder OnValueChanged(ValueChanged<string> _onValueChanged)
  168. {
  169. mOnValueChanged = _onValueChanged;
  170. return this;
  171. }
  172. public EditableTextBuilder OnSubmit(ValueChanged<string> _onSubmit)
  173. {
  174. mOnSubmit = _onSubmit;
  175. return this;
  176. }
  177. public EditableTextBuilder SetInputController(TextEditingController _inputController, FocusNode _focusNode, TextStyle _style, Color _cursorColor)
  178. {
  179. mInputController = _inputController;
  180. mFocusNode = _focusNode;
  181. mStyle = _style;
  182. mCursorColor = _cursorColor;
  183. return this;
  184. }
  185. public EditableTextBuilder FontSize(float size)
  186. {
  187. mFontSize = size;
  188. return this;
  189. }
  190. public EditableTextBuilder GetBuilder()
  191. {
  192. return new EditableTextBuilder();
  193. }
  194. public EditableText EndEditableTextBuilder()
  195. {
  196. return new EditableText(
  197. controller: mInputController,
  198. focusNode: mFocusNode,
  199. style: mFontSize == 0 ? mStyle : new TextStyle(fontSize: mFontSize),
  200. cursorColor: mCursorColor,
  201. onChanged: mOnValueChanged,
  202. onSubmitted: mOnSubmit);
  203. }
  204. }
  205. }

项目中的扩展方法

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEngine;
  6. namespace MyTestUIWidgets.UIWidgets
  7. {
  8. public class TodoViewState
  9. {
  10. public TodoListApp.TodoListPageMode toDoListPageMode = TodoListApp.TodoListPageMode.List;
  11. }
  12. public class Todo
  13. {
  14. public string Content = string.Empty;
  15. public bool Finished = false;
  16. }
  17. public static class Model
  18. {
  19. public static List<Todo> Load()
  20. {
  21. //PlayerPrefs.DeleteAll();
  22. var toDoListContent = PlayerPrefs.GetString("TODO_LIST_KEY", string.Empty);
  23. var splitDatas = toDoListContent.Split(new[] { "@@@@" }, StringSplitOptions.None);
  24. return splitDatas.Where(data => !string.IsNullOrEmpty(data))
  25. .Select(toddData =>
  26. {
  27. var todo = new Todo();
  28. var todoSplitDatas = toddData.Split(new[] { "::::" }, StringSplitOptions.None);
  29. todo.Content = todoSplitDatas[0];
  30. if (todoSplitDatas.Length > 1)
  31. {
  32. todo.Finished = bool.Parse(todoSplitDatas[1]);
  33. }
  34. return todo;
  35. })
  36. .ToList();
  37. }
  38. public static void Save(this List<Todo> self)
  39. {
  40. StringBuilder stringBuilder = new StringBuilder();
  41. self.ForEach(
  42. data =>
  43. {
  44. stringBuilder.Append(data.Content);
  45. stringBuilder.Append("::::");
  46. stringBuilder.Append(data.Finished);
  47. stringBuilder.Append("@@@@");
  48. }
  49. );
  50. PlayerPrefs.SetString("TODO_LIST_KEY", stringBuilder.ToString());
  51. }
  52. }
  53. }

列表类

  1. using Color = Unity.UIWidgets.ui.Color;
  2. using Unity.UIWidgets.foundation;
  3. using System;
  4. using System.Collections.Generic;
  5. using MyTestUIWidgets.UIWidgets;
  6. using Unity.UIWidgets.painting;
  7. using Unity.UIWidgets.widgets;
  8. using UnityEngine;
  9. using Unity.UIWidgets.material;
  10. namespace MyTestUIWidgets.UIWidgets
  11. {
  12. public class TodoView : StatelessWidget
  13. {
  14. private readonly Todo mData;
  15. private readonly Action mOnFinish;
  16. private readonly Action mDelete;
  17. private readonly IconData mIcon;
  18. public TodoView(Todo data, Action onFinish, Action onDelete,IconData icon)
  19. {
  20. mData = data;
  21. mOnFinish = onFinish;
  22. mDelete = onDelete;
  23. mIcon=icon;
  24. }
  25. public override Widget build(BuildContext context)
  26. {
  27. return
  28. new ListTile(
  29. leading: new IconButton(icon: new Icon(icon: mIcon /* Icons.check_box_outline_blank */, color: Colors.blueAccent, size: 30), onPressed: () => { mOnFinish(); },iconSize:50),
  30. // .OnTap(() =>
  31. // {
  32. // }),
  33. // leading: new Text(data : "我是领导标题"),
  34. subtitle: new Text(data: DateTime.Now.ToString("yyyy年 m月 d日 HH:mm:ss ")),
  35. //trailing : new Text(data : "我是补充说明"),
  36. trailing: new IconButton(icon: new Icon(icon: Icons.delete_outline, color: Colors.redAccent, size: 30), onPressed: () => { mDelete(); },iconSize:50),
  37. // .OnTap(() =>
  38. // {
  39. // mDelete();
  40. // // mOnFinish();
  41. // }),
  42. title: FQ.Text.Data(mData.Content).SetSize(30).EndText());
  43. // FQ.Container
  44. // .Alignment(Alignment.center)
  45. // .Child(
  46. // FQ.Text
  47. // .Data(mData)
  48. // .SetSize(20).EndText()
  49. // )
  50. // .EndContainer().OnTap(() =>
  51. // {
  52. // mOnFinish();
  53. // }));
  54. }
  55. }
  56. public class TodoInputView : StatelessWidget
  57. {
  58. private string mInputContent = string.Empty;
  59. private Action<string> mOnAdd;
  60. public TodoInputView(Action<string> onAdd)
  61. {
  62. mOnAdd = onAdd;
  63. }
  64. public void AddTodo()
  65. {
  66. if (!string.IsNullOrWhiteSpace(mInputContent))
  67. {
  68. mOnAdd(mInputContent);
  69. }
  70. }
  71. public override Widget build(BuildContext context)
  72. {
  73. return
  74. new Container(child:
  75. new Row(children: new List<Widget>(){
  76. FQ.Container.Width(190).Height( 40 ).Dec(Colors.lightBlue).Margin(EdgeInsets.only(left :60))
  77. .Child(FQ.EditableText.FontSize(30)
  78. .OnValueChanged(mInputContent => { this.mInputContent = mInputContent; } )
  79. .OnSubmit(inputvalue => AddTodo())
  80. .EndEditableTextBuilder())
  81. .EndContainer(),
  82. new IconButton( icon: new Icon(Icons.add_box,size:40,color:Colors.green),onPressed:AddTodo),
  83. // FQ.Container.Child(
  84. // new Icon(Icons.add_box,size:40,color:Colors.green)
  85. // .OnTap(() => {
  86. // AddTodo();
  87. // Debug.Log("On Tap");})
  88. // ).Margin(EdgeInsets.only(left:30)).EndContainer()
  89. }
  90. ));
  91. }
  92. }
  93. }

 

这个类用来管理绘制UIPanel

  1. using System.Runtime.CompilerServices;
  2. using System.Xml.Linq;
  3. using System;
  4. using System.Text;
  5. using System.Linq;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using Unity.UIWidgets.engine;
  9. using Unity.UIWidgets.painting;
  10. using Unity.UIWidgets.widgets;
  11. using UnityEngine;
  12. using Color = Unity.UIWidgets.ui.Color;
  13. using MyTestUIWidgets.UIWidgets;
  14. using Unity.UIWidgets.foundation;
  15. using Unity.UIWidgets.animation;
  16. using Unity.UIWidgets.material;
  17. using Unity.UIWidgets.ui;
  18. using UnityEditor;
  19. using Unity.UIWidgets.Redux;
  20. using Unity.UIWidgets;
  21. namespace MyTestUIWidgets
  22. {
  23. class Choice
  24. {
  25. public Choice(string title, IconData icon)
  26. {
  27. this.title = title;
  28. this.icon = icon;
  29. }
  30. public readonly string title;
  31. public readonly IconData icon;
  32. public static List<Choice> choices = new List<Choice> {
  33. new Choice("Car", Unity.UIWidgets.material.Icons.directions_car),
  34. new Choice("Bicycle", Unity.UIWidgets.material.Icons.directions_bike),
  35. new Choice("Boat", Unity.UIWidgets.material.Icons.directions_boat),
  36. new Choice("Bus", Unity.UIWidgets.material.Icons.directions_bus),
  37. new Choice("Train", Unity.UIWidgets.material.Icons.directions_railway),
  38. new Choice("Walk", Unity.UIWidgets.material.Icons.directions_walk)
  39. };
  40. }
  41. public class TodoListApp : UIWidgetsPanel
  42. {
  43. protected override void OnEnable()
  44. {
  45. base.OnEnable();
  46. FontManager.instance.addFont(Resources.Load<Font>("MaterialIcons-Regular"), "Material Icons", fontWeight: FontWeight.normal);
  47. FontManager.instance.addFont(Resources.Load<Font>("GalleryIcons"), "GalleryIcons");
  48. }
  49. protected override Widget createWidget()
  50. {
  51. var appWidget = new MaterialApp(home:
  52. new Scaffold(
  53. appBar: new AppBar(title: new Center(child: FQ.Text.Data("My App").SetSize(20).EndText()),
  54. backgroundColor: Color.black,
  55. // leading: new Icon(Icons.home),
  56. actions: new List<Widget>(){
  57. new IconButton(icon: new Icon(Icons.image,color:Colors.white)),
  58. new IconButton(icon: new Icon(Icons.image,color:Colors.white)),
  59. new PopupMenuButton<Choice>(
  60. onSelected: (choice)=> { Debug.Log(choice.title); },
  61. itemBuilder: (BuildContext subContext) => {
  62. List<PopupMenuEntry<Choice>> popupItems = new List<PopupMenuEntry<Choice>>();
  63. for (int i = 0; i < Choice.choices.Count; i++) {
  64. popupItems.Add(new PopupMenuItem<Choice>(
  65. value: Choice.choices[i],
  66. child: new Text(Choice.choices[i].title)));
  67. }
  68. return popupItems;
  69. }
  70. )
  71. }),
  72. drawer: new Drawer(
  73. child: FQ.ListView.Padding(EdgeInsets.zero).
  74. Child(new Divider()).
  75. Child(
  76. new StoreConnector<TodoViewState, object>(
  77. converter: (state) => null,
  78. builder: (context, Model, disoatcher) =>
  79. {
  80. return new ListTile(leading: new Icon(Icons.list),
  81. title: FQ.Text.Data("代办事项").EndText(), onTap: () =>
  82. {
  83. disoatcher.dispatch("LIST_PAGE_MODE");
  84. // ViewState.todoListPageMode = TodoListPageMode.List;
  85. // Debug.Log("点击了待办事项");
  86. // ViewState.OnStateChange.Invoke();
  87. });
  88. }
  89. )
  90. ).
  91. Child(new Divider()).
  92. Child(
  93. new StoreConnector<TodoViewState, object>(
  94. converter: (state) => null,
  95. builder: (context, Model, disoatcher) =>
  96. {
  97. return new ListTile(
  98. leading: new Icon(Icons.check_box),
  99. title: FQ.Text.Data("已完成事项").EndText(), onTap: () =>
  100. {
  101. disoatcher.dispatch("FINISH_PAGE_MODE");
  102. // Debug.Log("点击了已完成");
  103. // ViewState.todoListPageMode = TodoListPageMode.Finished;
  104. // ViewState.OnStateChange.Invoke();
  105. });
  106. })).Child(new Divider())
  107. .EndListView()
  108. ),
  109. body: new TodoListPage(),
  110. floatingActionButton: new FloatingActionButton(
  111. backgroundColor: Colors.redAccent,
  112. child: new Icon(Unity.UIWidgets.material.Icons.add_alert),
  113. onPressed: () => { Debug.Log("OnbuttonClick"); }
  114. )
  115. ));
  116. var store = new Store<TodoViewState>(reducer: (TodoViewState previousState, object action) =>
  117. {
  118. Debug.Log(action);
  119. switch (action)
  120. {
  121. case "LIST_PAGE_MODE":
  122. return new TodoViewState() { toDoListPageMode = TodoListPageMode.List };
  123. case "FINISH_PAGE_MODE":
  124. return new TodoViewState() { toDoListPageMode = TodoListPageMode.Finished };
  125. }
  126. return previousState;
  127. }, initialState: new TodoViewState());
  128. var provider = new StoreProvider<TodoViewState>(store: store, child: appWidget);
  129. return provider;
  130. //return appWidget;
  131. }
  132. class TodoListPage : StatefulWidget
  133. {
  134. public override State createState()
  135. {
  136. return new TodoListState();
  137. }
  138. }
  139. public enum TodoListPageMode
  140. {
  141. List,
  142. Finished
  143. }
  144. class TodoListState : State<TodoListPage>
  145. {
  146. public override void initState()
  147. {
  148. mTodoDatas = Model.Load();
  149. }
  150. void OnChange()
  151. {
  152. this.setState(() => { });
  153. }
  154. private List<Todo> mTodoDatas = null;
  155. public override Widget build(BuildContext context)
  156. {
  157. return new StoreConnector<TodoViewState, TodoListPageMode>(converter: state => state.toDoListPageMode, builder: (buildContext, model, DispatcherImpl) =>
  158. {
  159. if (model == TodoListPageMode.List)
  160. {
  161. return FQ.ListView
  162. //.Child(new Text(data: "哈哈哈哈哈"))
  163. .Child(new TodoInputView(data => { AddState(data); }))
  164. .Child(ListTodoViews)
  165. .Padding(EdgeInsets.only(0, 50))
  166. .EndListView();
  167. }
  168. else
  169. {
  170. return FQ.ListView
  171. //.Child(new Text(data: "哈哈哈哈哈"))
  172. //.Child(new TodoInputView(data => { AddState(data); }))
  173. .Child(FinishedListView)
  174. .Padding(EdgeInsets.only(0, 50))
  175. .EndListView();
  176. }
  177. });
  178. }
  179. private void AddState(string data)
  180. {
  181. this.setState(() =>
  182. {
  183. mTodoDatas.Add(new Todo() { Content = data, Finished = false });
  184. Save();
  185. });
  186. }
  187. private void Save()
  188. {
  189. mTodoDatas.Save();
  190. }
  191. Widget[] FinishedListView
  192. {
  193. get
  194. {
  195. var retWidgets = new List<Widget>();
  196. foreach (var data in mTodoDatas.Where(data => data.Finished))
  197. {
  198. retWidgets.Add(new TodoView(data, () =>
  199. {
  200. this.setState(() =>
  201. {
  202. Debug.Log(data.Finished + "未设置");
  203. data.Finished = false;
  204. Debug.Log(data.Finished + "设置后");
  205. });
  206. Save();
  207. },
  208. () =>
  209. {
  210. this.setState(() =>
  211. {
  212. mTodoDatas.Remove(data);
  213. Save();
  214. });
  215. },Icons.check_box));
  216. retWidgets.Add(new Divider());
  217. }
  218. return retWidgets.ToArray();
  219. }
  220. }
  221. Widget[] ListTodoViews
  222. {
  223. get
  224. {
  225. var retWidgets = new List<Widget>();
  226. foreach (var data in mTodoDatas.Where(data => !data.Finished))
  227. {
  228. retWidgets.Add(new TodoView(data, () =>
  229. {
  230. this.setState(() =>
  231. {
  232. Debug.Log(data.Finished + "未设置");
  233. data.Finished = true;
  234. Debug.Log(data.Finished + "设置后");
  235. });
  236. Save();
  237. },
  238. () =>
  239. {
  240. this.setState(() =>
  241. {
  242. mTodoDatas.Remove(data);
  243. Save();
  244. });
  245. },Icons. check_box_outline_blank));
  246. retWidgets.Add(new Divider());
  247. }
  248. return retWidgets.ToArray();
  249. // return mTodoDatas.Where(data => !data.Finished).Select(data => new TodoView(data, () =>
  250. // {
  251. // this.setState(() =>
  252. // {
  253. // Debug.Log(data.Finished + "未设置");
  254. // data.Finished = true;
  255. // Debug.Log(data.Finished + "设置后");
  256. // });
  257. // Save();
  258. // }, () =>
  259. // {
  260. // this.setState(() =>
  261. // {
  262. // mTodoDatas.Remove(data);
  263. // Save();
  264. // });
  265. // })).ToArray();
  266. }
  267. }
  268. }
  269. }
  270. }

 Redux 中的单向数据流介绍

Redux 风格的文件夹整理

这种重构我有点不理解,现在用不到,也没做深入的研究

使用 Redux 重构 Todo 的完成和删除功能

中间件(Middleware)的使用与存储功能实现 ( 还是在Store构造的时候传入的)

使用 redux-thunk 中间件完成异步 action 的处理

这几节课学的我是云里雾里的。。熬

重构我直接贴代码了 新建一个文件夹叫Store

新建类Actions

Reducers

SaveMiddleware

TodoViewState

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEngine;
  6. namespace MyTestUIWidgets.UIWidgets
  7. {
  8. ///用来
  9. public class TodoViewState
  10. {
  11. public TodoListPageMode toDoListPageMode = TodoListPageMode.List;
  12. public List<Todo> TodoDatas = new List<Todo>();
  13. }
  14. }
  1. using Unity.UIWidgets;
  2. using UnityEngine;
  3. using MyTestUIWidgets;
  4. namespace MyTestUIWidgets.UIWidgets
  5. {
  6. public class SaveMiddleware
  7. {
  8. public static Middleware<State> create<State>() where State : TodoViewState
  9. {
  10. return (store) => (next) => new DispatcherImpl((action) =>
  11. {
  12. var previousState = store.getState();
  13. if (previousState == default)
  14. {
  15. previousState.TodoDatas = Model.Load();
  16. }
  17. var result = next.dispatch(action);
  18. var afterState = store.getState();
  19. afterState.TodoDatas.Save();
  20. return result;
  21. });
  22. }
  23. }
  24. }
  1. using System.Linq;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace MyTestUIWidgets.UIWidgets
  6. {
  7. public class Reducers : MonoBehaviour
  8. {
  9. public static TodoViewState Reduce(TodoViewState previousState, object action)
  10. {
  11. //Debug.Log(action);
  12. switch (action)
  13. {
  14. case ListPageModeAction _:
  15. return new TodoViewState() { toDoListPageMode = TodoListPageMode.List, TodoDatas = previousState.TodoDatas };
  16. case FinishedPageModeAction _:
  17. return new TodoViewState() { toDoListPageMode = TodoListPageMode.Finished, TodoDatas = previousState.TodoDatas };
  18. case AddTodoAction addTodoAction:
  19. var previousTodos = previousState.TodoDatas;
  20. previousTodos.Add(new Todo()
  21. {
  22. Content = addTodoAction.TodoContent
  23. });
  24. return new TodoViewState()
  25. {
  26. toDoListPageMode = previousState.toDoListPageMode,
  27. TodoDatas = previousTodos
  28. };
  29. case DeleteTodoAction deleteTodoAction:
  30. return new TodoViewState()
  31. {
  32. toDoListPageMode = previousState.toDoListPageMode,
  33. TodoDatas = previousState.TodoDatas.Where(todo => todo != deleteTodoAction.mTodo).ToList()
  34. };
  35. case FinishTodoAction finishTodoAction:
  36. return new TodoViewState()
  37. {
  38. toDoListPageMode = previousState.toDoListPageMode,
  39. TodoDatas = previousState.TodoDatas.
  40. Select(todo =>
  41. {
  42. if (todo == finishTodoAction.mTodo)
  43. {
  44. todo.Finished = true;
  45. }
  46. return todo;
  47. }).ToList()
  48. };
  49. case NetworkRequestAction networkRequestAction:
  50. Debug.Log(networkRequestAction.Result);
  51. return previousState;
  52. }
  53. return previousState;
  54. }
  55. }
  56. }
  1. using System.Net.Http;
  2. using Unity.UIWidgets.Redux;
  3. using Unity.UIWidgets.ui;
  4. namespace MyTestUIWidgets.UIWidgets
  5. {
  6. public class ListPageModeAction
  7. {
  8. }
  9. public class FinishedPageModeAction
  10. {
  11. }
  12. public class AddTodoAction
  13. {
  14. public string TodoContent { get; }
  15. public AddTodoAction(string todoContent)
  16. {
  17. TodoContent = todoContent;
  18. }
  19. }
  20. public class DeleteTodoAction
  21. {
  22. public readonly Todo mTodo;
  23. public DeleteTodoAction(Todo todo)
  24. {
  25. mTodo = todo;
  26. }
  27. }
  28. public class FinishTodoAction
  29. {
  30. public readonly Todo mTodo;
  31. public FinishTodoAction(Todo todo)
  32. {
  33. mTodo = todo;
  34. }
  35. }
  36. public class NetworkRequestAction
  37. {
  38. public string Result { get; set; }
  39. public static ThunkAction<TodoViewState> Create()
  40. {
  41. return new ThunkAction<TodoViewState>(action: (dispatcher, getState) =>
  42. {
  43. var client = new HttpClient();
  44. var task = client.GetAsync("http://baidu.com");
  45. task.GetAwaiter().OnCompleted(() =>
  46. {
  47. var contentTsak = task.Result.Content.ReadAsStringAsync();
  48. contentTsak.GetAwaiter().OnCompleted(() =>
  49. {
  50. dispatcher.dispatch(new NetworkRequestAction()
  51. {
  52. Result = contentTsak.Result
  53. });
  54. });
  55. });
  56. return null;
  57. });
  58. }
  59. }
  60. }
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEngine;
  6. namespace MyTestUIWidgets.UIWidgets
  7. {
  8. public class Todo
  9. {
  10. public string Content = string.Empty;
  11. public bool Finished = false;
  12. }
  13. public static class Model
  14. {
  15. public static List<Todo> Load()
  16. {
  17. //PlayerPrefs.DeleteAll();
  18. var toDoListContent = PlayerPrefs.GetString("TODO_LIST_KEY", string.Empty);
  19. var splitDatas = toDoListContent.Split(new[] { "@@@@" }, StringSplitOptions.None);
  20. return splitDatas.Where(data => !string.IsNullOrEmpty(data))
  21. .Select(toddData =>
  22. {
  23. var todo = new Todo();
  24. var todoSplitDatas = toddData.Split(new[] { "::::" }, StringSplitOptions.None);
  25. todo.Content = todoSplitDatas[0];
  26. if (todoSplitDatas.Length > 1)
  27. {
  28. todo.Finished = bool.Parse(todoSplitDatas[1]);
  29. }
  30. return todo;
  31. })
  32. .ToList();
  33. }
  34. public static void Save(this List<Todo> self)
  35. {
  36. StringBuilder stringBuilder = new StringBuilder();
  37. self.ForEach(
  38. data =>
  39. {
  40. stringBuilder.Append(data.Content);
  41. stringBuilder.Append("::::");
  42. stringBuilder.Append(data.Finished);
  43. stringBuilder.Append("@@@@");
  44. }
  45. );
  46. PlayerPrefs.SetString("TODO_LIST_KEY", stringBuilder.ToString());
  47. }
  48. }
  49. }
  1. using Color = Unity.UIWidgets.ui.Color;
  2. using Unity.UIWidgets.foundation;
  3. using System;
  4. using System.Collections.Generic;
  5. using MyTestUIWidgets.UIWidgets;
  6. using Unity.UIWidgets.painting;
  7. using Unity.UIWidgets.widgets;
  8. using UnityEngine;
  9. using Unity.UIWidgets.material;
  10. namespace MyTestUIWidgets.UIWidgets
  11. {
  12. public class TodoView : StatelessWidget
  13. {
  14. private readonly Todo mData;
  15. private readonly Action mOnFinish;
  16. private readonly Action mDelete;
  17. private readonly IconData mIcon;
  18. public TodoView(Todo data, Action onFinish, Action onDelete, IconData icon)
  19. {
  20. mData = data;
  21. mOnFinish = onFinish;
  22. mDelete = onDelete;
  23. mIcon = icon;
  24. }
  25. public override Widget build(BuildContext context)
  26. {
  27. return
  28. new ListTile(
  29. leading: new IconButton(icon: new Icon(icon: mIcon /* Icons.check_box_outline_blank */, color: Colors.blueAccent, size: 30), onPressed: () => { mOnFinish(); }, iconSize: 50),
  30. // .OnTap(() =>
  31. // {
  32. // }),
  33. // leading: new Text(data : "我是领导标题"),
  34. subtitle: new Text(data: DateTime.Now.ToString("yyyy年 m月 d日 HH:mm:ss ")),
  35. //trailing : new Text(data : "我是补充说明"),
  36. trailing: new IconButton(icon: new Icon(icon: Icons.delete_outline, color: Colors.redAccent, size: 30), onPressed: () => { mDelete(); }, iconSize: 50),
  37. // .OnTap(() =>
  38. // {
  39. // mDelete();
  40. // // mOnFinish();
  41. // }),
  42. title: FQ.Text.Data(mData.Content).SetSize(30).EndText());
  43. // FQ.Container
  44. // .Alignment(Alignment.center)
  45. // .Child(
  46. // FQ.Text
  47. // .Data(mData)
  48. // .SetSize(20).EndText()
  49. // )
  50. // .EndContainer().OnTap(() =>
  51. // {
  52. // mOnFinish();
  53. // }));
  54. }
  55. }
  56. public class TodoInputView : StatelessWidget
  57. {
  58. private string mInputContent = string.Empty;
  59. private Action<string> mOnAdd;
  60. public TodoInputView(Action<string> onAdd)
  61. {
  62. mOnAdd = onAdd;
  63. }
  64. public void AddTodo()
  65. {
  66. if (!string.IsNullOrWhiteSpace(mInputContent))
  67. {
  68. mOnAdd(mInputContent);
  69. }
  70. }
  71. public override Widget build(BuildContext context)
  72. {
  73. return
  74. new Container(child:
  75. new Row(children: new List<Widget>(){
  76. FQ.Container.Width(190).Height( 40 ).Dec(Colors.lightBlue).Margin(EdgeInsets.only(left :60))
  77. .Child(FQ.EditableText.FontSize(30)
  78. .OnValueChanged(mInputContent => { this.mInputContent = mInputContent; } )
  79. .OnSubmit(inputvalue => AddTodo())
  80. .EndEditableTextBuilder())
  81. .EndContainer(),
  82. new IconButton( icon: new Icon(Icons.add_box,size:40,color:Colors.green),onPressed:AddTodo),
  83. }
  84. ));
  85. }
  86. }
  87. }
  1. using System;
  2. using System.Globalization;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Unity.UIWidgets.gestures;
  6. using Unity.UIWidgets.painting;
  7. using Unity.UIWidgets.widgets;
  8. using UnityEngine;
  9. using Color = Unity.UIWidgets.ui.Color;
  10. using Unity.UIWidgets.foundation;
  11. using Unity.UIWidgets.material;
  12. namespace MyTestUIWidgets.UIWidgets
  13. {
  14. public class FQ
  15. {
  16. public static ContainerBuild Container => new ContainerBuild();
  17. public static TextBuilder Text => new TextBuilder();
  18. public static ListViewBuilder ListView => new ListViewBuilder();
  19. public static EditableTextBuilder EditableText => new EditableTextBuilder();
  20. }
  21. public class ContainerBuild
  22. {
  23. private Widget mChild { get; set; }
  24. private Alignment mAlignment { get; set; }
  25. private Color mColor { get; set; }
  26. private EdgeInsets mMargin = EdgeInsets.zero;
  27. //可空参数
  28. private float? mWidth = null;
  29. private float? mHeight = null;
  30. public static ContainerBuild GetBuilder()
  31. {
  32. return new ContainerBuild();
  33. }
  34. public ContainerBuild Child(Widget _child)
  35. {
  36. mChild = _child;
  37. return this;
  38. }
  39. public ContainerBuild Color(Color _color)
  40. {
  41. mColor = _color;
  42. return this;
  43. }
  44. public ContainerBuild Margin(EdgeInsets _edgInsets)
  45. {
  46. mMargin = _edgInsets;
  47. return this;
  48. }
  49. public ContainerBuild Width(float _width)
  50. {
  51. mWidth = _width;
  52. return this;
  53. }
  54. public ContainerBuild Height(float height)
  55. {
  56. mHeight = height;
  57. return this;
  58. }
  59. public ContainerBuild Alignment(Alignment _alignment)
  60. {
  61. mAlignment = _alignment;
  62. return this;
  63. }
  64. private Color mBorderColor = null;
  65. public ContainerBuild Dec(Color color)
  66. {
  67. mBorderColor = color;
  68. return this;
  69. }
  70. public Container EndContainer()
  71. {
  72. return new Container(child: mChild,
  73. alignment: mAlignment,
  74. color: mColor,
  75. width: mWidth,
  76. height:mHeight,
  77. margin: mMargin,
  78. decoration:
  79. mBorderColor != null ? new BoxDecoration(border: Border.all(mBorderColor)) : null);
  80. }
  81. }
  82. public class TextBuilder
  83. {
  84. private string mData { get; set; }
  85. private TextStyle mStyle { get; set; } = new TextStyle();
  86. private int mFontSize { get; set; }
  87. public static TextBuilder GetBuilder()
  88. {
  89. return new TextBuilder();
  90. }
  91. public TextBuilder Data(string _data)
  92. {
  93. mData = _data;
  94. return this;
  95. }
  96. public TextBuilder SetTextStyle(TextStyle _style)
  97. {
  98. mStyle = _style;
  99. return this;
  100. }
  101. public TextBuilder SetSize(int _fountSize)
  102. {
  103. mFontSize = _fountSize;
  104. return this;
  105. }
  106. public Text EndText()
  107. {
  108. if (mFontSize == 0)
  109. {
  110. return new Text(data: mData);
  111. }
  112. else
  113. {
  114. return new Text(data: mData, style: new TextStyle(fontSize: mFontSize));
  115. }
  116. }
  117. }
  118. public class ListViewBuilder
  119. {
  120. List<Widget> mChildren = new List<Widget>();
  121. EdgeInsets mPadding = null;
  122. public static ListViewBuilder GetBuilder()
  123. {
  124. return new ListViewBuilder();
  125. }
  126. public ListViewBuilder Padding(EdgeInsets _madding)
  127. {
  128. mPadding = _madding;
  129. return this;
  130. }
  131. public ListViewBuilder Child(List<Widget> _children)
  132. {
  133. mChildren = _children;
  134. return this;
  135. }
  136. public ListViewBuilder Child(Widget _child)
  137. {
  138. mChildren.Add(_child);
  139. return this;
  140. }
  141. public ListViewBuilder Child(params Widget[] _childeen)
  142. {
  143. mChildren.AddRange(_childeen);
  144. return this;
  145. }
  146. public ListView EndListView()
  147. {
  148. return new ListView(children: mChildren, padding: mPadding);
  149. }
  150. }
  151. public static class GestureDetectorExtension
  152. {
  153. public static GestureDetector OnTap(this Widget _widget, GestureTapCallback onTap)
  154. {
  155. return new GestureDetector(child: _widget, onTap: onTap);
  156. }
  157. }
  158. public class EditableTextBuilder
  159. {
  160. private TextEditingController mInputController = new TextEditingController(text: "");
  161. private FocusNode mFocusNode = new FocusNode();
  162. public TextStyle mStyle = new TextStyle();
  163. public Color mCursorColor = Color.black;
  164. public float mFontSize;
  165. ValueChanged<string> mOnValueChanged = null;
  166. ValueChanged<string> mOnSubmit = null;
  167. public EditableTextBuilder OnValueChanged(ValueChanged<string> _onValueChanged)
  168. {
  169. mOnValueChanged = _onValueChanged;
  170. return this;
  171. }
  172. public EditableTextBuilder OnSubmit(ValueChanged<string> _onSubmit)
  173. {
  174. mOnSubmit = _onSubmit;
  175. return this;
  176. }
  177. public EditableTextBuilder SetInputController(TextEditingController _inputController, FocusNode _focusNode, TextStyle _style, Color _cursorColor)
  178. {
  179. mInputController = _inputController;
  180. mFocusNode = _focusNode;
  181. mStyle = _style;
  182. mCursorColor = _cursorColor;
  183. return this;
  184. }
  185. public EditableTextBuilder FontSize(float size)
  186. {
  187. mFontSize = size;
  188. return this;
  189. }
  190. public EditableTextBuilder GetBuilder()
  191. {
  192. return new EditableTextBuilder();
  193. }
  194. public EditableText EndEditableTextBuilder()
  195. {
  196. return new EditableText(
  197. controller: mInputController,
  198. focusNode: mFocusNode,
  199. style: mFontSize == 0 ? mStyle : new TextStyle(fontSize: mFontSize),
  200. cursorColor: mCursorColor,
  201. onChanged: mOnValueChanged,
  202. onSubmitted: mOnSubmit);
  203. }
  204. }
  205. }
  1. using System.Runtime.CompilerServices;
  2. using System.Xml.Linq;
  3. using System;
  4. using System.Text;
  5. using System.Linq;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using Unity.UIWidgets.engine;
  9. using Unity.UIWidgets.painting;
  10. using Unity.UIWidgets.widgets;
  11. using UnityEngine;
  12. using MyTestUIWidgets.UIWidgets;
  13. using Unity.UIWidgets.foundation;
  14. using Unity.UIWidgets.animation;
  15. using Unity.UIWidgets.material;
  16. using Unity.UIWidgets.ui;
  17. using UnityEditor;
  18. using Unity.UIWidgets.Redux;
  19. using Unity.UIWidgets;
  20. namespace MyTestUIWidgets
  21. {
  22. public enum TodoListPageMode
  23. {
  24. List,
  25. Finished
  26. }
  27. class Choice
  28. {
  29. public Choice(string title, IconData icon)
  30. {
  31. this.title = title;
  32. this.icon = icon;
  33. }
  34. public readonly string title;
  35. public readonly IconData icon;
  36. public static List<Choice> choices = new List<Choice> {
  37. new Choice("Car", Unity.UIWidgets.material.Icons.directions_car),
  38. new Choice("Bicycle", Unity.UIWidgets.material.Icons.directions_bike),
  39. new Choice("Boat", Unity.UIWidgets.material.Icons.directions_boat),
  40. new Choice("Bus", Unity.UIWidgets.material.Icons.directions_bus),
  41. new Choice("Train", Unity.UIWidgets.material.Icons.directions_railway),
  42. new Choice("Walk", Unity.UIWidgets.material.Icons.directions_walk)
  43. };
  44. }
  45. public class TodoListApp : UIWidgetsPanel
  46. {
  47. protected override void OnEnable()
  48. {
  49. base.OnEnable();
  50. FontManager.instance.addFont(Resources.Load<Font>("MaterialIcons-Regular"), "Material Icons", fontWeight: FontWeight.normal);
  51. FontManager.instance.addFont(Resources.Load<Font>("GalleryIcons"), "GalleryIcons");
  52. }
  53. protected override Widget createWidget()
  54. {
  55. var appWidget = new MaterialApp(home:
  56. new Scaffold(
  57. appBar: new AppBar(title: new Center(child: FQ.Text.Data("My App").SetSize(20).EndText()),
  58. backgroundColor: Colors.black,
  59. // leading: new Icon(Icons.home),
  60. actions: new List<Widget>(){
  61. new IconButton(icon: new Icon(Icons.image,color:Colors.white)),
  62. new IconButton(icon: new Icon(Icons.image,color:Colors.white)),
  63. new PopupMenuButton<Choice>(
  64. onSelected: (choice)=> { Debug.Log(choice.title); },
  65. itemBuilder: (BuildContext subContext) => {
  66. List<PopupMenuEntry<Choice>> popupItems = new List<PopupMenuEntry<Choice>>();
  67. for (int i = 0; i < Choice.choices.Count; i++) {
  68. popupItems.Add(new PopupMenuItem<Choice>(
  69. value: Choice.choices[i],
  70. child: new Text(Choice.choices[i].title)));
  71. }
  72. return popupItems;
  73. }
  74. )
  75. }),
  76. drawer: new Drawer(
  77. child: FQ.ListView.Padding(EdgeInsets.zero).
  78. Child(new Divider()).
  79. Child(
  80. new StoreConnector<TodoViewState, object>(
  81. converter: (state) => null,
  82. builder: (context, Model, disoatcher) =>
  83. {
  84. return new ListTile(leading: new Icon(Icons.list),
  85. title: FQ.Text.Data("代办事项").EndText(), onTap: () =>
  86. {
  87. disoatcher.dispatch(new ListPageModeAction());
  88. });
  89. }
  90. )
  91. ).
  92. Child(new Divider()).
  93. Child(
  94. new StoreConnector<TodoViewState, object>(
  95. converter: (state) => null,
  96. builder: (context, Model, disoatcher) =>
  97. {
  98. return new ListTile(
  99. leading: new Icon(Icons.check_box),
  100. title: FQ.Text.Data("已完成事项").EndText(), onTap: () =>
  101. {
  102. disoatcher.dispatch(new FinishedPageModeAction());
  103. });
  104. })).Child(new Divider())
  105. .EndListView()
  106. ),
  107. body: new TodoListPage(),
  108. floatingActionButton: new FloatingActionButton(
  109. backgroundColor: Colors.redAccent,
  110. child: new Icon(Unity.UIWidgets.material.Icons.add_alert),
  111. onPressed: () => { Debug.Log("OnbuttonClick"); }
  112. )
  113. ));
  114. var store = new Store<TodoViewState>(reducer: Reducers.Reduce, initialState: new TodoViewState()
  115. {
  116. TodoDatas = Model.Load()
  117. } ,
  118. SaveMiddleware.create<TodoViewState>()
  119. ,ReduxThunk.create<TodoViewState>()
  120. );
  121. var provider = new StoreProvider<TodoViewState>(store: store, child: appWidget);
  122. return provider;
  123. //return appWidget;
  124. }
  125. class TodoListPage : StatefulWidget
  126. {
  127. public override State createState()
  128. {
  129. return new TodoListState();
  130. }
  131. }
  132. class TodoListState : State<TodoListPage>
  133. {
  134. void OnChange()
  135. {
  136. this.setState(() => { });
  137. }
  138. private List<Todo> mTodoDatas = null;
  139. public override Widget build(BuildContext context)
  140. {
  141. return new StoreConnector<TodoViewState, TodoViewState>(
  142. converter: state => state, builder: (buildContext, model, dispatcher) =>
  143. {
  144. if (model.toDoListPageMode == TodoListPageMode.List)
  145. {
  146. return FQ.ListView
  147. .Child(new IconButton(icon: new Icon(Icons.wifi),onPressed:()=>{
  148. dispatcher.dispatch(NetworkRequestAction.Create());
  149. }) )
  150. .Child(new TodoInputView(
  151. data =>
  152. {
  153. dispatcher.dispatch(new AddTodoAction(data));
  154. /* AddState(data); */
  155. }))
  156. .Child(ListTodoViews(model.TodoDatas, dispatcher))
  157. .Padding(EdgeInsets.only(0, 50))
  158. .EndListView();
  159. }
  160. else
  161. {
  162. return FQ.ListView
  163. .Child(FinishedListView(model.TodoDatas, dispatcher))
  164. .Padding(EdgeInsets.only(0, 50))
  165. .EndListView();
  166. }
  167. });
  168. }
  169. private void AddState(string data)
  170. {
  171. this.setState(() =>
  172. {
  173. mTodoDatas.Add(new Todo() { Content = data, Finished = false });
  174. Save();
  175. });
  176. }
  177. private void Save()
  178. {
  179. // mTodoDatas.Save();
  180. }
  181. Widget[] FinishedListView(List<Todo> Todos, Dispatcher dispatcher)
  182. {
  183. var retWidgets = new List<Widget>();
  184. foreach (var data in Todos.Where(data => data.Finished))
  185. {
  186. retWidgets.Add(new TodoView(data, () =>
  187. {
  188. dispatcher.dispatch(new FinishTodoAction(data));
  189. Save();
  190. },
  191. () =>
  192. {
  193. dispatcher.dispatch(new DeleteTodoAction(data));
  194. }, Icons.check_box));
  195. retWidgets.Add(new Divider());
  196. }
  197. return retWidgets.ToArray();
  198. }
  199. Widget[] ListTodoViews(List<Todo> Todos, Dispatcher dispatcher)
  200. {
  201. var retWidgets = new List<Widget>();
  202. foreach (var data in Todos.Where(data => !data.Finished))
  203. {
  204. retWidgets.Add(new TodoView(data, () =>
  205. {
  206. dispatcher.dispatch(new FinishTodoAction(data));
  207. Save();
  208. },
  209. () =>
  210. {
  211. dispatcher.dispatch(new DeleteTodoAction(data));
  212. }, Icons.check_box_outline_blank));
  213. retWidgets.Add(new Divider());
  214. }
  215. return retWidgets.ToArray();
  216. }
  217. }
  218. }
  219. }

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号