如何动画添加或删除Android ListView行

时间:2010-10-13 21:29:02

标签: android listview animation

在iOS中,有一个非常简单而强大的工具可以动画添加和删除UITableView行,here's a clip from a youtube video显示默认动画。请注意周围行如何折叠到已删除的行上。此动画可帮助用户跟踪列表中的更改内容以及数据更改时列表中的位置。

由于我一直在使用Android进行开发,因此我找不到在TableView中为单个行设置动画的等效工具。在我的适配器上调用notifyDataSetChanged()会导致ListView立即使用新信息更新其内容。我希望在数据发生变化时显示一个新行推入或滑出的简单动画,但我找不到任何记录的方法来执行此操作。看起来LayoutAnimationController可能有一个关键,让它工作,但当我在ListView上设置LayoutAnimationController(类似于ApiDemo's 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实现/分支已经让我想到了,但这似乎不应该那么困难。

谢谢!

14 个答案:

答案 0 :(得分:123)

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>

答案 1 :(得分:14)

答案 2 :(得分:9)

查看Google解决方案。这是一种删除方法。

ListViewRemovalAnimation项目代码和Video演示

它需要Android 4.1+(API 16)。但我们在2014年之外。

答案 3 :(得分:2)

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

答案 4 :(得分:2)

您是否考虑过向右侧进行动画制作?你可以做一些事情,比如在列表项的顶部绘制一个逐渐变大的白条,然后从列表中删除它。其他细胞仍会痉挛到位,但它总比没有好。

答案 5 :(得分: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);
}

将此集合添加到List适配器:

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));

就是这样!您可以通过更改一次收缩高度的像素数来更改动画的速度。不是很复杂,但它确实有效!

答案 6 :(得分:2)

呼叫 listView.scheduleLayoutAnimation(); 在更改列表之前

答案 7 :(得分:2)

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

ListView.smoothScrollToPosition(position);

答案 8 :(得分:1)

由于Android是开源的,因此您实际上不需要重新实现ListView的优化。你可以抓住ListView的代码并试图找到一种破解动画的方法,你也可以在android bug跟踪器中open a feature request(如果你决定实现它,不要忘记contribute a patch)。

仅供参考,ListView源代码为here

答案 9 :(得分:1)

我还没试过,但看起来像animateLayoutChanges应该做你想要的。我在ImageSwitcher类中看到它,我认为它也在ViewSwitcher类中?

答案 10 :(得分: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);
        }
    });

了解图片see this

感谢。

答案 11 :(得分:1)

以下是允许您删除行并重新排序的source code

还可以使用演示APK文件。删除行的方式更多的是谷歌的Gmail应用程序,它会在刷顶视图后显示底部视图。底部视图可以有一个撤消按钮或任何你想要的。

答案 12 :(得分:0)

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

答案 13 :(得分:0)

只是分享另一种方法:

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

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

然后我使用处理程序添加项目并更新列表视图:

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;
}