13.13 用RecyclerView 来展示待办事项

下面我们来实现这个页面。

13.13 用RecyclerView 来展示待办事项 - 图1

首先,这个是主页面,对应 activity_main.xml 视图, 文件内容如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.design.widget.CoordinatorLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:app="http://schemas.android.com/apk/res-auto"
  5. xmlns:tools="http://schemas.android.com/tools"
  6. android:layout_width="match_parent"
  7. android:layout_height="match_parent"
  8. android:fitsSystemWindows="true"
  9. tools:context="com.easy.kotlin.mytodoapplication.MainActivity">
  10. <android.support.design.widget.AppBarLayout
  11. android:layout_width="match_parent"
  12. android:layout_height="wrap_content"
  13. android:theme="@style/AppTheme.AppBarOverlay">
  14. <android.support.v7.widget.Toolbar
  15. android:id="@+id/toolbar"
  16. android:layout_width="match_parent"
  17. android:layout_height="?attr/actionBarSize"
  18. android:background="?attr/colorPrimaryDark"
  19. app:popupTheme="@style/AppTheme.PopupOverlay" />
  20. </android.support.design.widget.AppBarLayout>
  21. <include layout="@layout/content_main" />
  22. <android.support.design.widget.FloatingActionButton
  23. android:id="@+id/fab"
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"
  26. android:layout_gravity="bottom|end"
  27. android:layout_margin="@dimen/fab_margin"
  28. app:srcCompat="@drawable/ic_content_add" />
  29. </android.support.design.widget.CoordinatorLayout>

我们的待办事项列表视图是fragment_todos.xml, 文件内容如下:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:app="http://schemas.android.com/apk/res-auto"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:paddingBottom="@dimen/activity_vertical_margin"
  7. android:paddingLeft="@dimen/activity_horizontal_margin"
  8. android:paddingRight="@dimen/activity_horizontal_margin"
  9. android:paddingTop="@dimen/activity_vertical_margin"
  10. tools:context=".TodosFragment"
  11. tools:showIn="@layout/activity_main">
  12. <co.moonmonkeylabs.realmrecyclerview.RealmRecyclerView
  13. android:id="@+id/todos_recycler_view"
  14. android:layout_width="match_parent"
  15. android:layout_height="match_parent"
  16. app:rrvEmptyLayoutId="@layout/empty_view"
  17. app:rrvIsRefreshable="false"
  18. app:rrvLayoutType="LinearLayout" />
  19. </RelativeLayout>

我们看下RealmRecyclerView的配置:

配置项 功能说明
app:rrvEmptyLayoutId 当列表为空的时候的显示页面
app:rrvIsRefreshable 是否支持下拉刷新,通过setOnRefreshListener 或 setRefreshing来进行事件处理
app:rrvLayoutType 配置LayoutManager,可选项是:LinearLayout,Grid,LinearLayoutWithHeaders等

下面我们来实现这个TodosFragment 。

首先新建TodosFragment类,继承如下面代码所示:

  1. class TodosFragment : Fragment(), TodoAdapter.TodoItemClickListener {
  2. @BindView(R.id.todos_recycler_view)
  3. lateinit var realmRecyclerView: RealmRecyclerView
  4. private var realm: Realm? = null
  5. ...
  6. }

其中,TodoAdapter是继承了RealmBasedRecyclerViewAdapter的适配器类。我们在 TodoAdapter 里面定义了一个视图持有类:

  1. inner class ViewHolder(view: View, private val clickListener: TodoItemClickListener?) :
  2. RealmViewHolder(view), View.OnClickListener {
  3. // Bind a field to the view for the specified ID. The view will automatically be cast to the field type
  4. @BindView(R.id.todo_item_todo_title)
  5. lateinit var todoTitle: TextView
  6. // val todoTitle: TextView by bindView(R.id.todo_item_todo_title)
  7. @BindView(R.id.todo_item_todo_content)
  8. lateinit var todoContent: TextView
  9. // val todoContent: TextView by bindView(R.id.todo_item_todo_content)
  10. init {
  11. // Bind annotated fields and methods
  12. ButterKnife.bind(this, view)
  13. view.setOnClickListener(this)
  14. }
  15. override fun onClick(v: View) {
  16. clickListener?.onClick(v, realmResults[adapterPosition])
  17. }
  18. }

在ViewHolder初始化 View 的时候,我们使用ButterKnife进行了绑定

  1. init {
  2. // Bind annotated fields and methods
  3. ButterKnife.bind(this, view)
  4. view.setOnClickListener(this)
  5. }

待办事项监听器类:

  1. interface TodoItemClickListener {
  2. fun onClick(caller: View, todo: Todo)
  3. }

我们在TodosFragment中实现这个方法:

  1. override fun onClick(caller: View, todo: Todo) {
  2. (activity as MainActivity).hideFab()
  3. val todoEditFragment = TodoEditFragment.newInstance(todo.id)
  4. activity.supportFragmentManager
  5. .beginTransaction()
  6. .replace(R.id.content_main, todoEditFragment, todoEditFragment.javaClass.getSimpleName())
  7. .addToBackStack(todoEditFragment.javaClass.getSimpleName())
  8. .commit()
  9. }

点击待办事项,把当前的content_main切换成编辑事项 EditFragment的视图。

然后我们在TodoAdapter中重写RealmBasedRecyclerViewAdapter的onCreateRealmViewHolder和onBindRealmViewHolder方法。

  1. override fun onCreateRealmViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
  2. val v = inflater.inflate(R.layout.todo_item, viewGroup, false)
  3. return ViewHolder(v, clickListener)
  4. }
  5. override fun onBindRealmViewHolder(viewHolder: ViewHolder, position: Int) {
  6. val todo = realmResults[position]
  7. viewHolder.todoTitle.setText(todo.title)
  8. viewHolder.todoTitle.fontFeatureSettings = "font-size:12px"
  9. viewHolder.todoTitle.setTextColor(Color.argb(255, 69, 106, 124))
  10. viewHolder.todoContent.setText(todo.content)
  11. }

我们在添加(保存)完事项的时候,回到之前的列表页面:

  1. private fun createTodoFrom(title: EditText, todoContent: EditText) {
  2. realm.beginTransaction()
  3. // Either update the edited object or create a new one.
  4. var t = todo ?: realm.createObject(Todo::class.java)
  5. t.id = todo?.id ?: UUID.randomUUID().toString()
  6. t.title = title.text.toString()
  7. t.content = todoContent.text.toString()
  8. realm.commitTransaction()
  9. activity.supportFragmentManager.popBackStack()
  10. }

当回退到待办事项列表的时候,我们在TodosFragment中的 onResume() 函数中来实现数据的更新展示:

  1. override fun onResume() {
  2. super.onResume()
  3. val todos = realm!!.where(Todo::class.java).findAll()
  4. Log.i(MY_TAG, "onResume: ${todos}")
  5. Log.i(MY_TAG, "onResume: realmRecyclerView = ${realmRecyclerView} ")
  6. val adapter = TodoAdapter(activity, todos, true, true, this)
  7. realmRecyclerView.setAdapter(adapter)
  8. }

其中,val todos = realm!!.where(Todo::class.java).findAll() 是去 Realm 数据库中查询出所有Todo对应的实体记录。

然后,通过适配器val adapter = TodoAdapter(activity, todos, true, true, this)把数据装配到RecyclerView中 realmRecyclerView.setAdapter(adapter)