在iOS中,有一个非常简单和强大的工具来动画添加和删除UITableView行,这是一个来自youtube视频的剪辑,显示默认动画。注意周围的行如何折叠到已删除的行上。这个动画帮助用户跟踪列表中发生了什么变化,以及当数据发生变化时他们正在查看列表中的哪个位置。

Since I've been developing on Android I've found no equivalent facility to animate individual rows in a TableView. Calling notifyDataSetChanged() on my Adapter causes the ListView to immediately update its content with new information. I'd like to show a simple animation of a new row pushing in or sliding out when the data changes, but I can't find any documented way to do this. It looks like LayoutAnimationController might hold a key to getting this to work, but when I set a LayoutAnimationController on my ListView (similar to ApiDemo's LayoutAnimation2) and remove elements from my adapter after the list has displayed, the elements disappear immediately instead of getting animated out.

我还尝试了如下方法,在移除单个项目时将其动画化:

@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的实现/分支已经越过我的脑海,这似乎不应该是那么困难的事情。

谢谢!


当前回答

我用另一种方法来做而不需要操作列表视图。不幸的是,常规的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));

就是这样!你可以通过改变一次缩小高度的像素数来改变动画的速度。不是很复杂,但很管用!

其他回答

我用另一种方法来做而不需要操作列表视图。不幸的是,常规的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));

就是这样!你可以通过改变一次缩小高度的像素数来改变动画的速度。不是很复杂,但很管用!

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

RecyclerView负责添加、删除和重新排序动画!

这个简单的AndroidStudio项目有一个RecyclerView。看一下提交:

提交经典的Hello World Android应用程序 commit,添加一个RecyclerView到项目中(内容不是动态的) commit,增加了在运行时修改RecyclerView内容的功能(但没有动画) 最后…提交添加动画到RecyclerView

你考虑过向右移动吗?您可以在列表项的顶部绘制一个逐渐增大的白色条,然后将其从列表中删除。其他细胞仍然会原地跳动,但总比没有强。

由于Android是开源的,你实际上不需要重新实现ListView的优化。你可以抓取ListView的代码,并试图找到一种方法来破解动画,你也可以在android漏洞跟踪器中打开一个功能请求(如果你决定实现它,不要忘记贡献一个补丁)。

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