如何对Android ListView行的添加或删除进行动画处理


212

在iOS中,有一个非常简单而强大的工具可以对UITableView行的添加和删除进行动画处理,这是一个来自youtube视频的剪辑,显示了默认动画。注意周围的行如何折叠到已删除的行上。此动画可帮助用户跟踪列表中的更改以及数据更改时用户在列表中的位置。

自从我在Android上进行开发以来,我发现没有等效的工具可以为TableView中的各个行设置动画。调用notifyDataSetChanged()我的适配器会使ListView立即用新信息更新其内容。我想显示一个新的简单动画,当数据更改时,新行会推入或滑出,但是我找不到任何记录的方式来做到这一点。看起来LayoutAnimationController可能拥有使它起作用的关键,但是当我在ListView上设置LayoutAnimationController(类似于ApiDemo的LayoutAnimation2)并在列表显示后从适配器中删除元素时,这些元素会立即消失而不是动画化。

我还尝试了以下操作来为单个项目添加动画:

@Override
protected void onListItemClick(ListView l, View v, final int position, long id) {
    Animation animation = new ScaleAnimation(1, 1, 1, 0);
    animation.setDuration(100);
    getListView().getChildAt(position).startAnimation(animation);
    l.postDelayed(new Runnable() {
        public void run() {
            mStringList.remove(position);
            mAdapter.notifyDataSetChanged();
        }
    }, 100);
}

但是,动画行周围的行不会移动位置,直到它们在notifyDataSetChanged()调用时跳到新位置为止。放置元素后,ListView似乎不会更新其布局。

在编写我自己的ListView的实现/分支时,我已经想到了,这似乎并不难。

谢谢!


有人找到答案了吗?请与他人分享
AndroidGecko

@Alex:您是否完成了类似youtube视频(如iPhone)的动画,如果您有任何演示或android链接,请给我,我已经尝试过在xml文件中使用animateLayoutChanges,但这与iphone并不完全一样
Jayesh

@Jayesh,很遗憾,我不再从事Android开发。我还没有测试过大约在2012
。– Alex Pretzlav 2014年

Answers:


124
Animation anim = AnimationUtils.loadAnimation(
                     GoTransitApp.this, android.R.anim.slide_out_right
                 );
anim.setDuration(500);
listView.getChildAt(index).startAnimation(anim );

new Handler().postDelayed(new Runnable() {

    public void run() {

        FavouritesManager.getInstance().remove(
            FavouritesManager.getInstance().getTripManagerAtIndex(index)
        );
        populateList();
        adapter.notifyDataSetChanged();

    }

}, anim.getDuration());

从上到下的动画使用:

<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromYDelta="20%p" android:toYDelta="-20"
            android:duration="@android:integer/config_mediumAnimTime"/>
        <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

70
最好使用anim.setAnimationListener(new AnimationListener() { ... })而不是使用处理程序
Oleg Vaskevich

1
populateList()为了什么?
瓦西里·索钦斯基

5
@MrAppleBR有几个原因。首先,您并不是要创建不需要的Handler。其次,通过在动画结束时使用内置的回调,使代码的复杂度降低。第三,您不知道在每个平台上如何实现Handler以及Animation将如何工作;您的延迟运行可能会在动画完成之前发生。
Oleg Vaskevich 2013年

7
“但是,动画行周围的行只有在调用notifyDataSetChanged()时跳到新位置后才移动位置。” 该问题仍然存在于您的解决方案中。
鲍里斯·鲁塞夫

5
什么是FavouritesManager类和populateList()方法?
Jayesh 2014年

14

1
我认为这是需要简单动画时的简单方法,但是您也可以使用RecyclerView.setItemAnimator()方法来自定义动画。
qatz 16'Mar

2
最后一步是我缺少的链接。稳定的ID。谢谢!
阿米尔·乌瓦尔

这是一个很好的示例项目,很好地演示了API。
Mr-IDE


2

由于ListViews高度优化,我认为这是不可能实现的。您是否尝试过通过代码创建“ ListView”(即通过将行从xml扩展并将其附加到LinearLayout)并设置动画效果?


6
重新实现listview仅添加动画是没有意义的。
Macarse

我当然可以只使用a LinearLayout,但是对于非常大的数据集LinearLayout,其性能将变得糟糕透顶。 ListView围绕视图回收进行了许多智能优化,使其可以处理大型数据集(iOS的UITableView具有相同的优化)。编写我自己的视图回收器属于重新实现ListView的类别:(
Alex Pretzlav 2010年

我知道这没有意义-但是,如果您仅处理几行,那么拥有不错的进/出动画的好处就值得一试。
2010年

2

您是否考虑过向右移动动画?您可以执行类似在列表项顶部绘制逐渐变大的白色条,然后从列表中将其删除的操作。其他单元仍然会突然移动,但总比没有好。



2

我共同尝试了另一种方法,而不必操纵列表视图。不幸的是,常规的Android动画似乎可以操纵行的内容,但是实际上无法缩小视图。因此,首先考虑以下处理程序:

private Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
    Bundle bundle = message.getData();

    View view = listView.getChildAt(bundle.getInt("viewPosition") - 
        listView.getFirstVisiblePosition());

    int heightToSet;
    if(!bundle.containsKey("viewHeight")) {
        Rect rect = new Rect();
        view.getDrawingRect(rect);
        heightToSet = rect.height() - 1;
    } else {
        heightToSet = bundle.getInt("viewHeight");
    }

    setViewHeight(view, heightToSet);

    if(heightToSet == 1)
        return;

    Message nextMessage = obtainMessage();
    bundle.putInt("viewHeight", (heightToSet - 5 > 0) ? heightToSet - 5 : 1);
    nextMessage.setData(bundle);
    sendMessage(nextMessage);
}

将此集合添加到您的列表适配器:

private Collection<Integer> disabledViews = new ArrayList<Integer>();

并添加

public boolean isEnabled(int position) {
   return !disabledViews.contains(position);
}

接下来,无论您要隐藏行的位置,添加以下内容:

Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("viewPosition", listView.getPositionForView(view));
message.setData(bundle);
handler.sendMessage(message);    
disabledViews.add(listView.getPositionForView(view));

而已!您可以通过更改动画的速度来改变动画的速度,该像素可一次缩小高度。并不是真正的复杂,但是可以工作!


2

在将新行插入到ListView之后,我只需将ListView滚动到新位置。

ListView.smoothScrollToPosition(position);


1

由于Android是开源的,因此您实际上不需要重新实现ListView的优化。您可以获取ListView的代码并尝试找到一种破解动画的方法,还可以在android bug跟踪器中打开功能请求(如果您决定实施它,请不要忘记提供补丁)。

仅供参考,ListView源代码在这里


1
这不是应实施此类更改的方式。首先,您应该拥有AOSP项目构建-这是将动画添加到列表视图中的一种繁琐的方法。请查看各种开源库中的实现。
OrhanC1 2014年

1

这是使您删除行并对其重新排序的源代码

演示APK文件也可用。删除行的操作与Google Gmail应用程序大致相同,可在滑动顶视图后显示底视图。底视图可以具有“撤消”按钮或您想要的任何按钮。


1

正如我在网站上解释我的方法一样,我共享了链接。无论如何,该想法是通过getdrawingcache创建位图。具有两个位图并为较低的位图设置动画以创建移动效果

请参见以下代码:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
    {
        public void onItemClick(AdapterView<?> parent, View rowView, int positon, long id)
        {
            listView.setDrawingCacheEnabled(true);
            //listView.buildDrawingCache(true);
            bitmap = listView.getDrawingCache();
            myBitmap1 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), rowView.getBottom());
            myBitmap2 = Bitmap.createBitmap(bitmap, 0, rowView.getBottom(), bitmap.getWidth(), bitmap.getHeight() - myBitmap1.getHeight());
            listView.setDrawingCacheEnabled(false);
            imgView1.setBackgroundDrawable(new BitmapDrawable(getResources(), myBitmap1));
            imgView2.setBackgroundDrawable(new BitmapDrawable(getResources(), myBitmap2));
            imgView1.setVisibility(View.VISIBLE);
            imgView2.setVisibility(View.VISIBLE);
            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp.setMargins(0, rowView.getBottom(), 0, 0);
            imgView2.setLayoutParams(lp);
            TranslateAnimation transanim = new TranslateAnimation(0, 0, 0, -rowView.getHeight());
            transanim.setDuration(400);
            transanim.setAnimationListener(new Animation.AnimationListener()
            {
                public void onAnimationStart(Animation animation)
                {
                }

                public void onAnimationRepeat(Animation animation)
                {
                }

                public void onAnimationEnd(Animation animation)
                {
                    imgView1.setVisibility(View.GONE);
                    imgView2.setVisibility(View.GONE);
                }
            });
            array.remove(positon);
            adapter.notifyDataSetChanged();
            imgView2.startAnimation(transanim);
        }
    });

要了解图片,请参阅此

谢谢。


0

我做了类似的事情。一种方法是onMeasure在发出requestLayout()listView的同时,在动画时间内插入行内视图的高度。是的,最好直接在listView代码中进行操作,但这是一个快速的解决方案(看起来不错!)


0

只是分享另一种方法:

首先将列表视图的android:animateLayoutChanges设置true

<ListView
        android:id="@+id/items_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"/>

然后,我使用处理程序添加项并延迟更新listview:

Handler mHandler = new Handler();
    //delay in milliseconds
    private int mInitialDelay = 1000;
    private final int DELAY_OFFSET = 1000;


public void addItem(final Integer item) {
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mDataSet.add(item);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mAdapter.notifyDataSetChanged();
                        }
                    });
                }
            }).start();

        }
    }, mInitialDelay);
    mInitialDelay += DELAY_OFFSET;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.