背景介紹
在某些特定場(chǎng)景下蜕窿,我們需要考慮加載長(zhǎng)圖的需求故硅,比如加載一幅《清明上河圖》蘑险,這個(gè)好像有點(diǎn)過(guò)分了腐泻,那就加載1/2的《清明上河圖》吧... 那TMD還不是一樣道理决乎。
言歸正傳說(shuō)一下我這邊遇到的情況,之前有圖片或大圖的模塊是劃分為H5來(lái)實(shí)現(xiàn)的派桩,現(xiàn)在需求變更劃分為原生開(kāi)發(fā)构诚,那么問(wèn)題就來(lái)了。圖片尺寸為這一刻我是懵逼的窄坦,哪個(gè)端圖片上傳的時(shí)候沒(méi)限制尺寸和壓縮唤反?mdzz,
吐槽歸吐槽鸭津,還是要擼起袖子解決加載長(zhǎng)圖大圖的問(wèn)題彤侍。
先提供幾個(gè)技術(shù)方案來(lái)對(duì)比一下:
方案1:WebView加載渲染
因?yàn)閳D片本身也是一個(gè)URL地址,也是被WebView渲染逆趋,并且支持縮放盏阶。這是一種實(shí)現(xiàn)方案,遇到幾M的大圖WebView也是會(huì)崩潰Crash闻书,所以這種投機(jī)的方式并不推薦名斟。
方案2:BitmapRegionDecoder
分片加載,使用系統(tǒng)BitmapRegionDecoder去加載本地的圖片魄眉,調(diào)用bitmapRegionDecoder.decodeRegion解析圖片的矩形區(qū)域砰盐,返回bitmap,最終顯示在ImageView上坑律。這種方案需要手動(dòng)處理滑動(dòng)岩梳、縮放手勢(shì),網(wǎng)絡(luò)圖片還要處理緩存策略等問(wèn)題晃择。實(shí)現(xiàn)方式比較繁瑣也不是很推薦冀值。
方案3:SubsamplingScaleImageView
一款封裝BitmapRegionDecoder的三方庫(kù),已經(jīng)處理了滑動(dòng)宫屠,縮放手勢(shì)列疗。我們可以考慮選擇這個(gè)庫(kù)來(lái)進(jìn)行加載長(zhǎng)圖,但是官方上的Demo示例加載的長(zhǎng)圖均為本地圖片浪蹂。這可能并不符合我們的網(wǎng)絡(luò)場(chǎng)景需求抵栈,所以對(duì)于網(wǎng)絡(luò)圖片告材,我們還要考慮不同的加載框架,
SubsamplingScaleImageView Git傳送門
方案4:Glide+SubsamplingScaleImageView混合加載渲染
對(duì)于圖片加載框架竭讳,Glide當(dāng)然是首選创葡,我們使用Glide進(jìn)行網(wǎng)絡(luò)圖片的下載和緩存管理,F(xiàn)ileTarget作為橋梁绢慢,SubsamplingScaleImageView進(jìn)行本地資源圖片的分片加載灿渴,看起來(lái)很靠譜,那么一起來(lái)實(shí)現(xiàn)吧胰舆。
Glide Git傳送門
SubsamplingScaleImageView Git傳送門
fun loadLargeImage(context: Context, res: String, imageView: SubsamplingScaleImageView) {
imageView.isQuickScaleEnabled = true
imageView.maxScale = 15F;
imageView.isZoomEnabled = true;
imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
Glide.with(context).load(res).downloadOnly(object : SimpleTarget<File?>() {
override fun onResourceReady(resource: File, glideAnimation: Transition<in File?>?) {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(resource.absolutePath, options)
val sWidth = options.outWidth
val sHeight = options.outHeight
options.inJustDecodeBounds = false
val wm = ContextCompat.getSystemService(context, WindowManager::class.java)
val width = wm?.defaultDisplay?.width ?: 0
val height = wm?.defaultDisplay?.height ?: 0
if (sHeight >= height
&& sHeight / sWidth >= 3) {
imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP)
imageView.setImage(ImageSource.uri(Uri.fromFile(resource)), ImageViewState(0.5f, PointF(0f, 0f), 0))
} else {
imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM)
imageView.setImage(ImageSource.uri(Uri.fromFile(resource)))
imageView.setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER_IMMEDIATE)
}
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
}
})
}
這是我封裝起來(lái)的一個(gè)方法骚露,就很簡(jiǎn)單就能理解了, 包括SubsamplingScaleImageView的縮放設(shè)置缚窿,默認(rèn)展示狀態(tài)棘幸、縮放、位置倦零,計(jì)算當(dāng)前圖片高寬比為3倍進(jìn)行長(zhǎng)圖渲染處理误续,否則按正常圖片渲染處理。