Android 是否正确设置在ListView中删除行的动画?

Android 是否正确设置在ListView中删除行的动画?,android,android-listview,android-animation,Android,Android Listview,Android Animation,问题是: 1在listview中的行中添加一个触摸监听器,以便在滑动时 播放2个滑动动画 在后端删除3行,然后 4动画播放时没有任何闪烁或抖动。通过闪烁,我的意思是删除的行在动画完成后短暂显示 我怀疑动画监听器发生了一些奇怪的事情,因此我按照给定的顺序完成了以下操作: 通过将setFillAfter和setFillenabled设置为true,执行动画并使其持久化 在动画结束时使视图不可见 删除数据库中的行 重置动画 重新加载listview 使视图可见,但再等待300毫秒 结果删除行时没有抖动

问题是:

1在listview中的行中添加一个触摸监听器,以便在滑动时

播放2个滑动动画

在后端删除3行,然后

4动画播放时没有任何闪烁或抖动。通过闪烁,我的意思是删除的行在动画完成后短暂显示

我怀疑动画监听器发生了一些奇怪的事情,因此我按照给定的顺序完成了以下操作:

通过将setFillAfter和setFillenabled设置为true,执行动画并使其持久化 在动画结束时使视图不可见 删除数据库中的行 重置动画 重新加载listview 使视图可见,但再等待300毫秒 结果删除行时没有抖动或闪烁,但现在由于额外的300毫秒等待而感觉迟钝。我也不确定这种延迟是否适用于所有设备

更新:我应该指出,300毫秒的延迟是它工作的原因。这很奇怪,因为此时动画已经重置,listview拥有最新的数据。没有理由让视图可见会使旧行短暂显示,对吗

我还尝试按照使用ViewPropertyAnimator,但由于某些原因,在动画的每一步都会调用onAnimationEnd侦听器

我还读到,我们应该实现一个自定义视图并覆盖其onAnimationEnd侦听器。然而,我还没有尝试过这种方法

更新:只是尝试在末尾添加一个额外的虚拟动画。然而,这是行不通的

我的测试手机运行冰淇淋三明治。我的应用程序的目标是姜饼和之后

那么正确的解决方案是什么?我这样做不对吗

代码如下:

 @Override
public boolean onTouch(final View view, MotionEvent event)
{
    //...

    switch(action) {
        //...
        case MotionEvent.ACTION_MOVE:
            // ...
            if (//check for fling
            {
                view.clearAnimation();
                //animation = standard translate animation
                animation.setAnimationListener(new AnimationListener() {
                    //

                    @Override
                    public void onAnimationEnd(Animation animation)
                    {
                        view.setVisibility(View.INVISIBLE);
                        flingListener.onFling(cursorPosition, view, velocity);
                    }

                    //...
                });
                view.startAnimation(animation);
            }
            break;
      //
 }
放纵的听众:

    @Override
    public void onFling(int position, final View view, float velocity)
    {
        //delete row -- its actually a Loader
        //the following code runs in the Loader's onLoadFinished
        view.clearAnimation();
        adapter.notifyDataSetChanged();
        adapter.swapCursor(null);

        //reload listview -- it's actually a Loader
        //the following code runs in the Loader's onLoadFinished
        adapter.swapCursor(cursor);
        view.postDelayed(new Runnable() {
            @Override
            public void run()
            {
                view.setVisibility(View.VISIBLE);
            }
        }, 300);
    }

更新:在比较Chet Haase的代码之后,我们正在做一些类似的事情,但有一些重要的区别:1他使用一个onPreDraw侦听器和ListView树观察器来执行实际的删除,2他不仅从数组中删除行,而且从ListView中删除行。在模仿了他的代码之后,它仍然不起作用。现在的问题是加载器——我使用加载器异步删除行。在后端删除行之前,加载程序似乎会强制对ListView进行额外的draw调用。这是闪烁的另一个原因。但是仍然没有找到解决办法。

切特·哈斯谷歌工程师在这个主题上做了一个非常好的开发,我建议看一下/从他的来源中吸取一些想法。如果您使用nineodeldroid,我认为这将向后兼容到GB

在这里查看:


谷歌工程师切特·哈斯(Chet Haase)在这个话题上做了一个非常好的设计,我建议你看看/从他的来源中汲取一些想法。如果您使用nineodeldroid,我认为这将向后兼容到GB

在这里查看:


正如我在评论中指出的,Chet代码的问题在于它是为同步数据访问而设计的。一旦开始异步删除行,他的代码就会失败

我通过结合Chet的代码和以下答案找到了闪烁问题的解决方案:

正确执行行删除操作的解决方案是:

为ListView树观察者创建onPreDraw侦听器以防止闪烁。此侦听器中的所有代码在列表视图重新绘制自身之前运行,以防止闪烁。 找到删除listview中但尚未删除数据库中的行的方法。有两种方法,请参见: 创建一个AbstractCursor包装器,忽略要删除的行,并将其替换为真正的游标。或 将要删除的行标记为染色,并在重新绘制该行时对其进行适当操作。 异步删除数据库中的real行。 使用AbstractCursor包装器的一些伪代码技术上称为代理:

    //Called when you swipe a row to delete
    @Override
    public void onFling(final int positionToRemove, final View view)
    {
        final ViewTreeObserver observer = listView.getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
        {
            public boolean onPreDraw()
            {
                observer.removeOnPreDrawListener(this);

                //remove the row from the matrix cursor
                CursorProxy newCursor = new CursorProxy(cursor,
                                                        positionToRemove);
                swapCursor(newCursor);
                //delete row in database
             }
        }
  }

正如我在评论中指出的,Chet代码的问题在于它是为同步数据访问而设计的。一旦开始异步删除行,他的代码就会失败

我通过结合Chet的代码和以下答案找到了闪烁问题的解决方案:

正确执行行删除操作的解决方案是:

为ListView树观察者创建onPreDraw侦听器以防止闪烁。此侦听器中的所有代码在列表视图重新绘制自身之前运行,以防止闪烁。 找到删除listview中但尚未删除数据库中的行的方法。有两种方法,请参见: 创建一个AbstractCursor包装器,忽略要删除的行,并将其替换为真正的游标。或 将要删除的行标记为染色,并在重新绘制该行时对其进行适当操作。 异步删除数据库中的real行。 使用AbstractCursor包装器的一些伪代码技术上称为代理:

    //Called when you swipe a row to delete
    @Override
    public void onFling(final int positionToRemove, final View view)
    {
        final ViewTreeObserver observer = listView.getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
        {
            public boolean onPreDraw()
            {
                observer.removeOnPreDrawListener(this);

                //remove the row from the matrix cursor
                CursorProxy newCursor = new CursorProxy(cursor,
                                                        positionToRemove);
                swapCursor(newCursor);
                //delete row in database
             }
        }
  }

可能的副本请在表决前阅读。您提供的链接仅适用于Android 4.1及以上版本。我需要姜饼和姜饼。如果你读过,你就会意识到这一点
欧丁,;不要检查这个。它还有姜饼的代码。我不投反对票。我把它作为复制品合上了。我还没有测试代码。但它应该是有效的,因为Cher haase是一名谷歌工程师。我对你的问题投了更高的票,但我仍然认为这是一个重复的问题。我不知道我是否可以回滚关闭投票,因为我已经将其标记为重复。啊,好的,谢谢。我看到姜饼密码,正在调查。感谢可能的副本,请在投票前阅读。您提供的链接仅适用于Android 4.1及以上版本。我需要姜饼和姜饼。如果你读过,你就会意识到你在读;不要检查这个。它还有姜饼的代码。我不投反对票。我把它作为复制品合上了。我还没有测试代码。但它应该是有效的,因为Cher haase是一名谷歌工程师。我对你的问题投了更高的票,但我仍然认为这是一个重复的问题。我不知道我是否可以回滚关闭投票,因为我已经将其标记为重复。啊,好的,谢谢。我看到姜饼密码,正在调查。感谢幸运的是,这是可行的,因为它依赖于withEndAction,Android 4.1的一项功能。不幸的是,早期版本中的等效功能动画侦听器已损坏。因此,我的问题。是的,这就是为什么我要检查,它提供了一个向后兼容的动画api版本。是的,推出本机动画代码来使用NineodelDroids,你就很好了。我试图避免使用另一个库来做一些应该很简单的事情。但如果我不能弄清楚,我肯定会调查。不幸的是,这是可行的,因为它依赖于withEndAction,一个Android 4.1的功能。不幸的是,早期版本中的等效功能动画侦听器已损坏。因此,我的问题。是的,这就是为什么我要检查,它提供了一个向后兼容的动画api版本。是的,推出本机动画代码来使用NineodelDroids,你就很好了。我试图避免使用另一个库来做一些应该很简单的事情。但如果我搞不清楚,我肯定会调查的