Індикатор виконання під час завантаження зображення за допомогою Glide


102

Чи можу я завантажити блешню в заповнювач з обертовою анімацією, поки зображення не завантажується за допомогою Glide?

Я намагаюся зробити це, використовуючи .placeholder (R.Drawable.spinner), анімація не з’являється?

Було б чудово, якби хтось міг мені допомогти?

Дякую!


stackoverflow.com/questions/39263403/… Будь ласка, вирішіть цю проблему
Датська Попка

Відповіді:


231

Редагувати: Це тепер дуже просто за допомогою CircularProgressDrawable

build.gradle

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"

MyGlideModule.kt

@GlideModule
class MyGlideModule : AppGlideModule()

MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)

  val circularProgressDrawable = CircularProgressDrawable(this)
  circularProgressDrawable.strokeWidth = 5f
  circularProgressDrawable.centerRadius = 30f
  circularProgressDrawable.start()

  GlideApp.with(applicationContext)
      .load("https://raw.githubusercontent.com/bumptech/glide/master/static/glide_logo.png")
      .placeholder(circularProgressDrawable)
      .into(a_main_image)
}

Це деякі інші фрагменти Glide


Стара відповідь: Ви також можете створити звичайний ProgressBar, а потім приховати його на Glide's onResourceReady().

Метод, який буде викликаний, коли завантаження ресурсу закінчиться.


Приклад :

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final ImageView imageView = (ImageView) findViewById(R.id.img_glide);
    final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress);

    Glide.with(this)
            .load("https://raw.githubusercontent.com/bumptech/glide/master/static/glide_logo.png")
            .listener(new RequestListener<Drawable>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                    progressBar.setVisibility(View.GONE);
                    return false;
                }

                @Override
                public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                    progressBar.setVisibility(View.GONE);
                    return false;
                }
            })
            .into(imageView);
}

activity_main.xml (макет):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ProgressBar
        android:id="@+id/progress"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:visibility="visible" />

    <ImageView
        android:id="@+id/img_glide"
        android:layout_width="match_parent"
        android:layout_height="100dp" />

</RelativeLayout>

Результат:

введіть тут опис зображення


6
OnException повинен робити progressBar.setVisibility (View.GONE); теж. :)
AndroidRuntimeException

1
це добре, але це не показує значення прогресу. Як його додати?
Хан Уайтинг

2
Клас GlideDrawable не може бути вирішений, хоча я імпортував бібліотеку Glide. Чи потрібно додавати будь-які додаткові бібліотеки, щоб використовувати GlideDrawable?
XerXes

Ймовірно, ви імпортуєте версію Glide RC1, де вони замінили GlideDrawable на Drawable. Спробуйте compile 'com.github.bumptech.glide:glide:3.8.0замість цього імпортувати .
Evin1_

Наразі CircularProgressDrawable застарілий. Якщо ви хочете повністю контролювати завантажуване зображення, пропоную відповідь Марка Ченга. developer.android.com/reference/android/support/v4/widget/…
Маркос Роча

42

Ви можете встановити значення прогресу, що завгодно, за допомогою мого GlideImageLoader.

Сподіваюся, це вирішить ваше питання.

ДЕМО ДОДАТОК

Я інкапсулюю завантажувач зображень із прогресом у GlideImageLoader.java & ProgressAppGlideModule .java

Як реалізувати за допомогою 3 кроків:

1. build.gradle

//Glide
implementation 'com.github.bumptech.glide:glide:4.4.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.4.0'

2. Клонуйте GlideImageLoader.java & ProgressAppGlideModule.Java у свій проект

3. Просте використання в будь-якому місці

RequestOptions options = new RequestOptions()
                    .centerCrop()
                    .placeholder(R.drawable.placeholder)
                    .error(R.drawable.ic_pic_error)
                    .priority(Priority.HIGH);

new GlideImageLoader(YOUR.imageView,  
                     YOUR.progressBar).load(url,options);

Повний код Java для клону:

GlideImageLoader.java

public class GlideImageLoader {

    private ImageView mImageView;
    private ProgressBar mProgressBar;

    public GlideImageLoader(ImageView imageView, ProgressBar progressBar) {
        mImageView = imageView;
        mProgressBar = progressBar;
    }

    public void load(final String url, RequestOptions options) {
        if (url == null || options == null) return;

        onConnecting();

        //set Listener & start
        ProgressAppGlideModule.expect(url, new ProgressAppGlideModule.UIonProgressListener() {
            @Override
            public void onProgress(long bytesRead, long expectedLength) {
                if (mProgressBar != null) {
                    mProgressBar.setProgress((int) (100 * bytesRead / expectedLength));
                }
            }

            @Override
            public float getGranualityPercentage() {
                return 1.0f;
            }
        });
        //Get Image
        Glide.with(mImageView.getContext())
                .load(url)
                .transition(withCrossFade())
                .apply(options.skipMemoryCache(true))
                .listener(new RequestListener<Drawable>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                        ProgressAppGlideModule.forget(url);
                        onFinished();
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                        ProgressAppGlideModule.forget(url);
                        onFinished();
                        return false;
                    }
                })
                .into(mImageView);
    }


    private void onConnecting() {
        if (mProgressBar != null) mProgressBar.setVisibility(View.VISIBLE);
    }

    private void onFinished() {
        if (mProgressBar != null && mImageView != null) {
            mProgressBar.setVisibility(View.GONE);
            mImageView.setVisibility(View.VISIBLE);
        }
    }
}

ProgressAppGlideModule.java

@GlideModule
public class ProgressAppGlideModule extends AppGlideModule {

    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
        super.registerComponents(context, glide, registry);
        OkHttpClient client = new OkHttpClient.Builder()
                .addNetworkInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request();
                        Response response = chain.proceed(request);
                        ResponseProgressListener listener = new DispatchingProgressListener();
                        return response.newBuilder()
                                .body(new OkHttpProgressResponseBody(request.url(), response.body(), listener))
                                .build();
                    }
                })
                .build();
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client));
    }

    public static void forget(String url) {
        ProgressAppGlideModule.DispatchingProgressListener.forget(url);
    }
    public static void expect(String url, ProgressAppGlideModule.UIonProgressListener listener) {
        ProgressAppGlideModule.DispatchingProgressListener.expect(url, listener);
    }

    private interface ResponseProgressListener {
        void update(HttpUrl url, long bytesRead, long contentLength);
    }

    public interface UIonProgressListener {
        void onProgress(long bytesRead, long expectedLength);
        /**
         * Control how often the listener needs an update. 0% and 100% will always be dispatched.
         * @return in percentage (0.2 = call {@link #onProgress} around every 0.2 percent of progress)
         */
        float getGranualityPercentage();
    }

    private static class DispatchingProgressListener implements ProgressAppGlideModule.ResponseProgressListener {
        private static final Map<String, UIonProgressListener> LISTENERS = new HashMap<>();
        private static final Map<String, Long> PROGRESSES = new HashMap<>();

        private final Handler handler;

        DispatchingProgressListener() {
            this.handler = new Handler(Looper.getMainLooper());
        }

        static void forget(String url) {
            LISTENERS.remove(url);
            PROGRESSES.remove(url);
        }

        static void expect(String url, UIonProgressListener listener) {
            LISTENERS.put(url, listener);
        }

        @Override
        public void update(HttpUrl url, final long bytesRead, final long contentLength) {
            //System.out.printf("%s: %d/%d = %.2f%%%n", url, bytesRead, contentLength, (100f * bytesRead) / contentLength);
            String key = url.toString();
            final UIonProgressListener listener = LISTENERS.get(key);
            if (listener == null) {
                return;
            }
            if (contentLength <= bytesRead) {
                forget(key);
            }
            if (needsDispatch(key, bytesRead, contentLength, listener.getGranualityPercentage())) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        listener.onProgress(bytesRead, contentLength);
                    }
                });
            }
        }

        private boolean needsDispatch(String key, long current, long total, float granularity) {
            if (granularity == 0 || current == 0 || total == current) {
                return true;
            }
            float percent = 100f * current / total;
            long currentProgress = (long) (percent / granularity);
            Long lastProgress = PROGRESSES.get(key);
            if (lastProgress == null || currentProgress != lastProgress) {
                PROGRESSES.put(key, currentProgress);
                return true;
            } else {
                return false;
            }
        }
    }

    private static class OkHttpProgressResponseBody extends ResponseBody {
        private final HttpUrl url;
        private final ResponseBody responseBody;
        private final ResponseProgressListener progressListener;
        private BufferedSource bufferedSource;

        OkHttpProgressResponseBody(HttpUrl url, ResponseBody responseBody,
                                   ResponseProgressListener progressListener) {
            this.url = url;
            this.responseBody = responseBody;
            this.progressListener = progressListener;
        }

        @Override
        public MediaType contentType() {
            return responseBody.contentType();
        }

        @Override
        public long contentLength() {
            return responseBody.contentLength();
        }

        @Override
        public BufferedSource source() {
            if (bufferedSource == null) {
                bufferedSource = Okio.buffer(source(responseBody.source()));
            }
            return bufferedSource;
        }

        private Source source(Source source) {
            return new ForwardingSource(source) {
                long totalBytesRead = 0L;

                @Override
                public long read(Buffer sink, long byteCount) throws IOException {
                    long bytesRead = super.read(sink, byteCount);
                    long fullLength = responseBody.contentLength();
                    if (bytesRead == -1) { // this source is exhausted
                        totalBytesRead = fullLength;
                    } else {
                        totalBytesRead += bytesRead;
                    }
                    progressListener.update(url, totalBytesRead, fullLength);
                    return bytesRead;
                }
            };
        }
    }
}

2
Ви маєте рацію, я спочатку хочу залишити коментарі, а не опублікувати відповідь. Але, схоже, у мене недостатньо репутації, щоб залишати коментарі. Я додаю сюди необхідний код, щоб запобігти недійсності посилання.
Марк Ченг

відсоток прогресу не відображається при використанні індикатора прогресу, просто відображається панель завантаження
Швидке навчання

нарешті це спрацювало, мені довелося внести зміни до індикатора прогресу з індивідуальним прогресом та фоном, Дякую
Швидке навчання

@Quicklearner, чи можете ви показати мені, як змінити стиль панелі прогресу? тож це може виглядати як демонстраційне зображення вище?
Darari Nur Amali

@DarariNurAmali ви хочете, щоб код реалізував те саме на наведених вище зображеннях?
Швидко навчається

12

Я писав додаток у Котліні і мав саме цю проблему, але, на жаль, прийнята відповідь була на Java. Отже, я переписав це у Котліні.

Glide.with(context)
                .load("<Insert Your URL>")
                .listener(object : RequestListener<Drawable> {
                    override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                        progressBar.visibility = View.GONE
                        return false
                    }

                    override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
                        progressBar.visibility = View.GONE
                        return false
                    }
                })
                .into(holder.imageView)

5

Ще одна хитрість: покладіть ImageViewвсередину RelativeLayouta ProgressBarззаду. Потім завантажте зображення через Glide або Picasso. Це зробить роботу за вас без жодного глибокого копання. Вам більше не потрібно приховувати або показувати індикатор прогресу. Він буде повністю перекритий зображенням.

<RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/_180sdp">
            <ProgressBar
                android:layout_centerInParent="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <ImageView
                android:id="@+id/iv_image"
                android:layout_width="match_parent"
                android:layout_height="@dimen/_180sdp"
                android:scaleType="centerCrop"/>
</RelativeLayout>

4

Ось моє повне рішення з прогресом завантаження кола. Я думаю, що requestOptionsдля досягнення цього краще використовувати атрибути.

CircularProgressDrawable circularProgressDrawable = new CircularProgressDrawable(context);
circularProgressDrawable.setStrokeWidth(5f);
circularProgressDrawable.setCenterRadius(30f);
circularProgressDrawable.start();

RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(circularProgressDrawable);
requestOptions.error(R.drawable.ic_image_not_found);
requestOptions.skipMemoryCache(true);
requestOptions.fitCenter();


glide.load(imagePath) //passing your url to load image.
        .load(imagePath)
        .apply(requestOptions) // here you have all options you need
        .transition(DrawableTransitionOptions.withCrossFade()) // when image (url) will be loaded by glide then this face in animation help to replace url image in the place of placeHolder (default) image.
        .listener(requestListener)
        .into(view); //pass imageView reference to appear the image.

І ви зрозуміли.


3

Спробуйте використовувати RequestOptions

RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.ic_placeholder);
requestOptions.error(R.drawable.ic_error);


Glide.with(MainActivity.this)
            .load(url)
            .apply(requestOptions)
            .into(imageview);

Це єдиний спосіб, яким ви можете реалізувати завантаження зображення за допомогою Glide .


2
але це не додасть індикатор прогресу, як він хоче у запитанні, він просто завантажить зображення
Саттар

3

Так, ми можемо показати навантажувач на ImageView, використовуючи Glide RequestOptions.
1) Використовуйте нижче рядок компіляції у файлі gradle рівня програми.

implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

2) Додайте файл progress_animation.xml у файл, який можна малювати

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/loader_test"
    android:pivotX="50%"
    android:pivotY="50%"/>

3) Додайте зображення loader_test.png нижче для малювання
введіть тут опис зображення

4) Створіть RequestOption, як показано нижче

public  RequestOptions options = new RequestOptions()
            .centerCrop()
            .placeholder(R.drawable.progress_animation)
            .error(R.drawable.user_image)
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .priority(Priority.HIGH)
            .dontAnimate()
            .dontTransform();

5) Нарешті скористайтеся цим, щоб завантажити зображення, як показано нижче

Glide.with(this).load(//*Your image url*//).apply(options).into(image_view);

Це насправді не анімація.
Phani Rithvij
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.