ListView 仅在第二次点击后才会展开条目的动画效果

8

我有一个包含以下视图的CardView:

- RelativeLayout (view_1)
    - TextView
    - TextView

- RelativeLayout (view_2)
    - ImageView
    - ImageView

当我打开我的ListView时,view_2被设置为Visible.GONE,所以你看不到它。 现在我使用了这个博客中的ExpandAnimation。这是代码:
/**
 *
 */
public class ExpandAnimation extends Animation {
    /**
     *
     */
    private AnimationCallback callback = null;
    /**
     *
     */
    private View viewToAnimate = null;
    /**
     *
     */
    private RelativeLayout.LayoutParams viewToAnimateLayoutParams = null;
    /**
     *
     */
    private int marginStart = 0;
    /**
     *
     */
    private int marginEnd = 0;
    /**
     *
     */
    private boolean isVisibleAfter = false;
    /**
     *
     */
    private boolean isEndedAlready = false;

    /**
     *
     * @param callback
     * @param view
     * @param duration
     */
    public ExpandAnimation(AnimationCallback callback, View view, int duration) {
        this.setDuration(duration);

        this.callback = callback;

        this.viewToAnimate = view;
        this.viewToAnimateLayoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();

        this.isVisibleAfter = (view.getVisibility() == View.VISIBLE);

        this.marginStart = this.viewToAnimateLayoutParams.bottomMargin;
        this.marginEnd = (this.marginStart == 0 ? (0 - view.getHeight()) : 0);

        view.setVisibility(View.VISIBLE);
    }

    /**
     *
     * @param interpolatedTime
     * @param transformation
     */
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation transformation) {
        super.applyTransformation(interpolatedTime, transformation);

        if (interpolatedTime < 1.0f) {
            this.viewToAnimateLayoutParams.bottomMargin = this.marginStart + (int) ((this.marginEnd - this.marginStart) * interpolatedTime);
            this.viewToAnimate.requestLayout();
        } else if (!this.isEndedAlready) {
            this.viewToAnimateLayoutParams.bottomMargin = this.marginEnd;
            this.viewToAnimate.requestLayout();

            if (this.isVisibleAfter) {
                this.viewToAnimate.setVisibility(View.GONE);
            }

            this.isEndedAlready = true;

            this.callback.onAnimationCompleted(-1);
        }
    }
}

我在AdapterView中使用它:
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, AnimationCallback {
    private TextView textViewValue = null;
    private TextView textViewTime = null;
    private RelativeLayout relativeLayoutExpand = null;
    private ImageView imageViewMood = null;
    private ImageView imageViewMeal = null;

    public ViewHolder(View itemView) {
        super(itemView);

        this.textViewValue = (TextView) itemView.findViewById(R.id.textview_value);
        this.textViewTime = (TextView) itemView.findViewById(R.id.textview_time);
        this.relativeLayoutExpand = (RelativeLayout) itemView.findViewById(R.id.list_row_expand);
        this.imageViewMood = (ImageView) itemView.findViewById(R.id.imageview_mood);
        this.imageViewMeal = (ImageView) itemView.findViewById(R.id.imageview_meal);

        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        this.animate(this.relativeLayoutExpand);
    }

    public void animate(final View view) {
        ExpandAnimation expand = new ExpandAnimation(this, view, 500);

        view.startAnimation(expand);
    }

    public void onAnimationCompleted(int position) {
    }
}

我目前只有一个问题:当我展开列表中的一项时,第一次它会立即出现而没有动画效果,之后的关闭和打开都有流畅的动画效果。有人知道为什么第一次打开没有动画效果,但之后每次点击都会触发正确的动画效果吗?我还需要第一次点击时也有动画效果。
编辑:是因为我的视图初始时的可见性设置为“GONE”,因此高度未知吗?如果是,我该如何解决?
编辑2:不是,我的XML布局文件没有将视图设置为“GONE”。
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginBottom="10dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RelativeLayout
            android:id="@+id/datatransfer_measure_list_row_data"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingEnd="10dp"
            android:paddingStart="10dp"
            android:paddingTop="10dp">

            <TextView
                android:id="@+id/datatransfer_measure_list_row_textview_value"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentStart="true"
                android:lines="1"
                android:maxLines="1"
                android:singleLine="true"
                android:text="@string/text_value"
                android:textColor="@color/textcolorprimary"
                android:textSize="30sp" />

            <TextView
                android:id="@+id/datatransfer_measure_list_row_textview_time"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/datatransfer_measure_list_row_textview_value"
                android:layout_gravity="center"
                android:layout_marginBottom="10dp"
                android:gravity="start"
                android:lines="1"
                android:maxLines="1"
                android:singleLine="true"
                android:textColor="@color/textcolorprimary"
                android:textSize="14sp" />

            <ImageView
                android:id="@+id/datatransfer_measure_list_row_imageview_expand"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentTop="true"
                android:contentDescription="@string/text_description"
                android:scaleType="fitCenter"
                android:src="@drawable/ic_expand_more_black_24dp" />
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/datatransfer_measure_list_row_expand"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/datatransfer_measure_list_row_data"
            android:background="@color/primaryColor"
            android:paddingBottom="10dp"
            android:paddingEnd="10dp"
            android:paddingStart="10dp"
            android:paddingTop="10dp">

            <RelativeLayout
                android:id="@+id/datatransfer_measure_list_row_mood"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentStart="true"
                    android:layout_centerVertical="true"
                    android:lines="1"
                    android:maxLines="1"
                    android:singleLine="true"
                    android:text="@string/text_mood"
                    android:textColor="@color/textcolorsecundary"
                    android:textSize="30sp" />

                <ImageView
                    android:id="@+id/datatransfer_measure_list_row_imageview_mood"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentEnd="true"
                    android:contentDescription="@string/text_description"
                    android:scaleType="fitCenter" />
            </RelativeLayout>

            <ImageView
                android:id="@+id/datatransfer_measure_list_row_imageview_meal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/datatransfer_measure_list_row_mood"
                android:layout_centerInParent="true"
                android:contentDescription="@string/text_description" />

        </RelativeLayout>

    </RelativeLayout>

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

我在我的ListAdapter中设置了View.GONE

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    ...

    viewHolder.textViewTime.setText(time);
    viewHolder.textViewValue.setText(value + " " + unitValue);
    viewHolder.relativeLayoutExpand.setVisibility(View.GONE); // <-- HERE

    ...
}

编辑 3

也许了解我的卡片视图容器是一个RecyclerView很重要:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/datatransfer_measure_list_textview_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:background="@color/primaryColorDark"
        android:gravity="center"
        android:padding="10dp"
        android:textColor="@color/white"
        android:textSize="18dp" />

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/datatransfer_measure_list_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/datatransfer_measure_list_textview_name">

        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/datatransfer_measure_list_swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/datatransfer_measure_list_row_parent"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipToPadding="false"
                android:padding="10dp"
                android:textColor="@color/textcolorprimary" />
        </android.support.v4.widget.SwipeRefreshLayout>

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/datatransfer_measure_list_floating_action_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"
            android:layout_marginEnd="16dp"
            android:clickable="true"
            android:src="@drawable/ic_search_white_24dp"
            app:backgroundTint="@color/primaryColorDark"
            app:borderWidth="0dp"
            app:elevation="6dp"
            app:layout_anchor="@id/datatransfer_measure_list_row_parent"
            app:layout_anchorGravity="bottom|right|end"
            app:layout_behavior="de.hof.ime_dc.idia_move.views.buttons.ScrollFABBehaviour"
            app:rippleColor="@color/accentColor" />

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

我真的需要一个解决方案。它影响了许多必要的功能。

编辑4

我添加了一些日志输出:

=============================== EXPAND =========================================

08-02 12:27:22.471   V/ExpandAnimation﹕ View is visible: 8 (GONE)
08-02 12:27:22.471   V/ExpandAnimation﹕ marginStart: 0
08-02 12:27:22.471   V/ExpandAnimation﹕ marginEnd: 0
08-02 12:27:22.472   V/ExpandAnimation﹕ View is visible: 0 (VISIBLE)

============================== COLLAPSE ========================================

08-02 12:27:51.015   V/ExpandAnimation﹕ View is visible: 0 (VISIBLE)
08-02 12:27:51.015   V/ExpandAnimation﹕ marginStart: 0
08-02 12:27:51.015   V/ExpandAnimation﹕ marginEnd: -156
08-02 12:27:51.015   V/ExpandAnimation﹕ View is visible: 8 (GONE)

=============================== EXPAND =========================================

08-02 12:27:56.007   V/ExpandAnimation﹕ View is visible: 8 (GONE)
08-02 12:27:56.007   V/ExpandAnimation﹕ marginStart: -156
08-02 12:27:56.007   V/ExpandAnimation﹕ marginEnd: 0
08-02 12:27:56.008   V/ExpandAnimation﹕ View is visible: 0 (VISIBLE)

============================== COLLAPSE ========================================

08-02 12:27:51.015   V/ExpandAnimation﹕ View is visible: 0 (VISIBLE)
08-02 12:27:51.015   V/ExpandAnimation﹕ marginStart: 0
08-02 12:27:51.015   V/ExpandAnimation﹕ marginEnd: -156
08-02 12:27:51.015   V/ExpandAnimation﹕ View is visible: 8 (GONE)

=============================== EXPAND =========================================

08-02 12:27:56.007   V/ExpandAnimation﹕ View is visible: 8 (GONE)
08-02 12:27:56.007   V/ExpandAnimation﹕ marginStart: -156
08-02 12:27:56.007   V/ExpandAnimation﹕ marginEnd: 0
08-02 12:27:56.008   V/ExpandAnimation﹕ View is visible: 0 (VISIBLE)

正如您所看到的,扩展的第一个marginStart为0,但它应该是-156。


如果与视图高度计算有关,则可以将其设置为不可见,而不是消失。 - kuljeet singh
是的,而且回收利用的视图也能立即工作。 - Mulgard
请问您能否发布完整的ListAdapter代码? - dkarmazi
2个回答

2

您没有展示您的XML,但我假设您在其中使用了 android:visibility="gone"。如果是这样,请从布局文件中删除它(以便默认情况下可见)。如果应该被隐藏,那么在充气后调用 setVisibility(View.GONE)。这样,您将获得相同的结果,但视图也能够获取其尺寸。


我更新了我的帖子。我没有在布局文件中设置可见性为gone,而是在我的ListAdapter中将其设置为gone。 - Mulgard

2

根据您的代码,边距的值已被初始化为0,0。

如果将视图设置为VISIBLE,则可以获得边距,如果设置为GONE,则边距将为零。

因此,请按照以下顺序编写您的代码:

this.viewToAnimate = view;

view.setVisibility(View.VISIBLE);

this.viewToAnimateLayoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();

// Now the margins will not be zero.
this.marginStart = this.viewToAnimateLayoutParams.bottomMargin;
this.marginEnd = (this.marginStart == 0 ? (0 - view.getHeight()) : 0);

不要初始化这些变量。
private int marginStart = 0;
private int marginEnd = 0;

甚至可以这样做:
private RelativeLayout.LayoutParams viewToAnimateLayoutParams = null;

你只需要初始化那些算法需要起始值的变量,例如布尔值。
private boolean isVisibleAfter = false;
private boolean isEndedAlready = false;

我遇到了这行代码的问题:

this.isVisibleAfter = (view.getVisibility() == View.VISIBLE);

我不明白为什么你的代码在这行没有在logcat中显示任何警告或错误。 (view.getVisibility() == View.VISIBLE) 没有返回visibility的值。
this.isVisibleAfter = view.getVisibility(); 
// will return the visibility of the view not a bool value.

if(view.getVisibility() == View.VISIBLE){
 // will  run only if the visibility is set to visible.
if(view.getVisibility() == View.INVISIBLE)
if(view.getVisibility() == View.GONE)

它不是布尔值,可以返回三个值中的一个。

我建议将其更改为:

if(view.getVisibility() == View.VISIBLE){

    this.isVisibleAfter = true;
}
else{
    this.isVisibleAfter = false;
}

使用GONE将只折叠该视图所占用的空间。 INVISIBLE将保留视图占用的空间。除非您想将布局元素强制保持在特定位置,否则我更喜欢使用GONE
希望这可以帮助您,让我知道。

它没有解决问题。与之前相同的行为。顺便说一下:(view.getVisibility() == View.VISIBLE) 返回 true 或 false。view.getVisibility()View.VISIBLE 单独返回 int 值。但是如果你说 (1 == 2),你会得到 false。 - Mulgard

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