Android Kotlin RecylerView 添加header Add a List Header

This is an EXTRA CREDIT exercise, so complete it if you’re up for a challenge!

In this exercise you’ll add a header to your RecyclerView. It has lots of steps, but when you’re done, your app will display a header as the first row of the list.

Let’s finish the adapter using DataItems. You can use this more advanced pattern when you have more than two types of views to hold in a RecyclerView.

At the bottom of SleepNightAdapter, add a sealed class called DataItem:

 sealed class DataItem {
     data class SleepNightItem(val sleepNight: SleepNight): DataItem() {
         override val id = sleepNight.nightId
     }

     object Header: DataItem() {
         override val id = Long.MIN_VALUE
     }

     abstract val id: Long
 }

Add the TextHolder class inside the SleepNightAdapter class.

 class TextViewHolder(view: View): RecyclerView.ViewHolder(view) {
       companion object {
           fun from(parent: ViewGroup): TextViewHolder {
               val layoutInflater = LayoutInflater.from(parent.context)
               val view = layoutInflater.inflate(R.layout.header, parent, false)
                return TextViewHolder(view)
           }
       }
 }

Update the declaration of SleepNightAdapter to support any type of view holder.
class SleepNightAdapter:
ListAdapter<SleepNight, RecyclerView.ViewHolder>(SleepNightDiffCallback())

Now let’s update ListAdapter to hold a list of DataItem instead of a list of SleepNight:
class SleepNightAdapter:
ListAdapter<DataItem, RecyclerView.ViewHolder>(SleepNightDiffCallback()) {}

Update your DiffCallback to handle DataItem instead of SleepNight:

 class SleepNightDiffCallback : DiffUtil.ItemCallback<DataItem>() {
     override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
         return oldItem.id == newItem.id
     }

     override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
         return oldItem == newItem
     }
 }

Then, to figure out what view type to return, add a check to see which type of item is in the list:
At the top of the file, before the class declaration, create variables for Header and SleepNight item types:

private val ITEM_VIEW_TYPE_HEADER = 0 
private val ITEM_VIEW_TYPE_ITEM = 1
Then override getItemViewType and return the correct item view type.

    override fun getItemViewType(position: Int): Int {
         return when (getItem(position)) {
             is DataItem.Header -> ITEM_VIEW_TYPE_HEADER
             is DataItem.SleepNightItem -> ITEM_VIEW_TYPE_ITEM
         }
    }

Change onCreateViewHolder’s return type to RecyclerView.ViewHolder, and update it to return the correct ITEM_VIEW_TYPE.

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType) {
        ITEM_VIEW_TYPE_HEADER -> TextViewHolder.from(parent)
        ITEM_VIEW_TYPE_ITEM -> ViewHolder.from(parent)
        else -> throw ClassCastException("Unknown viewType ${viewType}")
    }
 }

In onBindViewHolder() you’ll need to unwrap the DataItem to pass a SleepNight to the ViewHolder

 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    when (holder) {
        is ViewHolder -> {
            val nightItem = getItem(position) as DataItem.SleepNightItem
            holder.bind(nightItem.sleepNight, clickListener)
        }
    }
 }

You’ll need a way to convert a List to a List.

 private val adapterScope = CoroutineScope(Dispatchers.Default)
     fun addHeaderAndSubmitList(list: List<SleepNight>?) {
         adapterScope.launch {
             val items = when (list) {
                 null -> listOf(DataItem.Header)
                 else -> listOf(DataItem.Header) + list.map   DataItem.SleepNightItem(it) 
             }
        }
            withContext(Dispatchers.Main) {
         submitList(items)
        }
     }
 }

Finally, update SleepTrackerFragment to pass a list of DataItem instead of a list of SleepNight and call the new addHeaderAndSubmitList method instead of submitList method:

 sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
        it?.let {
            adapter.addHeaderAndSubmitList(it)
        }
 })

If you want to start at this step, you can download this exercise from: Step.13-Exercise-Add-a-List-Header.

You will find plenty of //TODO comments to help you complete this exercise, and if you get stuck, go back and watch the video again.

Once you’re done, you can check your solution against the solution we’ve provided here: Step.13-Solution-Add-a-List-Header, or using this git diff.

转载:https://learn.udacity.com/courses/ud9012/lessons/97c42668-51b8-454c-ba29-5ddfd2b92f6b/concepts/4392f247-36a7-42bb-9989-6957b795108c?lesson_tab=lesson

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值