Android Glide, first start based on loadThumbnail, Kotlin(二)

2024-06-20 09:36

本文主要是介绍Android Glide, first start based on loadThumbnail, Kotlin(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android Glide, first start based on loadThumbnail, Kotlin(二)

 

Android Glide, first start based on loadThumbnail, Kotlin(一)中有个小问题,通过loadThumbnail()采集到的缩略图真的就是整张图片的完整缩略图,直接放在正方形小格子里面,明显看到左右或者上下有空隙,因此,现在对这一情况改善,对loadThumbnail采集到的缩略图拉伸成标准的正方形图。

 

import android.content.ContentValues
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.view.setPadding
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormatclass MainActivity : AppCompatActivity() {companion object {const val TAG = "glide-fly"const val SIZE = 450const val VIEW_TYPE = 0const val DATE_TYPE = 1const val SPAN_COUNT = 6const val PAD_SIZE = 1var FIRST_START = true}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val rv: RecyclerView = findViewById(R.id.rv)rv.setHasFixedSize(true)rv.setItemViewCacheSize(SPAN_COUNT * 10)/*rv.setRecyclerListener(object : RecyclerListener {override fun onViewRecycled(holder: RecyclerView.ViewHolder) {if ((holder as MyVH).itemView is MyIV) {GlideApp.with(holder.itemView.context).clear(holder.itemView)}}})*/val layoutManager = MyGridLayoutManager(this, SPAN_COUNT)layoutManager.orientation = LinearLayoutManager.VERTICALrv.layoutManager = layoutManagerval adapter = MyAdapter(this)rv.adapter = adapterlifecycleScope.launch(Dispatchers.IO) {val items = readAllImage(this@MainActivity)items.sortByDescending {it.dateModified}val lists = items.distinctBy {it.dateString}lists.forEach { it_lists ->val idx = items.indexOfFirst {it_lists.dateString == it.dateString}val data = MyData()data.type = DATE_TYPEdata.dateString = it_lists.dateStringitems.add(idx, data) //不要直接加 it_Lists,这里面涉及到List的深拷贝/浅拷贝问题。}withContext(Dispatchers.Main) {adapter.dataChanged(items)}}layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {override fun getSpanSize(position: Int): Int {return if (adapter.getItemViewType(position) == DATE_TYPE) {//group,标题SPAN_COUNT} else {//单个小格子1}}}}class MyGridLayoutManager : GridLayoutManager {constructor(ctx: Context, cnt: Int) : super(ctx, cnt) {}override fun getExtraLayoutSpace(state: RecyclerView.State?): Int {return 1000}}class MyAdapter : RecyclerView.Adapter<MyVH> {private var mItems = arrayListOf<MyData>()private var mContext: Context? = nullprivate var mPlaceholder: Drawable? = nullprivate var mError: Drawable? = nullconstructor(ctx: Context) {mContext = ctxmPlaceholder = ContextCompat.getDrawable(mContext!!, android.R.drawable.ic_menu_gallery)mError = ContextCompat.getDrawable(mContext!!, android.R.drawable.stat_notify_error)}fun dataChanged(items: ArrayList<MyData>) {this.mItems = itemsnotifyDataSetChanged()}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {var v: View?if (viewType == VIEW_TYPE) {v = MyIV(mContext!!)} else {v = LayoutInflater.from(mContext!!).inflate(android.R.layout.simple_list_item_1, null)v.setBackgroundColor(Color.LTGRAY)}return MyVH(v!!)}override fun getItemCount(): Int {return mItems.size}override fun getItemViewType(position: Int): Int {return mItems[position].type}private fun getImageUri(context: Context, filePath: String): Uri? {val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,arrayOf(MediaStore.Images.Media._ID),MediaStore.Images.Media.DATA + "=? ",arrayOf(filePath),null)return if (cursor != null && cursor.moveToFirst()) {val id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))val baseUri = Uri.parse("content://media/external/images/media")Uri.withAppendedPath(baseUri, "" + id)} else {val values = ContentValues()values.put(MediaStore.Images.Media.DATA, filePath)context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)}}override fun onBindViewHolder(holder: MyVH, position: Int) {val type = getItemViewType(position)if (type == VIEW_TYPE) {val path = mItems[holder.adapterPosition].pathval miv = holder.itemView as MyIVif (position > 50) {FIRST_START = false}if (FIRST_START && position < 50) {miv.setImageDrawable(mPlaceholder)val uri = getImageUri(mContext!!, path!!)QuickLoader.Instance().start(mContext!!, uri!!, miv)} else {GlideApp.with(mContext!!).asBitmap().load(path).centerCrop().override(SIZE).placeholder(mPlaceholder).error(mError).into(miv)}} else if (type == DATE_TYPE) {holder.itemView.findViewById<TextView>(android.R.id.text1).text = "${mItems[position].dateString}"}}}class MyVH : RecyclerView.ViewHolder {constructor(itemView: View) : super(itemView) {}}class MyIV : AppCompatImageView {constructor(ctx: Context) : super(ctx) {setPadding(PAD_SIZE)}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)val w = MeasureSpec.getSize(widthMeasureSpec)val h = MeasureSpec.getSize(heightMeasureSpec)val size = Math.max(w, h) //取w,h的最大值。setMeasuredDimension(size, size) //使得ImageView为正方形。}}class MyData {var type = VIEW_TYPEvar dateModified: Long? = 0Lvar dateString: String? = nullvar path: String? = nullvar index: Int? = nulloverride fun toString(): String {return "MyData(type=$type, dateModified=$dateModified, dateString=$dateString, path=$path, index=$index)"}}private fun readAllImage(context: Context): ArrayList<MyData> {val photos = ArrayList<MyData>()//读取所有图片val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null)var index = 0val sdf = SimpleDateFormat("yyyy-MM-dd")while (cursor!!.moveToNext()) {//路径 urival path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))if (TextUtils.isEmpty(path)) {continue}val dateModified = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED))//图片名称//val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))//图片大小//val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))val dateStr = sdf.format(dateModified?.toLong()!! * 1000)val data = MyData()data.type = VIEW_TYPEdata.path = pathdata.dateModified = dateModified.toLong()data.dateString = dateStrdata.index = index++photos.add(data)}cursor.close()return photos}
}

 

 

 

 

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.RectF
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.util.Size
import androidx.appcompat.app.AppCompatActivity
import com.pkg.name0220.MainActivity.Companion.SIZE
import java.util.concurrent.Executors
import kotlin.math.minclass QuickLoader {private var mHandler: MsgHandler? = nullcompanion object {const val THREAD_NUMBER = 4const val WHAT = 0xf01private val inst by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { QuickLoader() }fun Instance() = inst/*** 把采集到的缩略图(可能是瘦长的,也可能是矮平的)拉伸为宽高为标准MainActivity.SIZE的Bitmap。* 注意:Bitmap的API函数createScaledBitmap()相对耗时更多。*/fun scale(srcBmp: Bitmap): Bitmap {val t = System.currentTimeMillis()val bmp = Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888)val c = Canvas(bmp)val width: Int = srcBmp.widthval height: Int = srcBmp.heightval bmpCenterX: Float = width / 2fval bmpCenterY: Float = height / 2fval minVal = min(width, height)val srcRectF = RectF(bmpCenterX - minVal / 2,bmpCenterY - minVal / 2,bmpCenterX + minVal / 2,bmpCenterY + minVal / 2)val dstRectF = RectF(0f, 0f, SIZE.toFloat(), SIZE.toFloat())val matrix = Matrix()//把bitmap中心区域的那一块放到目标的dstRectF里面。matrix.setRectToRect(srcRectF, dstRectF, Matrix.ScaleToFit.CENTER)c.drawBitmap(srcBmp, matrix, null)Log.d("耗时", "scale=${System.currentTimeMillis() - t}")return bmp}}private constructor() {Log.d(MainActivity.TAG, "QuickLoader 初始化")mHandler = MsgHandler()}fun start(ctx: Context, uri: Uri, miv: MainActivity.MyIV) {val msg = mHandler?.obtainMessage(WHAT)msg?.obj = LoadTask(ctx, uri, miv)mHandler?.sendMessage(msg!!)}private class MsgHandler : Handler {private var mExecutorService = Executors.newFixedThreadPool(THREAD_NUMBER)constructor() : super(Looper.getMainLooper()) {Log.d(MainActivity.TAG, "MsgHandler 初始化")}override fun handleMessage(msg: Message) {mExecutorService.execute(msg.obj as LoadTask)}fun destroy() {removeMessages(WHAT)mExecutorService.shutdownNow()mExecutorService = null}}class LoadTask(private val ctx: Context, private val uri: Uri, private val miv: MainActivity.MyIV) : Runnable {override fun run() {Log.d(MainActivity.TAG, "run $uri")val t = System.currentTimeMillis()val bmp = ctx.contentResolver?.loadThumbnail(uri, Size(MainActivity.SIZE, MainActivity.SIZE), null)Log.d(MainActivity.TAG, "LoadTask 耗时:${System.currentTimeMillis() - t} $uri")(ctx as AppCompatActivity).runOnUiThread {miv.setImageBitmap(scale(bmp!!))}}}fun destroy() {mHandler?.destroy()mHandler = null}
}

 

 

 

 

 

 

 

 

Android矩阵Matrix setRectToRect实现标准scaleType中心缩放centerCrop,Kotlin-CSDN博客文章浏览阅读516次,点赞15次,收藏13次。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。基础上,把剪切的区域从矩形Rect变为圆形的Path,当手指在上面的ImageView移动时候,下面同等大小对应的坐标区域显示“剪切”出来的圆形图。https://blog.csdn.net/zhangphil/article/details/139753381

Android Glide, first start based on loadThumbnail, Kotlin(一)-CSDN博客文章浏览阅读642次,点赞13次,收藏12次。【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。Android 13手机图片存储File路径转Uri,Java_android file 转uri-CSDN博客。文章浏览阅读690次。https://blog.csdn.net/zhangphil/article/details/139743546

Android简单把高大于宽或宽大于高的图从中心截成正方形,Kotlin-CSDN博客文章浏览阅读744次,点赞9次,收藏12次。Android BitmapFactory.decodeResource读取原始图片装载成原始宽高Bitmap,Kotlin_bitmapfactory解码宽高-CSDN博客。Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin-CSDN博客。实现的是把原图中心区域的一片小图挖取出来放大放到下面的ImageView里面,现在不再固定中心位置,而是以手指在上图的触点位置为中心位置,挖取一片区域图放大,然后放到下面的ImageView里面。https://blog.csdn.net/zhangphil/article/details/139181062

Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画,Kotlin(二)_android bitmap 动画-CSDN博客文章浏览阅读770次,点赞4次,收藏5次。【代码】Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画,Kotlin(二)_android bitmap 动画https://blog.csdn.net/zhangphil/article/details/135992780Android用setRectToRect实现Bitmap基于Matrix矩阵scale缩放RectF动画,Kotlin(一)_android matrix setrecttorect-CSDN博客文章浏览阅读1.2k次,点赞14次,收藏8次。基于Matrix,控制Bitmap的setRectToRect的目标RectF的宽高。从很小的宽高开始,不断迭代增加setRectToRect的目标RectF的宽高,每次迭代加上一定时延,实现Matrix基础上的动画。文章浏览阅读180次。【代码】Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin。Android矩阵setRectToRect裁剪Bitmap原图Matrix放大,mapRect标记中心区域,Kotlin-CSDN博客。_android matrix setrecttorecthttps://blog.csdn.net/zhangphil/article/details/135980821Android矩阵Matrix变换setRectToRect,Kotlin_android rect 矩阵-CSDN博客文章浏览阅读709次,点赞7次,收藏8次。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。基础上,把剪切的区域从矩形Rect变为圆形的Path,当手指在上面的ImageView移动时候,下面同等大小对应的坐标区域显示“剪切”出来的圆形图。_android rect 矩阵https://blog.csdn.net/zhangphil/article/details/135913218

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放,Kotlin-CSDN博客文章浏览阅读1.1k次,点赞7次,收藏14次。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。基础上,把剪切的区域从矩形Rect变为圆形的Path,当手指在上面的ImageView移动时候,下面同等大小对应的坐标区域显示“剪切”出来的圆形图。_createscaledbitmaphttps://blog.csdn.net/zhangphil/article/details/135961734

 

这篇关于Android Glide, first start based on loadThumbnail, Kotlin(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1077755

相关文章

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(