每一个列表视图项纺纱进度条纺纱、视图、进度条、列表

2023-09-04 09:36:16 作者:覀苽菋菂夏兲

我一直在抓我的头在这个很长一段时间,现在和搜索没有任何的运气答案! 这似乎是微不足道的,但据我所知,事实并非如此。

I've been scratching my head over this for a long time now and searched for an answer without any luck! It seems to be trivial, but as far as I know, it isn't.

我用在我的Andr​​oid应用程序列表视图,其中每个项目(视图)之前,会显示一个旋转的进度 内容加载和显示(内容是通过HTTP调用和JSON获取,因此它可能需要一段时间才能处理)。 的问题是,纺丝进度条彼此独立地旋转,因此形成了旋流的作用 混乱,而不是好看的装载标志物syncronised一行。

I use a listview in my Android application where every item (view) displays a spinning ProgressBar before the content is loaded and displayed (the content is retrieved through http calls and json, so it may take a while to process). The problem is that the spinning progress bars rotates independently of each other, thus creating the effect of a whirling chaos instead of a syncronised row of good-looking loading markers.

我已经试过所有我能想出...不是回收进度的getView()...有相同的进度只有一个实例... 重置ProgressBars机器人:每当进度列表项获得可见的(通过onScroll()中的活动)...等, 但自从他们开始创作的时间(当getView被调用的适配器)旋转,他们将永远不会有相同的周期同步。

I've tried everything i could come up with... not recycling the ProgressBar in getView()... have only one instance of the same ProgressBar... resetting the ProgressBars android:progress whenever the list items gets visible (via onScroll() in the activity)... etc, but since they start to spin in creation time (when getView gets called in the adapter) they will never have the same cycle sync.

任何建议,欢迎!

推荐答案

修改:现在的作品完美的 - 插入动画监听通话setStartOffset()返回到0后第一个重复,这样它不会让跳楼随机。

Now works perfectly! - inserted animation listener call setStartOffset() back to 0 after the first repeat so that it doesn't keep "jumping" randomly.

我发现了这个问题,它的工作原理是定时动画到当前系统毫秒的工作方案。这是一个黑客位的,因为它使用反射来得到进度 mAnimation 字段。话虽这么说,这一领域仍然存在在Android源,因为它创建(工程至4.2)。

I found a working solution for this issue, which works by timing the animation to the current system milliseconds. It's a bit of a hack, as it uses reflection to get the mAnimation field in ProgressBar. That being said, this field has remained in place in the Android sources since it was created (works up to 4.2).

创建 android.widget.SyncedProgressBar 类,并用它来代替进度在你的.xml文件。它基本上使动画开始在动画的持续时间的开始。您也可以玩弄 setDuration(500)来验证它的工作原理(进度车轮会打滑真的很快)。希望这有助于!

Create the android.widget.SyncedProgressBar class, and use it instead of ProgressBar in your .xml files. It essentially makes the animation start at the beginning of the animation duration. You can also play around with setDuration(500) to verify that it works (the progress wheel will spin really quickly). Hope this helps!

package android.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;

import java.lang.reflect.Field;

/**
* @author Oleg Vaskevich
*
*/
public class SyncedProgressBar extends ProgressBar {

    public SyncedProgressBar(Context context) {
        super(context);
        modifyAnimation();
    }

    public SyncedProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        modifyAnimation();
    }

    public SyncedProgressBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        modifyAnimation();
    }

    @Override
    public void setVisibility(int v) {
        super.setVisibility(v);
        modifyAnimation();
    }

    @SuppressLint("NewApi")
    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        modifyAnimation();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        modifyAnimation();
    }

    @Override
    public synchronized void setIndeterminate(boolean indeterminate) {
        super.setIndeterminate(indeterminate);
        modifyAnimation();
    }

    public void modifyAnimation() {
        Field mAnim;
        try {
            mAnim = ProgressBar.class.getDeclaredField("mAnimation");
            mAnim.setAccessible(true);
            AlphaAnimation anim = (AlphaAnimation) mAnim.get(this);
            if (anim == null)
                return;

            // set offset to that animations start at same time
            long duration = anim.getDuration();
            long timeOffset = System.currentTimeMillis() % duration;
            anim.setDuration(duration);
            anim.setStartOffset(-timeOffset);
            anim.setAnimationListener(new AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                    animation.setStartOffset(0);
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                }
            });
        } catch (Exception e) {
            Log.d("SPB", "that didn't work out...", e);
            return;
        }
        postInvalidate();
    }

}