In my last devlog for my productivity app Tempo, I discussed how I had created a CustomView for my Task object, how I would add them directly to my main ConstraintLayout, and how I fixed the layout by using LayoutParams.
In this post, I set out thinking how I was going to discuss implementing the “Add Task” functionality and managing the list of tasks in the MainActivity. However, fate it seems is not without a sense of irony. I knew that I wanted the tasks lined up into some sort of queue where it would start from the last task added and work backwards through the queue while the user is in the “flow state”. With Kotlin as my choice for this project I used a MutableList that holds my custom Task objects.
Creating the MutableList was easy enough by adding the following to the top of the MainActivity class:
private val taskMutableList = mutableListOf<Task>()
In this case taskMutableList
is a val
because we are creating the
MutableList object itself only once and then using its methods to modify it.
This way it ensures that we will not keep re-creating, replacing, or throwing
away the MutableList every time we want to change the contents.
Once I had that in place and started to think about how I was going to keep track of all the TaskViews on screen and scrolling them etc. etc. I immediately started to look for an improvement to the way I was displaying or managing the view. In comes the ListView (and by extension Adapters) to the rescue.
The ListView connects to an Adapter (such as an ArrayAdapter) that manages/controls access to a specific data source. In my case, I wanted to allow the ListView to display the contents of my taskMutableList and handle all of the layout and spacing for me. Naïvely, I added the ListView to my MainActivity and said something along the lines of:
taskListView.addView(TaskView(Task))
After which the project, unsurprisingly, failed to compile.
To get it to work I implemented TaskArrayAdapter
that extends the default
ArrayAdapter and overrides the getView()
method in order to return my own
TaskView to be displayed in the ListView. The actual TaskArrayAdapter’s
getView
looks something like this:
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val taskView = TaskView(parent!!.context)
taskView.populate(getItem(position))
return taskView
}
Once again, our nifty populate
is being used to fill the TaskView easily.
After creating the adapter, all that was left was to connect it to the ListView in the MainActivity by first creating the adapter, and then setting the ListView’s adapter:
listViewAdapter = TaskArrayAdapter(this, R.layout.view_task, taskMutableList)
taskListView.adapter = listViewAdapter
Now all we need to do when we want to update the list is to call
notifyDataSetChanged()
on our listViewAdapter
and the view should automatically
update itself. With the new system in place I stress tested it by adding a
bunch of tasks and was pleasantly surprised by how nicely it works using
Adapters. You can see how it looks below.
Although the layout is not perfect at this stage, it is functionally much better that before. As always, I will post an update when I work on it again, but until then, stay evil.