View->Bitmap缩放到自定义ViewGroup的任意区域

news2024/11/17 14:49:08

Bitmap缩放和平移

  • 加载一张Bitmap可能为宽高相同的正方形,也可能为宽高不同的矩形
  • 缩放方向可以为中心缩放,左上角缩放,右上角缩放,左下角缩放,右下角缩放
  • Bitmap中心缩放,包含了缩放和平移两个操作,不可拆开
  • Bitmap其余四个方向的缩放,可以单独缩放不带平移,也可以缩放带平移

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 mScaleMatrix = Matrix()
    var mDestRect = RectF()

    fun setBitmap(bitmap: Bitmap?) {
        mBitmap = bitmap
    }

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

中心缩放

  • ValueAnimator动画的初始值为0,开始区域为外层MyRelativeLayout区域,结束区域为内层MyImageView区域,缩放区域在这两个区域大小之间变化
  • 缩放比例取决于当前缩放区域mDestRectBitmap宽高的最小宽高比
fun setDestRectCenterWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = (srcRect.width() - mBitmap?.width!! * scale) / 2
    val dy = (srcRect.height() - mBitmap?.height!! * scale) / 2
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 中心缩放效果图
    在这里插入图片描述

左上角缩放

  • 左上角不带平移缩放
fun setDestRectLeftTopNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    mScaleMatrix.setScale(scale, scale)
    invalidate()
}
  • 左上角不带平移缩放效果图
    在这里插入图片描述

  • 左上角带平移缩放

fun setDestRectLeftTopWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = ((srcRect.width() - destRect.width())/2) * value + (destRect.left - srcRect.left) * value
    val dy = ((srcRect.height() - destRect.height())/2) * value + (destRect.top - srcRect.top) * value
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 左上角带平移缩放效果图
    在这里插入图片描述

右上角缩放

  • 右上角不带平移缩放
fun setDestRectRightTopNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left  + (destRect.left - srcRect.left) * value,
        srcRect.top + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = srcRect.width() - mBitmap!!.width * scale
    val dy = 0f
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 右上角不带平移缩放效果图
    在这里插入图片描述
  • 右上角带平移缩放
fun setDestRectRightTopWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left  + (destRect.left - srcRect.left) * value,
        srcRect.top + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = ((srcRect.width() - destRect.width())/2) * value + (destRect.left - srcRect.left) * value
    val dy = ((srcRect.height() - destRect.height())/2) * value + (destRect.top - srcRect.top) * value
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 右上角不带平移缩放效果图
    在这里插入图片描述

左下角缩放

  • 左下角不带平移缩放
fun setDestRectLeftBottomNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = 0f
    val dy = srcRect.height() - mBitmap?.height!! * scale
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 左下角不带平移缩放效果图
    在这里插入图片描述
  • 左下角平移缩放
fun setDestRectLeftBottomWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = ((srcRect.width() - destRect.width())/2 )* value
    val dy = ((srcRect.height() - destRect.height())/2 )* value + (destRect.bottom - srcRect.bottom) * value + (srcRect.height()- mBitmap?.height!! * scale)
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 左下角平移缩放效果图
    在这里插入图片描述

右下角缩放

  • 右下角不带平移缩放
fun setDestRectRightBottomNoTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = srcRect.width() - mBitmap!!.width * scale
    val dy = srcRect.height() - mBitmap?.height!! * scale
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 右下角不带平移缩放效果图

在这里插入图片描述

  • 右下角平移缩放
fun setDestRectRightBottomWithTranslate(srcRect: RectF, destRect: RectF, value : Float) {
    mDestRect = RectF(
        srcRect.left + (destRect.left - srcRect.left) * value,
        srcRect.top  + (destRect.top - srcRect.top) * value,
        srcRect.right + (destRect.right - srcRect.right) * value,
        srcRect.bottom + (destRect.bottom - srcRect.bottom) * value
    )
    val scale = Math.min(mDestRect.width() / mBitmap?.width!!, mDestRect.height() / mBitmap!!.height)
    val dx = ((srcRect.width() - destRect.width())/2 )* value
    val dy = ((srcRect.height() - destRect.height())/2 )* value + (destRect.bottom - srcRect.bottom) * value + (srcRect.height()- mBitmap?.height!! * scale)
    mScaleMatrix.reset()
    mScaleMatrix.postScale(scale, scale)
    mScaleMatrix.postTranslate(dx, dy)
    invalidate()
}
  • 右下角平移缩放效果图
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1710970.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第118题杨辉三角

题目&#xff1a; 题解&#xff1a; func generate(numRows int) [][]int {ans : make([][]int, numRows)for i : range ans {ans[i] make([]int, i1)ans[i][0] 1ans[i][i] 1for j : 1; j < i; j {ans[i][j] ans[i-1][j] ans[i-1][j-1]}}return ans }

NXP i.MX8系列平台开发讲解 - 3.12 Linux 之Audio子系统(一)

专栏文章目录传送门&#xff1a;返回专栏目录 目录 1. Audio 基础介绍 1.1 音频信号 1.2 音频的处理过程 1.3 音频硬件接口 1.3 音频专业术语解释 2. Linux Audio子系统介绍 3. Linux Audio子系统框架 Linux嵌入式系统中的音频子系统扮演着至关重要的角色&#xff0c;它涉…

Vue3+vite项目中使用mock模拟接口

安装依赖 分别安装vite-plugin-mock跟mockjs两个插件 npm install -D vite-plugin-mock mockjs vite.config.ts中添加配置&#xff0c;主要是红色标记的配置 注意此处如果配置出错可能是vite-plugin-mock依赖的版本有问题&#xff0c;重新安装一下依赖指定版本即可&#xf…

MX Component基础使用(多点位读取,多点位写入)

步骤&#xff0c;先连接PLC&#xff0c;然后在填入对应的点位 D10 然后去读取。 using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;us…

国产卫星星座,为什么一定要“走出去”?

今天这篇文章&#xff0c;我们来聊聊卫星和星座。 2024年行将过半&#xff0c;全球卫星通信产业的发展&#xff0c;又有了新的变化。 在卫星星座方面&#xff0c;各大企业的竞争博弈全面进入白热化阶段。卫星的发射速度在不断加快&#xff0c;而全球星座项目的数量和规模也在持…

nano机器人2:机械臂的视觉抓取

前言 参考链接: 【机械臂入门教程】机械臂视觉抓取从理论到实战 GRCNN 通过神经网络&#xff0c;先进行模型训练&#xff0c;在进行模型评估。 机械臂逆运动学求解 所有串联型6自由度机械臂均是可解的&#xff0c;但这种解通常只能通过数值解法得到&#xff0c;计算难度大&am…

Java | Leetcode Java题解之第118题杨辉三角

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> generate(int numRows) {List<List<Integer>> ret new ArrayList<List<Integer>>();for (int i 0; i < numRows; i) {List<Integer> row new…

Unity之如何使用Localization来实现文本+资源多语言

前言 使用Unity实现本地化&#xff08;Localization&#xff09;功能 在当今的游戏开发中&#xff0c;支持多语言已成为一项基本需求。Unity作为主流的游戏开发引擎&#xff0c;提供了强大的本地化工具&#xff0c;使开发者能够方便地为游戏添加多语言支持。本文将介绍如何在U…

JavaSE:StringBuilder和StringBuffer类

1、引言 在上一篇文章中&#xff0c;我们理解了字符串的常用方法&#xff0c;细心的同学大概已经发现&#xff0c;不管是将字符串中的字符转变为大写或小写&#xff0c;或是完成字符串的替换&#xff0c;又或是去除空白字符等等&#xff0c;只要涉及到字符串的修改&#xff0c…

js中金额进行千分以及toFixed()保留两位小数丢失精度的问题

1、金额进行千分 function commafy(num) { if ((num "").trim() "") { return ""; } if (isNaN(num)) { return ""; } num num ""; if (/^.*\..*$/.test(num)) { const pointIndex num.lastIndexOf("."); co…

[C][动态内存分配][柔性数组]详细讲解

目录 1.动态内存函数的介绍1.malloc2.free2.calloc4.realloc 2.常见的动态内存错误3.C/C程序的内存开辟4.柔性数组1.是什么&#xff1f;2.柔性数组的特点3.柔性数组的使用4.柔性数组的优势 1.动态内存函数的介绍 1.malloc 函数原型&#xff1a;void* malloc(size_t size)功能…

从0开始学会做标书:新手学习做标书制作必修(95节课)

入门框架 电子标书 商务标书 文档排版 技术标书 实操演示 你是否也有同样的问题 1、做标书公司没人教、没人带? 2、如何看懂招标文件? 3、小白零基础能不能学习做标书? 4、商务标、技术标如何得高分? 5、做标书需要什么软件? 6、如何制作电子标书? 7、如何避…

您提供或引用的参考资料无法对应怎么解决

在创建或编辑百度百科词条时&#xff0c;经常会遇到“您提供或引用的参考资料无法对应”的问题。以下百科参考网shaoshai是解决这个问题的一些方法&#xff1a; 检查和修正参考资料 首先&#xff0c;您需要仔细检查提供的参考资料&#xff0c;确保它们与您的内容相对应。如果发…

2024HW|常见红队使用工具

目录 什么是HW&#xff1f; 什么是网络安全红蓝对抗&#xff1f; 红队 常见工具 信息收集工具 Nmap 简介 漏洞扫描工具 Nessus简介 AWVS 简介 抓包工具 Wireshark简介 TangGo 简介 web 应用安全工具 Burpsuite 简介 SQLMap webshell 管理工具 蚁剑 冰蝎 后…

在豆包这事上,字节看得很明白

大数据产业创新服务媒体 ——聚焦数据 改变商业 导语&#xff1a; 1.基于豆包的话炉/猫箱APP市场反响一般 2.价格战对于豆包来说是副产物 3.价格战对大模型市场是良性的 4.豆包接下来会推广至国际社会 因为宣称价格比行业便宜99.3%&#xff0c;豆包成功出圈了。根据火山引擎公…

ADS基础教程17 - 创建含参子图

设计加密保护IP 一、引言二、参数设计 一、引言 将一个子图内部元器件的参数设置成可以在外部进行修改的参数&#xff0c;能够使得封装的子图更加灵活和通用。 二、参数设计 (1)打开一个子图&#xff0c;在菜单栏中选择File–>Design Parameters… (2)弹出的对话框中&am…

Aleth-NeRF: Illumination Adaptive NeRF with Concealing Field Assumption

Abstract Aleth-NeRF: 带有隐蔽场假设的照明自适应 NeRF 照明照明标准的神经辐射场(NeRF)范例采用了一种以观察者为中心的方法,将光照和材料反射的各个方面仅仅从3D 点发射纠缠在一起。这种简化的渲染方法在准确建模在不利光照条件下捕获的图像方面提出了挑战,如弱光或过度曝…

牛客网刷题 | BC101 翻转直角三角形图案

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 KiKi学习了循环&am…

【动态规划】速解简单多状态类问题

目录 17.16 按摩师 题⽬描述&#xff1a; 解法&#xff08;动态规划&#xff09;&#xff1a; 1. 状态表⽰&#xff1a; 2. 状态转移⽅程&#xff1a; 3. 初始化&#xff1a; 4. 填表顺序 5. 返回值 代码 总结&#xff1a; 213.打家劫舍II&#xff08;medium&#x…

实践部署 浦语·灵笔2 模型,写作图文并茂的文章

1 初步介绍 XComposer2 相关知识 浦语灵笔2 是基于 书生浦语2 大语言模型研发的突破性的图文多模态大模型&#xff0c;具有非凡的图文写作和图像理解能力&#xff0c;在多种应用场景表现出色&#xff0c;总结起来其具有&#xff1a; 自由指令输入的图文写作能力&#xff1a; 浦…