CardView中的展开/折叠动画

14

我试着做这样的事情:

enter image description here

我成功地编写了我的cardViewAdapter,但是我在放大我的卡片时遇到了困难。我参考了这个回答的代码(这里类的名称为:CardsAnimationHelper)来制作动画,但是它被叠加了。

在展开之前:picture 展开后:picture

我解决了上面的问题,但是如果我在CardView上同时显示10个元素,列表中有50个元素。 如果我展开第一个,则11、21、31、41数字也会扩展。 你有什么技巧可以避免这种情况发生吗?

我反思了一下,对我来说这没有任何意义。 在我的OnClick方法之前,我显示一个文本视图,其中文本是位置。 但是当我单击时,ID是正确的,这意味着当我单击它时,它检测到了多张卡片的点击。 我想我在OnClickListener中可能有一个视图问题

我的CardView

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView 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"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"

        app:cardBackgroundColor="@android:color/white"
        app:cardCornerRadius="2dp"
        app:cardElevation="2dp">

        <!-- Les CardView possèdent des attributs supplémentaires dont
             - cardBackgroundColor
             - cardElevation pour l'élévation (donc aussi l'ombre)
             - cardCornerRadius pour arrondir les angles
         -->

        <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <!-- Les CardView agissent comme des FrameLayout,
             pour avoir une organisation verticale nous devons
             donc rajouter un LinearLayout -->


            <TextView
                android:id="@+id/text_cards"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?android:selectableItemBackground"
                android:padding="20dp"
                tools:text="Paris"
                android:fontFamily="sans-serif"
                android:textColor="#333"
                android:textSize="18sp" />

            <ImageView
                android:id="@+id/item_description_game_more"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical|end"
                android:transitionName="@string/transition_cards_view"
                app:srcCompat="@drawable/ic_expand_more_black_24dp"/>

            <include layout="@layout/cards_resume_game_expand"/>

        </android.support.design.widget.CoordinatorLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

我的新适配器

public class CardsViewAdapter extends RecyclerView.Adapter<CardsViewAdapter.ViewHolder> {
    private Game[] mDataset;
    private boolean isPopupVisible = false;
    int rotationAngle = 0;

    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public static class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView mTextView;
        public ImageView imageView;
        public LinearLayout test2;

        public ViewHolder(View v) {
            super(v);
            mTextView = (TextView) v.findViewById(R.id.text_cards);
            imageView = (ImageView) v.findViewById(R.id.item_description_game_more);
            test2 = (LinearLayout) v.findViewById(R.id.popup_layout);

        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public CardsViewAdapter(Game[] myDataset) {
        mDataset = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public CardsViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cards_resume_game, parent, false);
        // set the view's size, margins, paddings and layout parameters
        //...

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element

        holder.mTextView.setText(String.valueOf(mDataset[position].getId_game()));
        holder.imageView.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Perform action on click
                if (isPopupVisible) {
                    isPopupVisible = false;

                    ObjectAnimator anim = ObjectAnimator.ofFloat(v, "rotation",rotationAngle, rotationAngle + 180);
                    anim.setDuration(500);
                    anim.start();
                    rotationAngle += 180;
                    rotationAngle = rotationAngle%360;

//                    CardsAnimationHelper.changeIconAnim((TextView) v, getString(R.string.icon_chevron_up));
                    CardsAnimationHelper.collapse(holder.test2);
                } else {
                    isPopupVisible = true;

                    ObjectAnimator anim = ObjectAnimator.ofFloat(v, "rotation",rotationAngle, rotationAngle + 180);
                    anim.setDuration(500);
                    anim.start();
                    rotationAngle += 180;
                    rotationAngle = rotationAngle%360;

//                    CardsAnimationHelper.changeIconAnim((TextView) v, getString(R.string.icon_chevron_down));
                    CardsAnimationHelper.expand(holder.test2);
                }
            }
        });



    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}

你尝试过使用 CardsAnimationHelper.collapse(v);CardsAnimationHelper.expand(v); 吗? - Suraj Rao
1
这里您只发送了TextView而没有发送卡片。 - Suraj Rao
@SurajRao 确实,这是我的错误,但现在已经叠加了: 展开之前:http://imgur.com/a/8uIsx 展开之后:http://imgur.com/a/VVz7g - filol
可能是展开和折叠CardView的重复问题。 - Madhur
2个回答

18

我不明白您所说的显示50个元素中的10个是什么意思。但是,您可以通过显示/隐藏视图并在CardView的子布局中提供android:animateLayoutChanges="true"来实现展开/折叠。以下是一个示例:

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:animateLayoutChanges="true"
        android:padding="16dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/hello"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"/>

        <TextView
            android:id="@+id/hello2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            android:visibility="gone"/>

        <TextView
            android:id="@+id/hello3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            android:visibility="gone"/>

    </LinearLayout>
</android.support.v7.widget.CardView>

相应的控制器:

    TextView t1 = (TextView) findViewById(R.id.hello);
    final TextView t2 = (TextView) findViewById(R.id.hello2);
    final TextView t3 = (TextView) findViewById(R.id.hello3);

    t1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (t2.getVisibility() == View.GONE) {
                t2.setVisibility(View.VISIBLE);
                t3.setVisibility(View.VISIBLE);
            } else {
                t2.setVisibility(View.GONE);
                t3.setVisibility(View.GONE);
            }
        }
    });

点击第一个TextView将折叠和展开CardView,并伴随着动画效果。


2
老兄,你应该喝一杯啤酒!太简单而优美了。我刚浪费了4-5个小时。 - AkshayT
1
android:animateLayoutChanges="true" 真的很好用啊! - sud007

13

您需要创建一个自定义类,继承 CardView。在该类内部放置以下方法:

public void expand() {
    int initialHeight = getHeight();

    measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    int targetHeight = getMeasuredHeight();

    int distanceToExpand = targetHeight - initialHeight;

    Animation a = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if (interpolatedTime == 1){
                // Do this after expanded
            }

            getLayoutParams().height = (int) (initialHeight + (distanceToExpand * interpolatedTime));
            requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    a.setDuration((long) distanceToExpand);
    startAnimation(a);
}

public void collapse(int collapsedHeight) {
    int initialHeight = getMeasuredHeight();

    int distanceToCollapse = (int) (initialHeight - collapsedHeight);

    Animation a = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if (interpolatedTime == 1){
                // Do this after collapsed
            }


            Log.i(TAG, "Collapse | InterpolatedTime = " + interpolatedTime);

            getLayoutParams().height = (int) (initialHeight - (distanceToCollapse * interpolatedTime));
            requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    a.setDuration((long) distanceToCollapse);
    startAnimation(a);
}

请注意,当你折叠它时,你需要传递想要折叠后的高度信息。展开时的高度设置为WRAP_CONTENT
我还添加了if/else语句,当动画完成时运行。
祝你好运!

我已经有这个类(请参见我的帖子中的链接):https://dev59.com/CW445IYBdhLWcg3wR4RN#13381228 - filol
你需要只有一个能扩展的CardView布局。在扩展和收缩时,你可以根据它是展开还是折叠来隐藏或显示想要隐藏或显示的视图。例如,在它折叠时显示头部,并在显示头部的过程中隐藏头部并显示内容。 - LukeWaggoner
1
然而,我在我的cardView中同时显示了10个元素,用于显示50个列表。如果我展开第一个,数字11、21、31和41也会展开。你有什么技巧可以防止这种情况发生吗? - filol
我已经反思了,但对我来说毫无意义。就在我的OnClick方法之前,我显示一个文本视图,其中文本是位置。但当我单击时,ID是正确的,这意味着当我单击时,它检测到了对几张卡片的单击。 - filol
我需要看一下你的CardsAnimationHelper才能确定,但我认为问题出在你的ViewHolder类是静态的。你已经实例化并将其作为ViewHolder传递了,所以你不需要它是静态的,而且将其设置为非静态可以让你调用一个特定卡片的方法,而不是多个卡片的方法。 - LukeWaggoner
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接