如何在RecyclerView中实现仿通知栏的点击及上下滑动展开收起效果
Hey there! Let me share a practical approach to implement the expand/collapse functionality for your RecyclerView notification items via vertical swipe and click—since you mentioned the previous solution didn’t meet your expectations.
Implementation Steps
1. Update Your Data Model
First, add a state flag to your notification data class to track whether an item is expanded or collapsed:
data class NotificationItem( val id: String, val title: String, val fullContent: String, var isExpanded: Boolean = false // Tracks expansion state )
2. Handle Vertical Swipe with ItemTouchHelper
Use ItemTouchHelper to intercept vertical swipe gestures and trigger state changes once a swipe threshold is met:
class VerticalSwipeHandler(private val swipeCallback: SwipeCallback) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.UP or ItemTouchHelper.DOWN) { interface SwipeCallback { fun onItemSwiped(position: Int) } override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false // We don't need drag-and-drop sorting here } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { // Trigger state toggle regardless of swipe direction (up/down) swipeCallback.onItemSwiped(viewHolder.adapterPosition) } override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float { // Set a threshold (e.g., 30% of item height) to trigger the swipe action return 0.3f } }
3. Build the Adapter with State Logic
In your RecyclerView Adapter, bind the state to the UI and handle both click and swipe-triggered state changes:
class NotificationAdapter(private val notifications: MutableList<NotificationItem>) : RecyclerView.Adapter<NotificationAdapter.NotificationViewHolder>() { inner class NotificationViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val titleTv: TextView = itemView.findViewById(R.id.tv_notification_title) val contentTv: TextView = itemView.findViewById(R.id.tv_notification_content) val rootLayout: ConstraintLayout = itemView.findViewById(R.id.root_layout) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_notification, parent, false) return NotificationViewHolder(view) } override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) { val item = notifications[position] holder.titleTv.text = item.title holder.contentTv.text = item.fullContent // Update UI based on expansion state if (item.isExpanded) { holder.contentTv.visibility = View.VISIBLE // Use wrap content to show full content holder.rootLayout.layoutParams = RecyclerView.LayoutParams( RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT ) } else { holder.contentTv.visibility = View.GONE // Set fixed height to only show the title section val collapsedHeight = holder.titleTv.measuredHeight + holder.itemView.paddingTop + holder.itemView.paddingBottom holder.rootLayout.layoutParams = RecyclerView.LayoutParams( RecyclerView.LayoutParams.MATCH_PARENT, collapsedHeight ) } // Toggle state on item click holder.itemView.setOnClickListener { toggleItemState(position) } } private fun toggleItemState(position: Int) { notifications[position].isExpanded = !notifications[position].isExpanded // Use local refresh to avoid full RecyclerView flicker notifyItemChanged(position) } // Expose method for swipe handler to trigger state toggle fun handleSwipe(position: Int) { toggleItemState(position) } override fun getItemCount() = notifications.size }
4. Connect Everything in Your Activity/Fragment
Initialize the RecyclerView, Adapter, and bind the swipe handler:
val recyclerView = findViewById<RecyclerView>(R.id.recycler_notifications) val notificationList = mutableListOf<NotificationItem>( // Populate your notification data here ) val adapter = NotificationAdapter(notificationList) recyclerView.adapter = adapter recyclerView.layoutManager = LinearLayoutManager(this) // Attach the vertical swipe handler val swipeHandler = VerticalSwipeHandler(object : VerticalSwipeHandler.SwipeCallback { override fun onItemSwiped(position: Int) { adapter.handleSwipe(position) } }) ItemTouchHelper(swipeHandler).attachToRecyclerView(recyclerView)
5. Optional Enhancements
- Add Animations: Use
ViewPropertyAnimatorto add smooth fade/height transitions when expanding/collapsing items. - Resolve Swipe Conflicts: If your item contains scrollable views, override
onInterceptTouchEventin a custom RecyclerView to prioritize vertical swipe gestures. - Persist State: Store expansion states in a
HashMap<String, Boolean>(mapping notification IDs to states) to retain state across configuration changes or pagination.
内容的提问来源于stack exchange,提问作者Kousalya
相关产品推荐
相关产品推荐

