首页 > 其他分享 >Android Glide加载小gif和图片比较模糊

Android Glide加载小gif和图片比较模糊

时间:2023-07-13 14:58:39浏览次数:53  
标签:resource Glide val width height gif fun Android size

其实Glide加载还是可以将小图片加载的非常清晰的,

可以通过Glide转换为Bitmap

利用Drawable将setFilterBitmap为true

但是这玩意解决不了GIF。在没有找到库的情况下:我直接自定义view
通过

pl.droidsonroids.gif:android-gif-drawable

获取时间间隔并将gif解析成bitmap获取像素 再通过Choreographer进行页面刷新

/**
 * GIF支持类 兼容 图片
 * @author xiaotie https://www.cnblogs.com/xiao-tie/
 * @time  2023/7/11 15:14
 * @param widthNum 像素宽
 * @param heightNum 像素高
 * @param seekGif 时间戳间隔
 * @param pos 当前显示位置
 * @param data 像素数据组
 */
data class GifSupport(val widthNum:Int, val heightNum:Int, val seekGif:Long, var pos:Int = 0, val data: MutableList<IntArray>){
    fun next(){
        pos++
        if(pos >= data.size){
            pos = 0
        }
    }
}

/**
 * 以像素点加载gif支持图片默认以宽度为标准(以高度为标准暂时不需要 未开发)
 * @author xiaotie https://www.cnblogs.com/xiao-tie/
 * @time  2023/7/11 14:48
 */
class GIFView : View, Choreographer.FrameCallback{

    constructor(context: Context?):super(context)
    constructor(context: Context?, attrs: AttributeSet?):super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int):super(context, attrs, defStyleAttr)

    private var gifSupport: GifSupport? = null
    private var size = 0
    private var margin = 0f
    private val paint = Paint()
    private val choreographer: Choreographer = Choreographer.getInstance()
    private var isRendering = false

    ///是否加网格
    var isGrid = true
        set(value) {
            field = value
            invalidate()
        }

    var widthDigit = 16
        set(value) {
            field = value
            requestLayout()
        }
    var heightDigit = 16
        set(value) {
            field = value
            requestLayout()
        }
    var path = Path()

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val measuredWidth = MeasureSpec.getSize(widthMeasureSpec)
        size = measuredWidth / (gifSupport?.widthNum?:widthDigit)
        margin = (MeasureSpec.getSize(widthMeasureSpec).toFloat() - size * (gifSupport?.widthNum?:widthDigit)) / 2
        val measuredHeight = size * (gifSupport?.heightNum?:heightDigit) + margin*2
        setMeasuredDimension(measuredWidth, measuredHeight.toInt())
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        startRendering()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        stopRendering()
    }

    @SuppressLint("DrawAllocation")
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        gifSupport?.apply {
            paint.reset()
            for (y in 0 until heightNum){
                for (x in 0 until widthNum){
                    paint.color = data[pos][x + widthNum*y]
                    val left = margin + x * size
                    val top = margin + y * size
                    canvas?.drawRect(Rect(left.toInt(), top.toInt(),
                        (left+size).toInt(), (top+size).toInt()),paint)
                }
            }
            if(isGrid){
                path.reset()
                for (y in 0 until heightNum){
                    path.moveTo(margin,margin + y * size)
                    path.lineTo(width-margin, margin + y * size)
                }
                for (x in 0 until widthNum){
                    path.moveTo(margin + x * size, margin)
                    path.lineTo(margin + x * size, height-margin)
                }
                paint.color = Color.parseColor("#66000000")
                paint.strokeWidth = 1f
                paint.style = Paint.Style.STROKE
                canvas?.drawPath(path,paint)
            }
        }
    }

    override fun doFrame(frameTimeNanos: Long) {
        gifSupport?.next()
        gifSupport?.let {
            invalidate() // 强制重绘视图
        }?: kotlin.run {
            stopRendering()
        }
        if (isRendering) {
            choreographer.postFrameCallbackDelayed(this, gifSupport?.seekGif?:100) // 每 200 毫秒刷新一次
        }
    }

    private fun startRendering() {
        if (!isRendering) {
            isRendering = true
            choreographer.postFrameCallback(this)
        }
    }

    private fun stopRendering() {
        invalidate()
        if (isRendering) {
            isRendering = false
            choreographer.removeFrameCallback(this)
        }
    }

    private suspend fun getHttpToStream(url:String) = withContext(Dispatchers.IO) {
        val client = OkHttpClient()
        val request: Request = Request.Builder()
            .url(url)
            .build()
        try {
            val response = client.newCall(request).execute()
            response.body!!.byteStream()
        }catch (e:Exception){
            e.printStackTrace()
            null
        }
    }
    private suspend fun getFileToStream(filePath:String) = withContext(Dispatchers.IO) {
        val file = File(filePath)
        try {
            val inputStream = FileInputStream(file) as InputStream
            inputStream
        }catch (e:Exception){
            e.printStackTrace()
            null
        }
    }

    /**
     * 颜色填充
     * @author xiaotie https://www.cnblogs.com/xiao-tie/
     * @time  2023/7/12 15:06
     */
    fun setColorData(@ColorInt colorInt: Int) {
        val colors:IntArray = Array(widthDigit * heightDigit) { colorInt }.toIntArray()
        gifSupport = GifSupport(widthDigit,heightDigit,10,0, mutableListOf(colors))
        invalidate()
    }

    /**
     * 资源链接 支持本地链接和图片链接
     * @author xiaotie https://www.cnblogs.com/xiao-tie/
     * @time  2023/7/12 15:06
     */
    fun setUrlOrFile(link :String?) {
        link?:return
        gifSupport = null
        GlobalScope.launch {
            if(link.contains("http")){
                getHttpToStream(link)
            }else{
                getFileToStream(link)
            }?.also {
                if(link.contains(".gif")){
                    val bis = BufferedInputStream(it)
                    val resource =  GifDrawable( bis )
                    val width = resource.intrinsicWidth
                    val height = resource.intrinsicHeight
                    val bitmapsData = mutableListOf<IntArray>()
                    // 将 GIF 每帧的像素数据写入 ByteBuffer
                    for (i in 0 until resource.numberOfFrames) {
                        val frame = resource.seekToFrameAndGet(i)
                        val framePixels = IntArray(width * height)
                        frame.getPixels(framePixels, 0, width, 0, 0, width, height)
                        bitmapsData.add(framePixels)
                    }
                    gifSupport = GifSupport(width,height,resource.duration.toLong()/resource.numberOfFrames, 0,bitmapsData)
                    post {
                        widthDigit = width
                        heightDigit = height
                    }
                    startRendering()
                    resource.recycle()
                }else if(link.contains(".png")){
                    val frame = BitmapFactory.decodeStream(it)
                    setBitmap(frame)
                    it.close()
                }
            }
        }
    }

    /**
     * 设置图片
     * @author xiaotie https://www.cnblogs.com/xiao-tie/
     * @time  2023/7/13 10:05
     */
    fun setBitmap(frame:Bitmap){
        val width = frame.width
        val height = frame.height
        val framePixels = IntArray(width * height)
        frame.getPixels(framePixels, 0, width, 0, 0, width, height)
        gifSupport = GifSupport(width,height,10,0, mutableListOf(framePixels))
        post {
            widthDigit = width
            heightDigit = height
        }
        invalidate()
    }

    /**
     * 设置gif数据
     * @author xiaotie https://www.cnblogs.com/xiao-tie/
     * @time  2023/7/13 10:06
     * @param byte Byte数组
     */
    fun setRawGifBytes(byte: ByteArray){
        val resource =  GifDrawable( byte )
        val width = resource.intrinsicWidth
        val height = resource.intrinsicHeight
        val bitmapsData = mutableListOf<IntArray>()
        // 将 GIF 每帧的像素数据写入 ByteBuffer
        for (i in 0 until resource.numberOfFrames) {
            val frame = resource.seekToFrameAndGet(i)
            val framePixels = IntArray(width * height)
            frame.getPixels(framePixels, 0, width, 0, 0, width, height)
            bitmapsData.add(framePixels)
        }
        gifSupport = GifSupport(width,height,resource.duration.toLong()/resource.numberOfFrames, 0,bitmapsData)
        widthDigit = width
        heightDigit = height
        startRendering()
        resource.recycle()
    }

    /**
     * 设置图片数据
     * @author xiaotie https://www.cnblogs.com/xiao-tie/
     * @time  2023/7/13 10:06
     * @param byte Byte数组
     */
    fun setRawPictureBytes(byte: ByteArray) {
        val frame = BitmapFactory.decodeByteArray(byte,0,byte.size)
        setBitmap(frame)
    }
}

 

标签:resource,Glide,val,width,height,gif,fun,Android,size
From: https://www.cnblogs.com/javaktolin/p/17550432.html

相关文章

  • 如何实现怎样实时监测Android系统打印的日志信息的具体操作步骤
    怎样实时监测Android系统打印的日志信息在开发Android应用程序的过程中,日志信息是非常重要的调试工具。通过日志信息,我们可以了解应用程序的运行状态、错误信息以及其他关键信息。为了更好地调试和分析应用程序的日志信息,我们可以实时监测Android系统打印的日志信息。本文将介绍如......
  • 【1】 android jdk环境安装和 开发工具androidStudio 安装[ mac+windows版本]
    工具jdk1.8 +as3.1.4jdk安装mac安装jdk tp windows安装jdk 一、下载:        http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html      我的电脑是64位的,所以下载版本是jdk-8u121-windows-x64.exe二、安装:     ......
  • android5.x添加sim1,sim2标识
    1,mobile_signal_group.xml.....<FrameLayoutandroid:id="@+id/mobile_combo"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/mobile_signal&q......
  • 如何实现Android 隐式绑定服务的具体操作步骤
    Android隐式绑定服务Android中的服务是一种可以在后台执行长时间运行操作的组件。服务可以在后台运行,即使用户切换到其他应用或锁定设备。在Android中,服务分为两种类型:启动服务和绑定服务。启动服务是通过调用startService()方法来启动的,而绑定服务是通过调用bindService()方法来......
  • 解决Android 修改 Application uiMode monitor dark mode的具体操作步骤
    Android修改ApplicationuiModemonitordarkmode随着智能手机的普及,人们对于移动应用程序的用户界面(UI)的黑暗模式(darkmode)的需求越来越高。黑暗模式不仅能够减少屏幕亮度,保护用户的眼睛,还能节省电池电量,给用户提供更好的用户体验。在Android平台上,我们可以通过修改Applic......
  • 如何实现Android 跳转通知管理的具体操作步骤
    Android跳转通知管理简介在Android开发中,通知管理是一项常见而重要的功能。通过实现Android跳转通知管理,可以让用户在点击通知时跳转到指定的页面或执行特定的操作。本文将向你介绍实现Android跳转通知管理的流程和具体步骤。实现流程以下是实现Android跳转通知管理的流程,可以......
  • 如何实现Android 添加圆形进度条的具体操作步骤
    Android添加圆形进度条在Android开发中,我们经常需要显示一个进度条来展示某个任务的进度。圆形进度条是一种常见的进度条样式,它以圆形的形式展示任务的进度。本文将介绍如何在Android应用中添加圆形进度条,并附带代码示例。第一步:添加依赖要使用圆形进度条,我们需要在项目的build......
  • 2023上半年Android高频面试题汇总(大厂真题+答案解析)
    前言小伙伴们大家好哇,不知道你们在找工作的时候是不是在力扣、在牛客网狂刷真题!可是有时候刷题的数量连起来可以绕地球三圈,但是面试却过不了第三轮!有没有一种可能就是你没有把握住重点!想想我们之前考试是不是老师划了重点,给了往期真题你考得分数高?题海战术是保底策略,能保证你大概率......
  • Android广播机制
    copy:https://www.cnblogs.com/lwbqqyumidi/p/4168017.html一、Android广播机制概述Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:1.同一app内部的同一组件内的消息......
  • Android studio 安装应用出现 The application could not be installed: INSTALL_FAIL
    错误详情Installationdidnotsucceed.Theapplicationcouldnotbeinstalled:INSTALL_FAILED_USER_RESTRICTEDListofapks:[0]'/Users/topjoy/git/git/ZeusSDK/Android/ZeusSDK/app/build/outputs/apk/debug/app-debug.apk'InstallationviaUSBisdisabl......