正确动画删除 ListView 中的行? [英] Correctly animate removing row in ListView?

查看:15
本文介绍了正确动画删除 ListView 中的行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

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

(1) add a touch listener to rows in a listview so that on swipe.

(2) 滑动动画播放

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

(3) rows get deleted in the backend, and

(4) 动画播放时没有任何闪烁或抖动.闪烁"是指动画完成后删除的行会短暂显示.

(4) the animation plays without any flicker or jerkiness. By "flicker" I mean that the deleted row briefly shows after the animation finished.

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

I suspect that something funky was happening with the animation listener, so I ended up doing the following (done in the order given):

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

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

The result deletes the row without jerkiness or flicker BUT it now feels sluggish because of extra 300 ms wait. (I'm also not sure if this delay works across all devices.)

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

Update: I should point out that the 300 ms delay is what makes it work. That's weird because by that point the animation was reset and the listview has the latest data. There should be no reason why making the view visible makes the old row briefly show, right?

我还尝试使用 ViewPropertyAnimator(根据 在 ViewPager 上使用动画和setFillAfter) 但出于某种原因,onAnimationEnd 侦听器在动画的每个 步骤中都被调用.

I also tried using a ViewPropertyAnimator (as per Using animation on a ViewPager and setFillAfter) but for some reason the onAnimationEnd listener was called at every step of the animation.

我还读到我们应该实现自定义视图并覆盖其 onAnimationEnd 侦听器.(不过,我还没有尝试过这种方法.)

I also read that we should implement a custom view and override its onAnimationEnd listener. (However, I haven't tried that approach yet.)

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

Update: just tried to add an extra dummy animation at the end (as per Android Animation Flicker). However, that doesn't work

我的测试手机运行的是冰淇淋三明治.我的应用面向 Gingerbread 及之后.

My test phone runs Ice Cream Sandwich. My app is targeting Gingerbread and after.

那么正确的解决方案是什么?我这样做是不是用错了方法?

So what's the proper solution? Am I doing this the wrong way?

代码如下:

 @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 ---我使用 Loader 异步删除行.加载程序似乎强制对 ListView 进行额外的绘制调用...之前该行已在后端删除.这是闪烁的(另一个)原因.仍然没有想出解决方法.

Update: After comparing Chet Haase's code, we are doing similar things with some important differences: (1) he uses a onPreDraw listener with the ListView tree observer to do the actual deletion, (2) he removes the row not only from the array but also from the listview. After mimicking his code, it still didn't work. The problem is now the Loader---I use a Loader to delete rows asynchronously. The Loader seems to force an additional draw call to the ListView...before the row has been deleted in the backend. And that's (another) cause of the flicker. Still haven't figured out a workaround though.

推荐答案

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

As I pointed out in the comments, the problem with Chet's code is that its designed for synchronous data access. Once you start asynchronously deleting rows, his code fails.

我通过结合 Chet 的代码和这个答案找到了解决闪烁问题的方法:CursorAdapter 支持的 ListView 删除动画闪烁";关于删除

I found the solution to the flicker problem by combining Chet's code with this answer: CursorAdapter backed ListView delete animation "flickers" on delete

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

The solution to correctly do a row deletion aynchronously is:

  1. 为 ListView 树观察器创建一个 onPreDraw 侦听器以防止闪烁.此侦听器中的所有代码在列表视图重新绘制自身之前运行,以防止闪烁.
  2. 找到一种方法来删除列表视图中的行(但还没有在数据库中).有两种方法(参见 CursorAdapter 支持的 ListView 删除动画flickers"; 在删除):
  1. 创建一个 AbstractCursor 包装器,忽略要删除的行并将其替换为真正的游标.或
  2. 将要删除的行标记为染色",并在重绘该行时对其进行适当的操作.

  • 删除数据库中的真实行(异步).
  • 一些使用 AbstractCursor 包装器的伪代码(技术上称为代理"):

    Some pseudo-code using the AbstractCursor wrapper (it's technically called a "proxy"):

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

    这篇关于正确动画删除 ListView 中的行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆