简体   繁体   English

在Android 5 Lollipop上打破的ListViewDraggingAnimation

[英]ListViewDraggingAnimation broken on Android 5 Lollipop

I'm using ListViewDraggingAnimation by DevBytes , but it seems broken on Android Lollipop developer preview 2 (LPX13D). 我正在使用DevBytes的 ListViewDraggingAnimation ,但它似乎在Android Lollipop开发者预览2(LPX13D)上被破坏了。 When I drag a row over other rows, those rows will disappear and become no longer clickable (see below). 当我在其他行上拖动一行时,这些行将消失并变得不再可点击(见下文)。 I tried disabling hardware acceleration for the listview but it didn't have any effect. 我尝试禁用listview的硬件加速,但它没有任何效果。

例

Has anyone experienced the same issue? 有没有人遇到过同样的问题? Any hints? 任何提示? Thanks :) 谢谢 :)

I found the problem. 我发现了这个问题。 It came from this flag. 它来自这面旗帜。 StableArrayAdapter.hasStableId . StableArrayAdapter.hasStableId

It fix all problem from this view on Lollipop. 它修复了Lollipop上这个视图的所有问题。

@Override
public boolean hasStableIds()
{
    return android.os.Build.VERSION.SDK_INT < 20;
}

To be honest, I don't what causes the problem, but this fix makes no visual errors anymore on any version. 说实话,我不是导致问题的原因,但是这个修复程序在任何版本上都不会出现任何视觉错误。 And because all that was changed is just visibility of view, I believe it shouldn't create any new functional problems. 因为所有改变的只是视图的可见性,我相信它不应该创造任何新的功能问题。


Replace this code in function handleCellSwitch() in class DynamicListView : 在类DynamicListView中的函数handleCellSwitch()中替换此代码:

mobileView.setVisibility(View.VISIBLE);
switchView.setVisibility(View.INVISIBLE);

for 对于

if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT){
    mobileView.setVisibility(View.VISIBLE);
    switchView.setVisibility(View.INVISIBLE);
} else{
    mobileView.setVisibility(View.INVISIBLE);
    switchView.setVisibility(View.VISIBLE);
}

I tried tinkering with the code and in the end I found a way how to make it display as it was before. 我试着修补代码,最后我找到了一种方法,让它像以前一样显示。 But fixing the problem for Lollipop made the same problem appear on KitKat and previous versions instead. 但是修复Lollipop的问题会导致相同的问题出现在KitKat和以前的版本中。 So I applied the fix only for android versions higher than KitKat. 所以我只为高于KitKat的Android版本应用了修复程序。

My guess is that these two views gets exchanged in the process for some reason on the new Lollipop version. 我的猜测是,由于某种原因,在新的Lollipop版本中,这两个视图在这个过程中被交换。 In effect, one of the views gets always displayed while the other one gets always hidden. 实际上,其中一个视图始终显示,而另一个视图始终隐藏。 Would be nice to know where and what was changed in the lollipop android code though... 很高兴知道棒棒糖安卓代码在哪里以及改变了什么......

The proper solution is to turn the visibility of that view back on before it's recycled and then turn it back off before it's drawn. 正确的解决方案是在回收之前将该视图的可见性重新打开,然后在绘制之前将其关闭。

       ((BaseAdapter) getAdapter()).notifyDataSetChanged();

        mDownY = mLastEventY;

        final int switchViewStartTop = switchView.getTop();

        mobileView.setVisibility(View.VISIBLE);
        switchView.setVisibility(View.INVISIBLE);

        updateNeighborViewsForID(mMobileItemId);

        final ViewTreeObserver observer = getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                observer.removeOnPreDrawListener(this);

replace with, 用。。。来代替,

        mobileView.setVisibility(VISIBLE);
        ((BaseAdapter) getAdapter()).notifyDataSetChanged();


        mDownY = mLastEventY;

        final int switchViewStartTop = switchView.getTop();

        updateNeighborViewsForID(mMobileItemId);

        final ViewTreeObserver observer = getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                observer.removeOnPreDrawListener(this);

                View mobileView = getViewForID(mMobileItemId);
                if (mobileView != null) mobileView.setVisibility(INVISIBLE);

The stableid solution is wrong. stableid解决方案是错误的。 The IDs are stable and telling it that they aren't is in error. ID是稳定的并且告诉它它们不是错误的。 It simply kluges the system into recycling the views the old way. 它只是简化了系统,以旧方式回收视图。 Which was in fact a bad way of doing it and was fixed in lollipop. 这实际上是一种糟糕的做法,并在棒棒糖中修复。 This is a much more correct solution. 这是一个更正确的解决方案。 Rather than predicting how the .notifyDataSetChanged will affect the views and turning on and off the proper elements given whatever version you're using. 给出你正在使用的任何版本,而不是预测.notifyDataSetChanged将如何影响视图以及打开和关闭正确的元素。 This one will turn on the visibility in all cases. 这个将在所有情况下打开可见性。 Then in the predraw listener to find the view again and turns it back invisible, before it's drawn and after it's in its proper state. 然后在预绘制侦听器中再次找到视图并在它被绘制之前和之后将其变回不可见状态。

And it doesn't matter, if that view is the same one or not, or some future version with some different way of doing it, or a bad adapter that doesn't actually recycle the views, etc. Stable Ids or non-stable ids (flagged not stable, they still have to be actually stable, but that's easily fixable), it's the way to properly do it and future proofed. 并且无关紧要,如果该视图是否相同,或者某些未来版本具有某种不同的方式,或者实际上不回收视图的不良适配器等。稳定的ID或不稳定ID(标记不稳定,它们仍然必须实际稳定,但这很容易修复),这是正确地做到这一点并且未来证明的方法。

The problem here is that which recycled view you're going to get isn't actually clear (they are half trash recycled views after all), not things you can safely store properties in. The behavior was changed in Lollipop to keep stable views actually stable if they can, you could check in the adapter function and the recycled view will likely already have your data because it will give you the same view back again maximally often. 这里的问题是,您将获得的回收视图实际上并不清楚(毕竟它们是半垃圾回收视图),而不是您可以安全存储属性的内容.Lollipop中的行为已更改为实际保持稳定视图如果可以稳定,你可以检查适配器功能,并且循环视图可能已经有你的数据,因为它会最大限度地为你提供相同的视图。 Which is something you want, which is why Lollipop does it that way. 这是你想要的东西,这就是为什么棒棒糖这样做的原因。

The problem here is that the code says mobileView should be made to be visible (the one you're moving), and the switchView should be made invisible (the one you're switching with). 这里的问题是代码说应该使mobileView可见(你正在移动的那个),并且应该使switchView不可见(你正在切换的那个)。 But, these are going to be recycled so they are technically ambiguous which one you'll get back, and depends entirely on how the system is recycling the views, and it's completely allowed to change that behavior for the better, and did. 但是,这些将被回收,因此它们在技术上是模棱两可的,你会得到回报,并完全取决于系统如何回收视图,并且完全允许改变这种行为,并且做到了。

Ps. PS。 I bother to check for null because I personally swap the views at the midway point and it can sometimes end up being null if you hit things just right. 我懒得去检查null,因为我个人在中间点交换视图,如果你恰到好处的话,它有时最终会变为null。

    int deltaYTotal = (mHoverCellOriginalBounds.bottom + mHoverCellOriginalBounds.top) / 2
            + mTotalOffset + deltaY;

...

        boolean isBelow = (belowView != null) && (deltaYTotal > belowView.getTop());
        boolean isAbove = (aboveView != null) && (deltaYTotal < aboveView.getBottom());

You need to visible the mobileView and switchView before adapter notify. 您需要在适配器通知之前显示mobileView和switchView。 This is work for me. 这对我有用。

 mobileView.setVisibility(View.VISIBLE);
 switchView.setVisibility(View.INVISIBLE);

 ((BaseAdapter) getAdapter()).notifyDataSetChanged();

    mDownY = mLastEventY;

    final int switchViewStartTop = switchView.getTop();

    updateNeighborViewsForID(mMobileItemId);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM