其实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? = nullprivate var size = 0private var margin = 0fprivate val paint = Paint()private val choreographer: Choreographer = Choreographer.getInstance()private var isRendering = false///是否加网格var isGrid = trueset(value) {field = valueinvalidate()}var widthDigit = 16set(value) {field = valuerequestLayout()}var heightDigit = 16set(value) {field = valuerequestLayout()}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)) / 2val measuredHeight = size * (gifSupport?.heightNum?:heightDigit) + margin*2setMeasuredDimension(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 * sizeval top = margin + y * sizecanvas?.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 = 1fpaint.style = Paint.Style.STROKEcanvas?.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 = truechoreographer.postFrameCallback(this)}}private fun stopRendering() {invalidate()if (isRendering) {isRendering = falsechoreographer.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 InputStreaminputStream}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?:returngifSupport = nullGlobalScope.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.intrinsicWidthval height = resource.intrinsicHeightval bitmapsData = mutableListOf<IntArray>()// 将 GIF 每帧的像素数据写入 ByteBufferfor (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 = widthheightDigit = 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.widthval height = frame.heightval framePixels = IntArray(width * height)frame.getPixels(framePixels, 0, width, 0, 0, width, height)gifSupport = GifSupport(width,height,10,0, mutableListOf(framePixels))post {widthDigit = widthheightDigit = 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.intrinsicWidthval height = resource.intrinsicHeightval bitmapsData = mutableListOf<IntArray>()// 将 GIF 每帧的像素数据写入 ByteBufferfor (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 = widthheightDigit = heightstartRendering()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)}
}