แถบความคืบหน้าขณะโหลดภาพโดยใช้ Glide


106

ฉันสามารถโหลดสปินเนอร์ในตัวยึดที่มีภาพเคลื่อนไหวแบบหมุนได้จนกว่าจะโหลดภาพโดยใช้ Glide ได้หรือไม่

ฉันกำลังพยายามทำโดยใช้ .placeholder (R.Drawable.spinner) ไม่มีภาพเคลื่อนไหวเกิดขึ้น?

จะดีมากถ้ามีใครช่วยฉันได้?

ขอบคุณ!


stackoverflow.com/questions/39263403/…โปรดแก้ปัญหานั้น
Danish Butt

คำตอบ:


241

แก้ไข:ตอนนี้ง่ายมากด้วย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)
}

นี่คือตัวอย่างข้อมูลร่อนอื่น ๆ


คำตอบเก่า:นอกจากนี้คุณยังสามารถสร้าง ProgressBar 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>

ผลลัพธ์:

ใส่คำอธิบายภาพที่นี่


7
onException ควรทำ progressBar.setVisibility (View.GONE); เกินไป. :)
AndroidRuntimeException

1
เป็นสิ่งที่ดี แต่ไม่ได้แสดงถึงคุณค่าของความก้าวหน้า จะเพิ่มได้อย่างไร?
Han Whiteking

2
ไม่สามารถแก้ไขคลาส GlideDrawable ได้แม้ว่าฉันจะนำเข้าไลบรารี Glide แล้ว ฉันต้องเพิ่มไลบรารีเพิ่มเติมเพื่อใช้ GlideDrawable หรือไม่
XerXes

คุณอาจจะนำเข้ารุ่น RC1 ของ Glide ซึ่งจะแทนที่ GlideDrawable สำหรับ Drawable ลองนำเข้าcompile 'com.github.bumptech.glide:glide:3.8.0แทนในตอนนี้
Evin1_

ขณะนี้ CircularProgressDrawable เลิกใช้งานแล้ว หากคุณต้องการควบคุมรูปภาพที่กำลังโหลดอย่างเต็มที่ฉันขอแนะนำคำตอบของ Mark Cheng developer.android.com/reference/android/support/v4/widget/…
Marcos Rocha

42

คุณสามารถตั้งค่าความคืบหน้าตามที่คุณต้องการด้วย GlideImageLoader ของฉัน

ฉันหวังว่ามันจะช่วยแก้ปัญหาของคุณได้

แอปสาธิต

ฉันห่อหุ้ม Image loader ด้วยความคืบหน้าใน 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
คุณพูดถูกตอนแรกฉันต้องการแสดงความคิดเห็นมากกว่าโพสต์คำตอบ แต่ดูเหมือนว่าฉันไม่มีชื่อเสียงพอที่จะแสดงความคิดเห็น ฉันเพิ่มรหัสที่จำเป็นที่นี่เพื่อป้องกันไม่ให้ลิงก์ไม่ถูกต้อง
Mark Cheng

เปอร์เซ็นต์ความคืบหน้าไม่แสดงในการใช้แถบความคืบหน้าเพียงแค่แสดงแถบการโหลดเท่านั้น
เรียนรู้อย่างรวดเร็ว

ในที่สุดมันก็ใช้งานได้ฉันต้องทำการเปลี่ยนแปลงสำหรับแถบความคืบหน้าด้วยความคืบหน้าและพื้นหลังที่กำหนดเองขอบคุณ
เรียนรู้อย่างรวดเร็ว

@Quicklearner ช่วยแสดงวิธีเปลี่ยนรูปแบบแถบความคืบหน้าได้ไหม จึงจะดูเหมือนภาพสาธิตด้านบน?
Darari Nur Amali

@DarariNurAmali คุณต้องการให้โค้ดใช้งานแบบเดียวกันในภาพด้านบนหรือไม่?
เรียนด่วน

13

ฉันกำลังเขียนแอปใน Kotlin และประสบปัญหานี้ แต่น่าเสียดายที่คำตอบที่ได้รับการยอมรับคือใน Java ดังนั้นฉันจึงเขียนมันใหม่ใน Kotlin

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ด้านในของคุณRelativeLayoutด้วย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>

5

นี่คือโซลูชันที่สมบูรณ์ของฉันพร้อมความคืบหน้าในการโหลดวงกลม ฉันคิดว่าควรใช้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);

นี้เป็นวิธีหนึ่งที่คุณสามารถใช้ภาพโหลดใช้กับฉุยฉาย


2
แต่จะไม่เพิ่มแถบความคืบหน้าตามที่เขาต้องการในคำถามมันจะโหลดภาพ
Sattar

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 ใน drawable

<?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);

มันไม่ได้เป็นภาพเคลื่อนไหวจริงๆ
ภาณีฤทธิ์วิจิตร
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.