1

问题:

(1) 向列表视图中的行添加触摸侦听器,以便在滑动时。

(2) 滑动动画播放

(3) 行在后端被删除,并且

(4) 动画播放没有任何闪烁或跳动。“闪烁”是指动画完成后删除的行会短暂显示。

我怀疑动画监听器发生了一些奇怪的事情,所以我最终做了以下事情(按照给定的顺序完成):

  1. 通过将 setFillAfter 和 setFillenabled 设置为 true 来制作动画并使其持续存在
  2. 动画结束时使视图不可见
  3. 删除数据库中的行
  4. 重置动画
  5. 重新加载列表视图
  6. 使视图可见(但再等待 300 毫秒)

结果删除了没有抖动或闪烁的行,但由于额外的 300 毫秒等待,它现在感觉迟缓。(我也不确定这种延迟是否适用于所有设备。)

更新:我应该指出,300 毫秒的延迟是它工作的原因。这很奇怪,因为到那时动画被重置并且列表视图具有最新数据。应该没有理由让视图可见会使旧行短暂显示,对吗?

我还尝试使用 ViewPropertyAnimator (根据在 ViewPager 和 setFillAfter 上使用动画),但由于某种原因,在动画的一步都调用了 onAnimationEnd 侦听器。

我还读到我们应该实现一个自定义视图并覆盖它的 onAnimationEnd 监听器。(但是,我还没有尝试过这种方法。)

更新:只是试图在最后添加一个额外的虚拟动画(根据Android Animation Flicker)。但是,这不起作用

我的测试手机运行冰淇淋三明治。我的应用程序针对 Gingerbread 及之后。

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

这是代码:

 @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)他不仅从数组中删除行,而且也来自列表视图。模仿他的代码后,还是不行。现在的问题是加载器——我使用加载器异步删除行。Loader 似乎在后端删除行之前强制对 ListView 进行额外的绘制调用。这是闪烁的(另一个)原因。不过还没有想出解决办法。

4

2 回答 2

2

Chet Haase(谷歌工程师)在这个主题上整理了一个非常好的 DevBytes,我建议从他的来源中观看/获取想法。如果您使用 NineOldAndroids,我认为这将向后兼容 GB。

在这里查看:

http://graphics-geek.blogspot.com/2013/06/devbytes-animating-listview-deletion.html

于 2013-08-05T02:48:27.450 回答
2

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

我通过将 Chet 的代码与此答案相结合找到了闪烁问题的解决方案:CursorAdapter backed ListView delete animation "flickers" on delete

正确异步执行行删除的解决方案是:

  1. 为 ListView 树观察者创建一个 onPreDraw 监听器以防止闪烁。此侦听器中的所有代码在列表视图重新绘制之前运行,以防止闪烁。
  2. 找到一种方法来删除列表视图中的行(但还没有在数据库中)。有两种方法(请参阅CursorAdapter 支持的 ListView 删除动画“闪烁” on delete):
    1. 创建一个 AbstractCursor 包装器,它忽略要删除的行并将其换成真正的游标。或者
    2. 将要删除的行标记为“染色”,并在重绘行时对其进行适当的操作。
  3. 删除数据库中的真实行(异步)。

一些使用 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
             }
        }
  }
于 2013-08-09T02:27:31.653 回答