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实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

GNSS CTS GNSS Start and Location Flow of Android15

目录 1. 本文概述2.CTS 测试3.Gnss Flow3.1 Gnss Start Flow3.2 Gnss Location Output Flow 1. 本文概述 本来是为了做Android 14 Gnss CTS 的相关环境的搭建和测试,然后在测试中遇到了一些问题,去寻找CTS源码(/cts/tests/tests/location/src/android/locat

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR