From ca9a35ff78bec03dfd727f9a8dbfedc517cfa293 Mon Sep 17 00:00:00 2001 From: rosuH Date: Wed, 1 Jul 2020 18:12:22 +0800 Subject: [PATCH] [Add] - User can add custom ImageEngine. - Custom ImageEngine Example. [Update] - Icon scale type. [Fix] - Support Glide 4.9 below version which would cause NoMethodFoundError. --- .../filepicker/adapter/FileListAdapter.kt | 25 ++------ .../filepicker/config/FilePickerConfig.kt | 12 ++++ .../filepicker/config/FilePickerManager.kt | 12 ++-- .../me/rosuh/filepicker/engine/GlideEngine.kt | 37 ++++++++---- .../me/rosuh/filepicker/engine/ImageEngine.kt | 6 +- .../filepicker/engine/ImageLoadController.kt | 60 +++++++++++++------ .../rosuh/filepicker/engine/PicassoEngine.kt | 26 +++++--- .../rosuh/filepicker/utils/ScreenUtils.java | 43 ------------- .../main/res/layout/item_list_file_picker.xml | 1 + sample/build.gradle | 9 ++- .../java/me/rosuh/sample/SampleActivity.kt | 20 +++++++ 11 files changed, 137 insertions(+), 114 deletions(-) diff --git a/filepicker/src/main/java/me/rosuh/filepicker/adapter/FileListAdapter.kt b/filepicker/src/main/java/me/rosuh/filepicker/adapter/FileListAdapter.kt index 53cf4c9..8c214ee 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/adapter/FileListAdapter.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/adapter/FileListAdapter.kt @@ -1,6 +1,5 @@ package me.rosuh.filepicker.adapter -import android.net.Uri import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View @@ -246,19 +245,11 @@ class FileListAdapter( val resId: Int = itemImpl.fileType?.fileIconResId ?: R.drawable.ic_unknown_file_picker when (itemImpl.fileType) { - is RasterImageFileType -> { + is RasterImageFileType, is VideoFileType -> { ImageLoadController.load( context, mIcon, - Uri.fromFile(File(itemImpl.filePath)), - resId - ) - } - is VideoFileType -> { - ImageLoadController.load( - context, - mIcon, - Uri.fromFile(File(itemImpl.filePath)), + itemImpl.filePath, resId ) } @@ -300,19 +291,11 @@ class FileListAdapter( val resId: Int = itemImpl.fileType?.fileIconResId ?: R.drawable.ic_unknown_file_picker when (itemImpl.fileType) { - is RasterImageFileType -> { - ImageLoadController.load( - context, - mIcon, - Uri.fromFile(File(itemImpl.filePath)), - resId - ) - } - is VideoFileType -> { + is RasterImageFileType, is VideoFileType -> { ImageLoadController.load( context, mIcon, - Uri.fromFile(File(itemImpl.filePath)), + itemImpl.filePath, resId ) } diff --git a/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerConfig.kt b/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerConfig.kt index fcb0948..db5af06 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerConfig.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerConfig.kt @@ -5,6 +5,7 @@ import android.support.annotation.NonNull import android.support.annotation.StringRes import me.rosuh.filepicker.FilePickerActivity import me.rosuh.filepicker.R +import me.rosuh.filepicker.engine.ImageEngine /** * @@ -112,6 +113,12 @@ class FilePickerConfig(private val pickerManager: FilePickerManager) { var emptyListTips: String = contextRes.getString(R.string.empty_list_tips_file_picker) private set + /** + * 如果您的 Glide 版本低于 4.9, 请使用自定义的 [ImageEngine] + */ + var customImageEngine: ImageEngine? = null + private set + fun showHiddenFiles(isShow: Boolean): FilePickerConfig { isShowHiddenFiles = isShow return this @@ -216,6 +223,11 @@ class FilePickerConfig(private val pickerManager: FilePickerManager) { return this } + fun imageEngine(ie: ImageEngine): FilePickerConfig { + this.customImageEngine = ie + return this + } + fun forResult(requestCode: Int) { val activity = pickerManager.contextRef?.get()!! val fragment = pickerManager.fragmentRef?.get() diff --git a/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerManager.kt b/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerManager.kt index d3af6a3..ed438cb 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerManager.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/config/FilePickerManager.kt @@ -2,6 +2,7 @@ package me.rosuh.filepicker.config import android.app.Activity import android.support.v4.app.Fragment +import me.rosuh.filepicker.engine.ImageLoadController import java.lang.ref.WeakReference /** @@ -26,11 +27,6 @@ object FilePickerManager { return config } - private fun reset() { - contextRef?.clear() - fragmentRef?.clear() - } - /** * 不能使用 fragmentRef.getContext(),因为无法保证外部的代码环境 */ @@ -58,4 +54,10 @@ object FilePickerManager { fun obtainData(): List { return dataList } + + private fun reset() { + contextRef?.clear() + fragmentRef?.clear() + ImageLoadController.reset() + } } \ No newline at end of file diff --git a/filepicker/src/main/java/me/rosuh/filepicker/engine/GlideEngine.kt b/filepicker/src/main/java/me/rosuh/filepicker/engine/GlideEngine.kt index c1d7490..f826b63 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/engine/GlideEngine.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/engine/GlideEngine.kt @@ -1,14 +1,16 @@ package me.rosuh.filepicker.engine import android.content.Context -import android.graphics.drawable.Drawable -import android.net.Uri +import android.graphics.Bitmap +import android.media.ThumbnailUtils import android.widget.ImageView import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.target.Target +import me.rosuh.filepicker.R +import me.rosuh.filepicker.utils.ScreenUtils /** * @author rosu @@ -16,33 +18,46 @@ import com.bumptech.glide.request.target.Target * An [ImageEngine] implementation by using Glide */ class GlideEngine : ImageEngine { - override fun loadImage(context: Context?, imageView: ImageView?, uri: Uri?, placeholder: Int) { + override fun loadImage( + context: Context?, + imageView: ImageView?, + url: String?, + placeholder: Int + ) { if (context == null || imageView == null) { return } Glide.with(context) - .load(uri) - .addListener(object : RequestListener { + .asBitmap() + .load(url) + .addListener(object : RequestListener { override fun onLoadFailed( e: GlideException?, model: Any?, - target: Target?, + target: Target?, isFirstResource: Boolean ): Boolean { - imageView.setImageResource(placeholder) + imageView.setImageResource(R.drawable.ic_unknown_file_picker) return true } override fun onResourceReady( - resource: Drawable?, + resource: Bitmap?, model: Any?, - target: Target?, + target: Target?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { - return false + // Create thumbnail for better effect. + val thumbnailBitmap = + ThumbnailUtils.extractThumbnail( + resource, + imageView.width.coerceAtLeast(ScreenUtils.dipToPx(context, 40f)), + imageView.height.coerceAtLeast(ScreenUtils.dipToPx(context, 40f)) + ) + imageView.setImageBitmap(thumbnailBitmap) + return true } - }) .into(imageView) } diff --git a/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageEngine.kt b/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageEngine.kt index aa2afa6..695a850 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageEngine.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageEngine.kt @@ -12,9 +12,9 @@ import android.widget.ImageView */ interface ImageEngine { /** - * 调用此接口加载图片,一般情况下[uri]参数表示图片的本地路径 path,通过[Uri.parse]得到的值。通常是 file:/// 开头 + * 调用此接口加载图片,一般情况下[url]参数表示图片的本地路径 path,通过[Uri.parse]得到的值。通常是 file:/// 开头 * 如果加载失败,将使用[placeholder] - * Call this interface to load the picture. Generally, the [uri] parameter indicates the local + * Call this interface to load the picture. Generally, the [url] parameter indicates the local * path of the picture, and the value obtained through [Uri.parse]. * Usually starts with file:/// * If loading fails, [placeholder] will be used @@ -22,7 +22,7 @@ interface ImageEngine { fun loadImage( context: Context?, imageView: ImageView?, - uri: Uri?, + url: String?, placeholder: Int ) } \ No newline at end of file diff --git a/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageLoadController.kt b/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageLoadController.kt index b2de767..dfcbc9d 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageLoadController.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/engine/ImageLoadController.kt @@ -1,15 +1,16 @@ package me.rosuh.filepicker.engine import android.content.Context -import android.net.Uri +import android.util.Log import android.widget.ImageView import me.rosuh.filepicker.R +import me.rosuh.filepicker.config.FilePickerManager /** * @author rosu * @date 2020-04-15 * 一个全局的图片加载控制类,包含了判断是否存在以及存在哪种图片加载引擎。 - * A global image loading control class, including determining whether there is and what kind of + * A global image loading controller, including determining whether there is and what kind of * image loading engine exists. */ object ImageLoadController { @@ -37,8 +38,43 @@ object ImageLoadController { private var engine: ImageEngine? = null - init { + /** + * 加载图片,如果没有不存在图片加载引擎,那么将使用默认 icon + * Load images, if there is no image loading engine, then the default icon is used + */ + fun load( + context: Context, + iv: ImageView, + url: String, + placeholder: Int? = R.drawable.ic_unknown_file_picker + ) { + if (engine == null && !initEngine()) { + iv.setImageResource(placeholder ?: R.drawable.ic_unknown_file_picker) + return + } + try { + engine?.loadImage(context, iv, url, placeholder ?: R.drawable.ic_unknown_file_picker) + } catch (e: NoSuchMethodError) { + Log.d( + "ImageLoadController", """ + AndroidFilePicker throw NoSuchMethodError which means current Glide version was not supported. + We recommend using 4.9+ or you should implements your own ImageEngine. + Ref:https://github.com/rosuH/AndroidFilePicker/issues/76 + """.trimIndent() + ) + iv.setImageResource(placeholder ?: R.drawable.ic_unknown_file_picker) + } + } + + /** + * 每次配置更新的时候,都需要重新初始化图片加载器 + * Every time the configuration is updated, we need to re-initialize the image loader + */ + private fun initEngine(): Boolean { engine = when { + FilePickerManager.config.customImageEngine != null -> { + FilePickerManager.config.customImageEngine + } enableGlide -> { GlideEngine() } @@ -49,22 +85,10 @@ object ImageLoadController { null } } + return engine != null } - /** - * 加载图片,如果没有不存在图片加载引擎,那么家使用默认 icon - * Load images, if there is no image loading engine, then the default icon is used - */ - fun load( - context: Context, - iv: ImageView, - uri: Uri, - placeholder: Int? = R.drawable.ic_unknown_file_picker - ) { - if (engine == null) { - iv.setImageResource(placeholder ?: R.drawable.ic_unknown_file_picker) - return - } - engine?.loadImage(context, iv, uri, placeholder ?: R.drawable.ic_unknown_file_picker) + fun reset() { + engine = null } } \ No newline at end of file diff --git a/filepicker/src/main/java/me/rosuh/filepicker/engine/PicassoEngine.kt b/filepicker/src/main/java/me/rosuh/filepicker/engine/PicassoEngine.kt index c468681..60f9365 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/engine/PicassoEngine.kt +++ b/filepicker/src/main/java/me/rosuh/filepicker/engine/PicassoEngine.kt @@ -1,9 +1,9 @@ package me.rosuh.filepicker.engine import android.content.Context -import android.net.Uri import android.widget.ImageView import com.squareup.picasso.Picasso +import java.io.File /** * @author rosu @@ -11,12 +11,22 @@ import com.squareup.picasso.Picasso * An [ImageEngine] implementation by using Picasso */ class PicassoEngine : ImageEngine { - override fun loadImage(context: Context?, imageView: ImageView?, uri: Uri?, placeholder: Int) { - Picasso.with(context) - .load(uri) - .fit() - .centerCrop() - .placeholder(placeholder) - .into(imageView) + override fun loadImage( + context: Context?, + imageView: ImageView?, + url: String?, + placeholder: Int + ) { + if (url?.startsWith("http") == true) { + Picasso.with(context) + .load(url) + .placeholder(placeholder) + .into(imageView) + } else { + Picasso.with(context) + .load(File(url)) + .placeholder(placeholder) + .into(imageView) + } } } \ No newline at end of file diff --git a/filepicker/src/main/java/me/rosuh/filepicker/utils/ScreenUtils.java b/filepicker/src/main/java/me/rosuh/filepicker/utils/ScreenUtils.java index 32e30c6..d47a54b 100644 --- a/filepicker/src/main/java/me/rosuh/filepicker/utils/ScreenUtils.java +++ b/filepicker/src/main/java/me/rosuh/filepicker/utils/ScreenUtils.java @@ -20,32 +20,6 @@ public static int dipToPx(Context context, float dipValue) { } - /** - * px 转 dp - * @param context - * @param px - * @return - */ - public static float pxToDip(Context context, float px) { - if (context == null) { - return -1; - } - return px / context.getResources().getDisplayMetrics().density; - } - - - /** - * sp 转 px - * @param context - * @param spValue - * @return - */ - public static int spToPx(Context context, float spValue) { - final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; - return (int) (spValue * fontScale + 0.5f); - } - - /** * 获得屏幕宽度像素 * @param context @@ -77,21 +51,4 @@ public static int getScreenHeightInPixel(Context context) { return screenH; } - /** - * 是否横屏 - */ - public static boolean isLandScape(Context context) { - return getScreenWidthInPixel(context) > getScreenHeightInPixel(context); - } - - /** - * 将像素转为 dp - * @param context - * @param pxValue 像素 - * @return - */ - public static int px2dp(Context context, float pxValue){ - return (int)(pxValue / context.getResources().getDisplayMetrics().density); - } - } diff --git a/filepicker/src/main/res/layout/item_list_file_picker.xml b/filepicker/src/main/res/layout/item_list_file_picker.xml index 7364f7c..37ae707 100644 --- a/filepicker/src/main/res/layout/item_list_file_picker.xml +++ b/filepicker/src/main/res/layout/item_list_file_picker.xml @@ -31,6 +31,7 @@ android:id="@+id/iv_icon_list_file_picker" android:layout_width="40dp" android:layout_height="40dp" + android:scaleType="centerCrop" android:layout_centerVertical="true" android:layout_marginStart="16dp" android:layout_marginLeft="16dp" diff --git a/sample/build.gradle b/sample/build.gradle index 1b2abdc..994a540 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -29,11 +29,10 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') debugImplementation project(':filepicker') -// implementation ("com.github.bumptech.glide:glide:4.8.0") { -// exclude group: "com.android.support" -// } - implementation 'com.squareup.picasso:picasso:2.5.2' -// releaseImplementation 'me.rosuh:AndroidFilePicker:0.6.1' + implementation ("com.github.bumptech.glide:glide:4.9.0") { + exclude group: "com.android.support" + } +// implementation 'com.squareup.picasso:picasso:2.5.2' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' diff --git a/sample/src/main/java/me/rosuh/sample/SampleActivity.kt b/sample/src/main/java/me/rosuh/sample/SampleActivity.kt index dc52bfd..8dbec17 100644 --- a/sample/src/main/java/me/rosuh/sample/SampleActivity.kt +++ b/sample/src/main/java/me/rosuh/sample/SampleActivity.kt @@ -1,6 +1,8 @@ package me.rosuh.sample +//import com.bumptech.glide.Glide import android.app.Activity +import android.content.Context import android.content.Intent import android.os.Bundle import android.support.v4.app.DialogFragment @@ -11,11 +13,14 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button +import android.widget.ImageView import android.widget.Toast +import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.demo_activity_main.* import me.rosuh.filepicker.adapter.FileListAdapter import me.rosuh.filepicker.bean.FileItemBeanImpl import me.rosuh.filepicker.config.* +import me.rosuh.filepicker.engine.ImageEngine import me.rosuh.filepicker.filetype.FileType import me.rosuh.filepicker.filetype.RasterImageFileType import me.rosuh.filepicker.utils.ScreenUtils @@ -50,6 +55,21 @@ class SampleActivity : AppCompatActivity() { FilePickerManager .from(this@SampleActivity) .setTheme(getRandomTheme()) + .imageEngine(object : ImageEngine { + override fun loadImage( + context: Context?, + imageView: ImageView?, + url: String?, + placeholder: Int + ) { + // 应该使用 loadImage 传递过来的 context,而不是您自己的 context + // You should use the context passed by loadImage(), not your own context + Glide + .with(context!!) + .load(url) + .into(imageView!!) + } + }) .enableSingleChoice() .forResult(FilePickerManager.REQUEST_CODE) }