【问题标题】:TransitionManager doesn't animate color changeTransitionManager 不会为颜色变化设置动画
【发布时间】:2018-03-12 05:00:09
【问题描述】:

我关注了Nick Butcher's Material Improvements I/O 2016 talk,大约在 6:00,他开始谈论动画列表项。我已经完全按照他的做法实现了该功能,并且绑定的变化动画正确,但颜色变化没有动画,尽管他明确表示会这样做:

这就是代码的样子:

这是RecyclerView.Adapter类的相关部分:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val item: Pair<String, String> = items[position]

    holder.title.text = item.first
    holder.subtitle.text = item.second

    val isExpanded = position == expandedPosition
    holder.subtitle.visibility = if (isExpanded) View.VISIBLE else View.GONE
    holder.itemView.isActivated = isExpanded
    holder.itemView.setOnClickListener {
        expandedPosition = if (isExpanded) -1 else position
        TransitionManager.beginDelayedTransition(recyclerView)
        notifyDataSetChanged()
    }
}

这是我用于项目的布局。 ConstraintLayout 对于当前的布局设置来说有点矫枉过正,但我​​减少了布局以创建一个最小的示例。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/item_background"
    android:stateListAnimator="@animator/item_elevation"
    android:padding="8dp">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        tools:text="Title 1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>

    <TextView
        android:id="@+id/subtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:text="Subtitle 1"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintStart_toStartOf="parent"
        />

</android.support.constraint.ConstraintLayout>

这是我用于项目布局的背景:

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:enterFadeDuration="@android:integer/config_mediumAnimTime"
    android:exitFadeDuration="@android:integer/config_mediumAnimTime">

    <item android:state_activated="true"
        android:drawable="@color/colorAccent" />

    <item android:drawable="@color/colorPrimaryDark" />

</selector>

【问题讨论】:

  • Gif 不起作用:-/
  • @azizbekian 很遗憾听到这个消息,也许它不起作用,因为您正在移动设备上查看...
  • 背景可绘制对象与ConstraintLayout 一起工作,无需调用TransitionManager。我想知道您使用的是哪个视图组。你能发布你的布局吗?

标签: android android-layout android-recyclerview material-design android-animation


【解决方案1】:

确保您的数据集具有稳定的 ID,并致电 Recycler.Adapter#setHasStableIds(true)。看 setHasStableIds().

您还需要在适配器中覆盖 getItemId() 以返回稳定的 ID。另请参阅notifyDataSetChanged,了解有关稳定 ID 的简短讨论。

当使用此方法时,RecyclerView 将尝试为适配器报告它们具有稳定 ID 的可见结构更改事件。这有助于动画和视觉对象持久性的目的,但仍需要重新绑定和重新排列各个项目视图。

这是一个将 stable id 设置为 false 的演示:

并且稳定的 id 设置为 true。我已经让颜色变化的过渡时间很长,所以它会很明显。

RecyclerViewAdapter.java

这是演示中使用的适配器。 TransitionManager.beginDelayedTransition(mRecyclerView) 已被移除,以便 RecyclerView 更好地处理动画。

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    RecyclerViewAdapter() {
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        return new ItemViewHolder(view);
    }

    private int mExpandedPosition = RecyclerView.NO_POSITION;

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        final ItemViewHolder vh = (ItemViewHolder) holder;
        final TextView subTitle = vh.mSubTitle;

        vh.mTitle.setText(titleForPosition(position));
        subTitle.setText(subTitleForPosition(position));

        final boolean isExpanded = position == mExpandedPosition;

        subTitle.setVisibility((isExpanded) ? View.VISIBLE : View.GONE);
        holder.itemView.setActivated(isExpanded);
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mExpandedPosition = isExpanded ? RecyclerView.NO_POSITION : vh.getAdapterPosition();
                notifyDataSetChanged();
            }
        });
    }

    private String titleForPosition(int position) {
        return "Title " + position;
    }

    private String subTitleForPosition(int position) {
        return "Subtitle " + position;
    }

    @Override
    public int getItemCount() {
        return 5;
    }

    @Override
    public long getItemId(int position) {
        return titleForPosition(position).hashCode();
    }

    static class ItemViewHolder extends RecyclerView.ViewHolder {
        private final TextView mTitle;
        private final TextView mSubTitle;

        ItemViewHolder(View itemView) {
            super(itemView);
            mTitle = itemView.findViewById(R.id.title);
            mSubTitle = itemView.findViewById(R.id.subtitle);
        }
    }

    @SuppressWarnings("unused")
    private final static String TAG = "RecyclerViewAdapter";
}

【讨论】:

  • 不幸的是,设置setHasStableIds 会在调整视图大小时导致明显的重叠。看起来当前选定的项目从列表中消失了,然后从列表的开头或结尾开始动画。我将在问题中发布我的布局...
  • @AleksandarStefanović 从适配器中删除TransitionManager.beginDelayedTransition(mRecyclerView) 并让RecyclerView 做它的事情。颜色过渡问题解决了吗?
  • 删除 beginDelayedTransition 修复了奇怪的调整大小动画,但颜色变化仍然没有动画。
  • @AleksandarStefanović 你的稳定ID设置了吗?你为getItemId()返回什么?
  • 是的,setHasStableIds 已启用。至于getItemId(),我使用的是数据数组中item的数据的哈希值,即items[position].name.hashCode().toLong()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
相关资源
最近更新 更多