13

私はこれについて長い間頭を悩ませてきましたが、運がなかったので答えを探しました! 些細なことのように思えますが、私の知る限り、そうではありません。

コンテンツが読み込まれて表示される前に、すべてのアイテム (ビュー) が回転する ProgressBar を表示する Android アプリケーションでリストビューを使用しています (コンテンツは http 呼び出しと json を介して取得されるため、処理に時間がかかる場合があります)。問題は、回転する進行状況バーが互いに独立して回転するため、見栄えの良い読み込みマーカーが同期して並んでいるのではなく、渦巻く混乱の効果が生じることです.

私が思いつくことができるすべてを試しました... getView() で ProgressBar をリサイクルしません... 同じ ProgressBar のインスタンスを 1 つだけ持っています... リスト項目が表示されるたびに ProgressBars android:progress をリセットします (onScroll 経由) () in the activity)... などですが、作成時 (アダプターで getView が呼び出されたとき) にスピンし始めるため、同じサイクル同期になることはありません。

ここに画像の説明を入力

どんな提案も大歓迎です!

4

6 に答える 6

2

編集:今は完璧に動作します!-アニメーションリスナーの呼び出しを挿入し、最初の繰り返しの後にsetStartOffset()を0に戻して、ランダムに「ジャンプ」し続けないようにしました。


この問題の実用的な解決策を見つけました。これは、アニメーションのタイミングを現在のシステムのミリ秒に合わせると機能します。mAnimationリフレクションを使用してフィールドを取得するため、これは少しハックProgressBarです。そうは言っても、このフィールドは作成されてからAndroidソースに残っています(4.2まで機能します)。

android.widget.SyncedProgressBarクラスを作成ProgressBarし、.xmlファイルの代わりに使用します。基本的に、アニメーションはアニメーション期間の開始時に開始されます。また、それが機能することを確認するためにいじることもできますsetDuration(500)(プログレスホイールは非常に速く回転します)。お役に立てれば!

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();
    }

}
于 2012-11-25T22:20:28.317 に答える
1

これを機能させる方法は次のとおりです。AnimationDrawable を 1 つだけ使用し、コールバックを多重化します。ProgressBar は実際には何も追加しません。View に固執することもできます。Drawable の管理をバイパスする View のサブクラスを作成します。

public class Whirly extends View
{
   Drawable image = null;

   public Whirly(Context context, AttributeSet attr)
   {
      super(context, attr);
   }

   @Override
   public void draw(Canvas canvas)
   {
      if (image!=null)
         image.draw(canvas);
   }

   public void setImageDrawable(Drawable image)
   {
      this.image = image;
      invalidate();
   }
}

次に、何らかの形ですべての渦巻きを追跡するアクティビティを作成します。

public class Demo extends Activity implements Drawable.Callback
{
   private Handler h;
   private AnimationDrawable a;

   private Whirly w0;
   private Whirly w1;
   private Whirly w2;
   private Whirly w3;

   public void onCreate(Bundle bundle)
   {
      ...

      h = new Handler();

      a = (AnimationDrawable) getResources().getDrawable(R.drawable.mywhirly);
      int width = a.getIntrinsicWidth();
      int height = a.getIntrinsicHeight();
      a.setBounds(0, 0, width, height);

      w0 = (Whirly) findViewById(R.id.whirly0);
      w1 = (Whirly) findViewById(R.id.whirly1);
      w2 = (Whirly) findViewById(R.id.whirly2);
      w3 = (Whirly) findViewById(R.id.whirly3);

      w0.setImageDrawable(a);
      w1.setImageDrawable(a);
      w2.setImageDrawable(a);
      w3.setImageDrawable(a);

      a.setCallback(this);
      a.start();
   }

   public void invalidateDrawable (Drawable who)
   {
      w0.invalidate();
      w1.invalidate();
      w2.invalidate();
      w3.invalidate();
   }

   public void scheduleDrawable (Drawable who, Runnable what, long when)
   {
      h.postAtTime(what, who, when);
   }

   public void unscheduleDrawable (Drawable who, Runnable what)
   {
      h.removeCallbacks(what, who);
   }
}
于 2012-06-20T14:16:07.333 に答える
0

アダプタ getView() で、progressView を無効にしてから、progressView ごとに無効にします。

handler.postAtTime(new Runnable(){

public void run(){
     progressView.setEnabled(true);
}}, someTimeInTheFuture
);

これにより、すべての progressViews が同時に有効になります。これはうまくいくかもしれませんが、私はテストしていません。これが機能しない場合は、progressView を動的に追加することをお勧めします (レイアウトには含まれませんが、addView() を介して追加します)。ただし、ランナブルで実行します。ここで重要なのは、すべてが同時に追加されるようにすることです。

于 2012-06-20T13:11:40.380 に答える
0

ソースコードを掘り下げると、回転する画像はプライベートのために回転しているドローアブルであることがわかりますAnimation。ビューまたはアニメーションを取得する方法がないため、すべてのビューで 1 つのアニメーションを再利用するという考えを捨てました。あなたの唯一の選択肢は、最も美しい解決策ではありませんが、Jug6ernaut が提案したものだと思います。

于 2012-06-20T15:26:48.213 に答える
0

あなたの各行がListView画面外に移動するとリサイクルされるため、これが可能かどうかはわかりません。画面に新しい行が表示されるProgressBarと、すべてのビューを相互に再同期する必要があります。すべての行の同期を維持することは、大きな PITA になるでしょう。

すべてのリスト データを 1 つの要求で読み込み、そのデータをローカル ストレージにキャッシュすることを検討しましたか? これははるかに効率的であり、ユーザー エクスペリエンスが向上します。ListView空の行をすぐにロードする はあまり役に立ちません。リストが完全に読み込まれるのを待ちたいと思います。

于 2012-06-22T00:49:32.623 に答える