我正在使用带有GridLayoutManager的RecyclerView.用户可以在2到4之间切换跨度计数,这将导致动画将每个单元格的内置翻译动画运行到其新位置.我到目前为止使用的代码是:
TransitionManager.beginDelayedTransition(moviesGridRecycler); gridLayoutManager.setSpanCount(NEW_SPAN_COUNT); adapter.notifyDataSetChanged();
这对我来说一直很好,但现在我需要为每个跨度计数设置不同的布局.为了支持这一点,我在RecyclerView中有2种视图类型,并且由于在移动到新的跨度计数时视图类型已更改,因此RecyclerView无法看到它是“相同”内容,并且未运行默认的转换动画.
如果我启用布局转换,我会获得视图输入动画,而不是查看位置更改动画.两个跨度计数的单元格视图的宽度和高度为match_parent和wrap_content.
作为替代方案,我尝试将所有新视图类型放在一起,只有一种视图类型.我有一个FrameLayout,它保存两个跨度计数的视图.在onBindViewHolder()中,我只是切换子视图的可见性.这也导致没有动画.
我跟着this thread和this one,但无法解决我的问题.
完整代码:
class ItemFragment : Fragment() { private var spanCount = 2 lateinit var recyclerView: RecyclerView lateinit var button: Button override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_item_list,container,false) recyclerView = view.findViewById(R.id.listView) recyclerView.apply { adapter = MyItemRecyclerViewAdapter(DummyContent.ITEMS,spanCount) layoutManager = GridLayoutManager(context,spanCount) addItemDecoration(RecyclerGridDecoration(context)) } button = view.findViewById(R.id.toggle) button.setOnClickListener { onToggle() } return view } fun onToggle() { spanCount = if (spanCount == 2) 4 else 2 TransitionManager.beginDelayedTransition(recyclerView) (recyclerView.layoutManager as GridLayoutManager).spanCount = spanCount (recyclerView.adapter!! as MyItemRecyclerViewAdapter).apply { span = spanCount notifyDataSetChanged() } } } class MyItemRecyclerViewAdapter( private val mValues: List<DummyItem>,var span: Int) : RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): ViewHolder { if (viewType == 2) { val view = LayoutInflater.from(parent.context) .inflate(R.layout.items_two,parent,false) return TwoViewHolder(view) } else { val view = LayoutInflater.from(parent.context) .inflate(R.layout.items_four,false) return FourViewHolder(view) } } override fun onBindViewHolder(holder: ViewHolder,position: Int) { val item = mValues[position] if (holder is TwoViewHolder) { holder.textTwo.text = item.content } else if (holder is FourViewHolder) { holder.textFour.text = item.content } } override fun getItemCount(): Int = mValues.size abstract inner class ViewHolder(mView: View) : RecyclerView.ViewHolder(mView) inner class TwoViewHolder(mView: View) : ViewHolder(mView) { val image: ImageView = mView.imageTwo val textTwo: TextView = mView.textTwo } inner class FourViewHolder(mView: View) : ViewHolder(mView) { val textFour: TextView = mView.textFour } override fun getItemViewType(position: Int): Int { return span } }
解决方法
我有一个问题的解决方案将您的切换功能更改为:
fun onToggle() { spanCount = if (spanCount == 2) 4 else 2 (recyclerView.adapter!! as MyItemRecyclerViewAdapter).apply { span = spanCount notifyDataSetChanged() } recyclerView.post(object:Runnable { public override fun run() { TransitionManager.beginDelayedTransition(recyclerView) (recyclerView.layoutManager as GridLayoutManager).spanCount = spanCount } }) }
在上面的代码中,我们首先更改recyclelerView的viewType,然后我们在RecyclerView UI Handler Queue上更改GridLayoutManager的spanCount,以便顺序实现两个UI操作.