Android Glide自定义AppCompatImageView切分成若干小格子,每个小格子onDraw绘制Bitmap,Kotlin(1)

Android Glide自定义AppCompatImageView切分成若干小格子,每个小格子onDraw绘制Bitmap,Kotlin(1)

 

垂直方向的RecyclerView,每行一个AppCompatImageView,每个AppCompatImageView被均匀切割成n个小格子, 每个小格子通过Glide加载出来Bitmap,然后onDraw绘制整行。

 

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

 

implementation("com.github.bumptech.glide:glide:4.16.0")

 

import android.content.Context
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext


class MainActivity : AppCompatActivity() {
    companion object {
        const val VIEW_TYPE = 0
        const val TAG = "fly/MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val rv = findViewById<RecyclerView>(R.id.recycler_view)

        val layoutManager = LinearLayoutManager(this)
        layoutManager.orientation = LinearLayoutManager.VERTICAL
        rv.layoutManager = layoutManager

        val adapter = MyAdapter()
        rv.adapter = adapter

        lifecycleScope.launch(Dispatchers.IO) {
            val items = readAllImage(this@MainActivity)
            items.reverse()

            val data = sliceDataList(items)
            withContext(Dispatchers.Main) {
                adapter.dataChanged(data)
            }
        }
    }

    private fun sliceDataList(data: ArrayList<MyData>): ArrayList<ArrayList<MyData>> {
        var k: Int
        val lists = ArrayList<ArrayList<MyData>>()
        for (i in data.indices step BatchBitmapView.ROW_SIZE) {
            val temp = ArrayList<MyData>()

            k = 0
            for (j in 0 until BatchBitmapView.ROW_SIZE) {
                k = i + j
                if (k >= data.size) {
                    break
                }
                temp.add(data[k])
            }

            lists.add(temp)
        }

        return lists
    }

    class MyAdapter : RecyclerView.Adapter<MyVH>() {
        private var items = ArrayList<ArrayList<MyData>>()

        fun dataChanged(items: ArrayList<ArrayList<MyData>>) {
            this.items = items

            notifyDataSetChanged()
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {
            Log.d(TAG, "onCreateViewHolder")
            val view = BatchBitmapView(parent.context)
            return MyVH(view)
        }

        override fun getItemCount(): Int {
            return items.size
        }

        override fun getItemViewType(position: Int): Int {
            return VIEW_TYPE
        }

        override fun onBindViewHolder(holder: MyVH, position: Int) {
            Log.d(TAG, "onBindViewHolder $position")
            val biv = (holder.itemView as? BatchBitmapView)
            biv?.setRowBitmapData(items[position], position)
        }
    }

    class MyVH(itemView: BatchBitmapView) : RecyclerView.ViewHolder(itemView) {

    }

    class MyData(var path: String, var index: Int)

    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 = 0
        while (cursor!!.moveToNext()) {
            //路径 uri
            val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))

            //图片名称
            //val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))

            //图片大小
            //val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))

            photos.add(MyData(path, index++))
        }
        cursor.close()

        return photos
    }
}

 

 

 

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.Log
import androidx.appcompat.widget.AppCompatImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition


class BatchBitmapView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatImageView(context, attributeSet, defStyleAttr) {
    private val mData = mutableListOf<DataBean>()
    private val mScreenWidth = resources.displayMetrics.widthPixels
    private val mTargets = mutableListOf<CustomTarget<Bitmap>>()

    companion object {
        const val TAG = "fly/BatchBitmapView"
        const val ROW_SIZE = 16 //一行多少个bitmap
        const val IMAGE_SIZE = 80 //每个小格子图片的尺寸
    }

    fun setRowBitmapData(rows: ArrayList<MainActivity.MyData>?, position: Int) {
        Log.d(TAG, "setRowBitmapData $position")

        mData.clear()

        Log.d(TAG, "mTargets.size=${mTargets.size}")
        mTargets.forEach {
            Glide.with(context).clear(it) //如果不清楚,会发生有些图错放位置。
        }
        mTargets.clear() //mTargets上下滑动列表会越来越大,清空,一直保持ROW_SIZE.

        rows?.forEachIndexed { index, myData ->
            val target = object : CustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    val bean = DataBean(resource)
                    mData.add(bean)
                    postInvalidate()
                }

                override fun onLoadCleared(placeholder: Drawable?) {

                }
            }

            Glide.with(context)
                .asBitmap()
                .centerCrop()
                .override(IMAGE_SIZE)
                .load(myData.path)
                .into(target)

            mTargets.add(target)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(mScreenWidth, IMAGE_SIZE)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        mData.forEachIndexed { index, dataBean ->
            canvas.save()
            var left = (mScreenWidth / ROW_SIZE) * index
            canvas.drawBitmap(dataBean.bitmap, left.toFloat(), 0f, null)
            canvas.restore()
        }
    }

    data class DataBean(val bitmap: Bitmap)
}

上面每一行加载16个bitmap绘图,速度很快,因为是canvas直接绘图。但是,如果使用下文的方式:

Android LinearLayout dynamic add child ImageView,Glide load,kotlin_zhangphil的博客-CSDN博客文章浏览阅读645次。【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。《Android图片加载与缓存开源框架:Android Glide》Android Glide是一个开源的图片加载和缓存处理的第三方框架。https://blog.csdn.net/zhangphil/article/details/132080406即每一行先初始化一个水平的线性布局,然后逐个添加16个ImageView,对比发现明显卡顿,因为是以ViewGroup的方式布局摆放子view形成View。

 

 

 

Android Glide CustomTarget ,kotlin-CSDN博客文章浏览阅读1.4k次。【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。《Android图片加载与缓存开源框架:Android Glide》Android Glide是一个开源的图片加载和缓存处理的第三方框架。https://blog.csdn.net/zhangphil/article/details/131661819

 

相关推荐

  1. 程序定义表格组件

    2023-12-07 05:34:04       19 阅读
  2. 微信程序定义组件

    2023-12-07 05:34:04       24 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-07 05:34:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-07 05:34:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-07 05:34:04       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-07 05:34:04       20 阅读

热门阅读

  1. Hadoop安装

    2023-12-07 05:34:04       29 阅读
  2. 解决 video.js ios 播放一会行一会不行

    2023-12-07 05:34:04       42 阅读
  3. 微信小程序中全局变量的应用

    2023-12-07 05:34:04       39 阅读
  4. 【Android】Glide的简单使用(下)

    2023-12-07 05:34:04       36 阅读
  5. JPA构建多条件查询

    2023-12-07 05:34:04       38 阅读
  6. 浅谈深度学习中的过拟合

    2023-12-07 05:34:04       34 阅读
  7. EasyExcel下拉列表长度过长不显示【已修复】

    2023-12-07 05:34:04       45 阅读
  8. 第3节:Vue3 v-bind指令

    2023-12-07 05:34:04       38 阅读
  9. 【flink】基于flink全量同步postgres表到doris

    2023-12-07 05:34:04       38 阅读
  10. Stream流

    Stream流

    2023-12-07 05:34:04      31 阅读