首页 > 其他分享 >View->Bitmap缩放到自定义ViewGroup的任意区域(RectF方式绘制Bitmap)

View->Bitmap缩放到自定义ViewGroup的任意区域(RectF方式绘制Bitmap)

时间:2024-06-04 14:31:27浏览次数:16  
标签:ViewGroup val 自定义 srcRect value Bitmap width height destRect

XML文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.yang.app.MyRelativeLayout
        android:id="@+id/real_rl"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_marginTop="30dp"
        android:layout_marginBottom="30dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:background="@color/gray">
        <com.yang.app.MyImageView
            android:id="@+id/real_iv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="30dp"
            android:layout_marginBottom="30dp"
            android:layout_marginLeft="30dp"
            android:layout_marginRight="30dp" />
    </com.yang.app.MyRelativeLayout>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_weight="0"
        android:background="#00ff00" />
</LinearLayout>

Activity代码

const val TAG = "Yang"
class MainActivity : AppCompatActivity() {
    var mRealView : MyImageView ?= null
    var mRelativeLayout : MyRelativeLayout ?= null
    var tempBitmap : Bitmap ?= null
    var mHandler = Handler(Looper.getMainLooper())
    var screenWidth = 0
    var screenHeight = 0
    var srcRect = RectF()
    var destRect = RectF()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mRealView = findViewById(R.id.real_iv)
        mRelativeLayout = findViewById(R.id.real_rl)
        // 屏幕宽高的一半作为临时RectF, 用于压缩Bitmap
        screenWidth = resources.displayMetrics.widthPixels
        screenHeight = resources.displayMetrics.heightPixels
        val tempRect = RectF(0f, 0f, screenWidth.toFloat() / 2, screenHeight.toFloat() / 2)
        
        
        CoroutineScope(Dispatchers.IO).launch {
            tempBitmap = getBitmap(resources, tempRect, R.drawable.fake)
            withContext(Dispatchers.Main) {
                mRelativeLayout?.post {
                    // 获取初始区域的RectF
                    srcRect.set(
                        0f,
                        0f,
                        mRelativeLayout?.width?.toFloat()!!,
                        mRelativeLayout?.height?.toFloat()!!
                    )
                    // 获取结束区域的RectF
                    mRelativeLayout?.forEach { childView ->
                        if (childView is MyImageView) {
                            destRect.set(
                                0f,
                                0f,
                                 childView.width.toFloat(),
                                childView.height.toFloat()
                            )
                        }
                    }
                    scaleRectFun(tempBitmap, srcRect, destRect)
                }
            }
        }
    }
    
    fun scaleRectFun(tempBitmap: Bitmap?, srcRect : RectF, destRect: RectF){
        tempBitmap?.let { bitmap->
            mRelativeLayout?.setBitmap(bitmap)
            val animator = ValueAnimator.ofFloat(0f, 1f)
            animator.duration = 5000L
            animator.interpolator = DecelerateInterpolator()
            animator.addUpdateListener {
                val value = it.animatedValue as Float
                // 中心缩放
                mRelativeLayout?.setDestRectCenterWithTranslate(srcRect, destRect, value)
                // 左上角不带平移缩放
                // mRelativeLayout?.setDestRectLeftTopNoTranslate(srcRect, destRect, value)
                // 左上角平移缩放
                // mRelativeLayout?.setDestRectLeftTopWithTranslate(srcRect, destRect, value)
                // 右上角不带平移缩放
                // mRelativeLayout?.setDestRectRightTopNoTranslate(srcRect, destRect, value)
                // 右上角平移缩放
                // mRelativeLayout?.setDestRectRightTopWithTranslate(srcRect, destRect, value)
                // 左下角不带平移缩放
                // mRelativeLayout?.setDestRectLeftBottomNoTranslate(srcRect, destRect, value)
                // 左下角平移缩放
                // mRelativeLayout?.setDestRectLeftBottomWithTranslate(srcRect, destRect, value)
                // 右下角不带平移缩放
                // mRelativeLayout?.setDestRectRightBottomNoTranslate(srcRect, destRect, value)
                // 右下角平移缩放
                // mRelativeLayout?.setDestRectRightBottomWithTranslate(srcRect, destRect, value)
            }
            animator.start()
        }
    }
}
fun getBitmap(resources : Resources, destRect : RectF, imageId: Int): Bitmap? {
    var imageWidth = -1
    var imageHeight = -1
    val preOption = BitmapFactory.Options().apply {
        // 只获取图片的宽高
        inJustDecodeBounds = true
        BitmapFactory.decodeResource(resources, imageId, this)
    }
    imageWidth = preOption.outWidth
    imageHeight = preOption.outHeight
    // 计算缩放比例
    val scaleMatrix = Matrix()
    // 确定未缩放Bitmap的RectF
    var srcRect = RectF(0f, 0f, imageWidth.toFloat(), imageHeight.toFloat())
    // 通过目标RectF, 确定缩放数值,存储在scaleMatrix中
    scaleMatrix.setRectToRect(srcRect, destRect, Matrix.ScaleToFit.CENTER)
    // 缩放数值再映射到原始Bitmap上,得到缩放后的RectF
    scaleMatrix.mapRect(srcRect)

    val finalOption = BitmapFactory.Options().apply {
        if (imageHeight > 0 && imageWidth > 0) {
            inPreferredConfig = Bitmap.Config.RGB_565
            inSampleSize = calculateInSampleSize(
                imageWidth,
                imageHeight,
                srcRect.width().toInt(),
                srcRect.height().toInt()
            )
        }
    }
    return BitmapFactory.decodeResource(resources, imageId, finalOption)
}

fun calculateInSampleSize(fromWidth: Int, fromHeight: Int, toWidth: Int, toHeight: Int): Int {
    var bitmapWidth = fromWidth
    var bitmapHeight = fromHeight
    if (fromWidth > toWidth|| fromHeight > toHeight) {
        var inSampleSize = 2
        // 计算最大的inSampleSize值,该值是2的幂,并保持原始宽高大于目标宽高
        while (bitmapWidth >= toWidth && bitmapHeight >= toHeight) {
            bitmapWidth /= 2
            bitmapHeight /= 2
            inSampleSize *= 2
        }
        return inSampleSize
    }
    return 1
}

自定义ViewGroupView代码

class MyImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr)



class MyRelativeLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
    var mBitmap : Bitmap ?= null
    var mDestRect = RectF()
    fun setBitmap(bitmap: Bitmap?) {
        mBitmap = bitmap
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        mBitmap?.let {
            canvas?.drawBitmap(it, null, mDestRect, Paint().apply {
                isAntiAlias = true
        })
    }
}

中心缩放

fun setDestRectCenterWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempWidth = mBitmap?.width!! *  (startScale + (endScale - startScale) * value)
    val tempHeight = mBitmap?.height!! *  (startScale + (endScale - startScale) * value)
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
        )
    val dx = (srcRect.width()- tempWidth)/2
    val dy = (srcRect.height() - tempHeight)/2
    mDestRect.offset(dx, dy)
    invalidate()
}

左上角缩放

  • 左上角不带平移缩放
fun setDestRectLeftTopNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! * tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    invalidate()
}
  • 左上角平移缩放
fun setDestRectLeftTopWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! *  tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    val dx = ((srcRect.width() - destRect.width())/2) * value
    val dy = ((srcRect.height() - destRect.height())/2) * value
    mDestRect.offset(dx, dy)
    invalidate()
}

右上角缩放

  • 右上角不带平移缩放
fun setDestRectRightTopNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! *  tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    val dx = srcRect.width() - tempWidth
    val dy = 0f
    mDestRect.offset(dx, dy)
    invalidate()
}
  • 右上角带平移缩放
fun setDestRectRightTopWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! *  tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    val dx = ((srcRect.width() - destRect.width())/2) * value
    val dy = ((srcRect.height() - destRect.height())/2) * value
    mDestRect.offset(dx, dy)
    invalidate()
}

左下角缩放

  • 左下角不带平移缩放
fun setDestRectLeftBottomNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! *  tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    val dx = 0f
    val dy = srcRect.height() - tempHeight
    mDestRect.offset(dx, dy)
    invalidate()
}
  • 左下角平移缩放
fun setDestRectLeftBottomWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! *  tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    val dx = ((srcRect.width() - destRect.width())/2 )* value
    val dy = ((srcRect.height() - destRect.height())/2 )* value  + (destRect.bottom - srcRect.bottom) * value + (srcRect.height()- tempHeight)
    mDestRect.offset(dx, dy)
    invalidate()
}

右下角缩放

  • 右下角不带平移缩放
fun setDestRectRightBottomNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
    val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
    val tempScale = (startScale + (endScale - startScale) * value)
    val tempWidth = mBitmap?.width!! *  tempScale
    val tempHeight = mBitmap?.height!! *  tempScale
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
        srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
    )
    val dx = srcRect.width() - tempWidth
    val dy = srcRect.height() - tempHeight
    mDestRect.offset(dx, dy)
    invalidate()
}
  • 右下角带平移缩放
fun setDestRectRightBottomWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
     val startScale = Math.min(srcRect.width() / mBitmap?.width!!, srcRect.height() / mBitmap!!.height)
     val endScale = Math.min(destRect.width() / mBitmap?.width!!, destRect.height() / mBitmap!!.height)
     val tempScale = (startScale + (endScale - startScale) * value)
     val tempWidth = mBitmap?.width!! *  tempScale
     val tempHeight = mBitmap?.height!! *  tempScale
     mDestRect = RectF(
         srcRect.left + (destRect.left - srcRect.left) * value,
         srcRect.top  + (destRect.top - srcRect.top) * value,
         srcRect.left + (destRect.left - srcRect.left) * value  + tempWidth,
         srcRect.top  + (destRect.top - srcRect.top) * value + tempHeight
     )
     val dx = ((srcRect.width() - destRect.width())/2 )* value
     val dy = ((srcRect.height() - destRect.height())/2 )* value  + (destRect.bottom - srcRect.bottom) * value + (srcRect.height()- tempHeight)
     mDestRect.offset(dx, dy)
     invalidate()
 }

标签:ViewGroup,val,自定义,srcRect,value,Bitmap,width,height,destRect
From: https://blog.csdn.net/sunshine_guo/article/details/139325136

相关文章

  • 博客园文章目录生成脚本v1.0:支持多级、过滤空行、可指定文章、自定义插入点
    使用说明:1.设置-申请JS权限,等待审核通过2.设置-页脚HTML代码,代码贴进去保存 样式说明:1.默认目录插到文章顶部,可以加入<divid="toc"></div>标签自定义插入位置。2.H1和H2是加粗体,其他的是正常体。自定义功能:catalogue(true):给所有文章生成目录catalogue(false):只......
  • idea设置自定义快捷键定义代码块
    自定义代码块常用的psvm,main,sout等就是系统预设的。我们可以自己添加自定义的代码块,并制定调用该代码块的缩写,这样在使用该代码块时,就无需手动填写,只需通过代码块缩写触发idea的自动补全即可,位置:Setting–>Editor–>LiveTemplates如下图 为了区分方便管理,你可以添加自己的模板......
  • 自定义FlutterFragment的初始化路由没有生效
    问题:在自定义FlutterFragment的configureFlutterEngine方法中初始化页面路由发现一直是'/'原因:当configureFlutterEngine方法被调用时,Flutter已经完成了初始化并设置了默认的初始路由(通常是'/')。在Android项目中,FlutterFragment在onAttach方法中创建FlutterEngine。在......
  • 【C语言】自定义类型:结构体(建议收藏!!!)
    结构体前言1、什么是结构体2、结构体类型的声明3、结构体变量的创建和初始化4、结构成员访问操作符5、结构体内存对齐6、存在内存对齐的原因7、结构体传参8、结构体实现位段前言我们已经学了很多数据类型,列如int,char,float,double等。但还不能满足需求,在我们......
  • vue3中ref绑定自定义组件没有获取到dom?
    问题<template><my-compref="test"/></template><scriptlang="ts"setup>consttest=ref()onMounted(()=>{console.log(test.value)})</script>打印出来的是一个proxy对象解决办法1.如果ref绑定的是一个普通的d......
  • VS Code自定义代码模板
    VSCode自定义代码模板VSCode作为一款轻量级的编辑器,使用体验极佳,具有很多有用的小功能,也有着非常丰富的插件,日常写代码的时候自动补全和各种模板能够有效的提高编码的效率,这里介绍两种我常使用的自定义代码块或者模板的设置方法。集成自定义代码段VSCode自带了用户定......
  • HarmonyOS NEXT星河版之自定义List下拉刷新与加载更多
    文章目录一、加载更多二、下拉刷新三、小结一、加载更多借助List的onReachEnd方法,实现加载更多功能,效果如下:@ComponentexportstructHPList{//数据源@PropdataSource:object[]=[]//加载更多是否ing@StateisLoadingMore:boolean=false......
  • 「AntV」X6 自定义vue节点(vue3)
    官方文档本篇文档只讲解vue3中如何使用,vue2的可以参考下官方文档安装插件@antv/x6-vue-shape添加vue组件既然使用vue节点,那么我们就需要准备一个vue的组件,这个组件就是节点的一些样式,根据你们的ui自行写代码即可<template><div>节点名称</div><div>节点描述</div>......
  • IDEA自定义配置注释模板,让你看起来更加专业!!!
    一:类注释我们先来康康成果:在以上的代码中我们可以看到只要创建一个类,idea自动会给你补充注释消息,有作者信息和创建时间关于模板参数代码我已经放到下面了:/***@author:dlwlrma*@data${YEAR}年${MONTH}月${DAY}日${TIME}*/ 使用方法:打开IDEA的Settings,点击Edi......
  • # window10 设置一个【自定义运行】命令行快捷方式
    window10设置一个【自定义运行】命令行快捷方式window10[运行】命令行打不开,可采用如下简单快捷方法:1、右键点击桌面空白处,然后点击【新建】,再点击【快捷方式】。2、在【请键入对象的位置】文本框输入:explorershell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}3......