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

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.MyRelativeLayoutandroid: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.MyImageViewandroid: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><ImageViewandroid: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 ?= nullvar mRelativeLayout : MyRelativeLayout ?= nullvar tempBitmap : Bitmap ?= nullvar mHandler = Handler(Looper.getMainLooper())var screenWidth = 0var screenHeight = 0var 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, 用于压缩BitmapscreenWidth = resources.displayMetrics.widthPixelsscreenHeight = resources.displayMetrics.heightPixelsval 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 {// 获取初始区域的RectFsrcRect.set(0f,0f,mRelativeLayout?.width?.toFloat()!!,mRelativeLayout?.height?.toFloat()!!)// 获取结束区域的RectFmRelativeLayout?.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 = 5000Lanimator.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 = -1var imageHeight = -1val preOption = BitmapFactory.Options().apply {// 只获取图片的宽高inJustDecodeBounds = trueBitmapFactory.decodeResource(resources, imageId, this)}imageWidth = preOption.outWidthimageHeight = preOption.outHeight// 计算缩放比例val scaleMatrix = Matrix()// 确定未缩放Bitmap的RectFvar srcRect = RectF(0f, 0f, imageWidth.toFloat(), imageHeight.toFloat())// 通过目标RectF, 确定缩放数值,存储在scaleMatrix中scaleMatrix.setRectToRect(srcRect, destRect, Matrix.ScaleToFit.CENTER)// 缩放数值再映射到原始Bitmap上,得到缩放后的RectFscaleMatrix.mapRect(srcRect)val finalOption = BitmapFactory.Options().apply {if (imageHeight > 0 && imageWidth > 0) {inPreferredConfig = Bitmap.Config.RGB_565inSampleSize = 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 = fromWidthvar bitmapHeight = fromHeightif (fromWidth > toWidth|| fromHeight > toHeight) {var inSampleSize = 2// 计算最大的inSampleSize值,该值是2的幂,并保持原始宽高大于目标宽高while (bitmapWidth >= toWidth && bitmapHeight >= toHeight) {bitmapWidth /= 2bitmapHeight /= 2inSampleSize *= 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 ?= nullvar 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) / 2val dy = (srcRect.height() - mBitmap?.height!! * scale) / 2mScaleMatrix.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) * valueval dy = ((srcRect.height() - destRect.height())/2) * value + (destRect.top - srcRect.top) * valuemScaleMatrix.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 * scaleval dy = 0fmScaleMatrix.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) * valueval dy = ((srcRect.height() - destRect.height())/2) * value + (destRect.top - srcRect.top) * valuemScaleMatrix.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 = 0fval dy = srcRect.height() - mBitmap?.height!! * scalemScaleMatrix.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 )* valueval 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 * scaleval dy = srcRect.height() - mBitmap?.height!! * scalemScaleMatrix.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 )* valueval 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.mzph.cn/news/845741.shtml

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

相关文章

【面试】class文件里面是什么?

目录 1. 说明2. 主要部分2.1 魔数2.2 版本信息2.3 常量池2.4 访问标志2.5 类索引、父类索引和接口索引数组2.6 字段表2.7 方法表2.8 属性 1. 说明 1. .class 文件是 Java 编译器编译 Java 源代码文件&#xff08;.java 文件&#xff09;后生成的字节码文件。2.这些文件包含了 …

​探究当代婚恋市场的状况与挑战

​ 在当今社会&#xff0c;婚恋市场正经历着前所未有的变化。随着科技的进步和社会观念的演变&#xff0c;人们在寻找伴侣的方式和标准也在不断地发展。本文将探讨当前婚恋市场的状况&#xff0c;分析其面临的挑战&#xff0c;并提出相应的建议。 首先&#xff0c;互联网的普…

SpringBoot 多模块 多环境 项目 单元测试

环境描述 假设项目中有以下三个yml文件&#xff1a; application.ymlapplication-dev.ymlapplication-prod.yml 假设项目各Module之间依赖关系如下&#xff1a; 其中&#xff0c;D依赖C&#xff0c;C依赖B&#xff0c;B依赖A&#xff0c;D对外提供最终的访问接口 现在要想采…

深入解析MySQL事务的实现原理

一、事务的基本概念 在计算机科学中&#xff0c;事务 (Transaction) 是指对数据库进行的一系列操作&#xff0c;这些操作要么全部执行&#xff0c;要么全部不执行&#xff0c;是不可分割的工作单位。它们通常被用于确保数据库的完整性和一致性。 事务具有以下四个重要特性&am…

VUE阻止浏览器记住密码若依CLOUD(INPUT框密码替换圆点)

网上找的要不就是缺少方法要不就是不好用,故发一个完整的 粘贴可用版本 <el-form-item prop"password"><el-input v-model"loginForm.pwdCover" type"text" name"pwd" id"pwd" placeholder"密码" autoco…

“两客一危”车辆综合监控信息化产品及应用分析

引言 随着科技的不断进步和社会的发展&#xff0c;“两客一危”车辆&#xff08;即长途客车、旅游包车和危险品运输车&#xff09;的安全监管问题日益凸显。为了提升车辆的安全性能和管理效率&#xff0c;综合监控信息化产品应运而生。本文将对这一产品进行详细介绍&#xff0…

像艺术家一样工作

接下来开始翻译这本小册子 豆瓣评分还是挺高的&#xff0c;目前在国内没有看到有在售的翻译版本 书名直译的话是&#xff1a;像艺术家一样去偷 作者可能是为了制造营销话题&#xff0c;所以起了这么一个名字 但是偷这个词总归不太体面&#xff0c;所以我把书名翻译为&#…

随便用css换个渐变的太阳

来源于GPT4o&#xff1a;代码来源 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>渐变色上半圆…

机器学习笔记——欠拟合、过拟合

欠拟合 将训练损失和测试损失都比较大的拟合叫欠拟合&#xff0c;那么他的预测精度很低 1.一般出现在模型的复杂度小于数据本身的复杂度导致的&#xff0c;这个可能就是模型对数据的分布和实际数据分布之间的差异&#xff0c;这个就可能需要更换模型 2.还可能出现在梯度下降算…

零基础构建基于LangChain的聊天机器人(3)

检索对象 review_chain的目标是回答有关患者在医院就医体验的问题。到目前为止&#xff0c;已经将患者对医院的评论作为问题的上下文。虽然能回答少量问题&#xff0c;但它不具有很好的扩展性。此外&#xff0c;即使将所有评论放入模型的上下文中&#xff0c;也不能保证它使用…

QT天气预报项目(写在简历上)

一、ui设计 实现功能:可以搜索不同的城市进行天气的查询,并且显示未来7天内的天气,并绘制出当天的最高气温和最低气温曲线图。 学到的知识: stylesheet界面美化 Json数据解析 HTTP通信get请求 使用事件过滤器绘制温度曲线 多控件处理(利用数组) 代码整合调试能力 二…

线程思维导图

列出线程所有知识的框架结构&#xff0c;帮助理解线程相关知识&#xff0c;有更好的知识体系 Java相关进阶知识 多线程相关知识&#xff0c;超详细&#xff0c;易懂

Webrtc支持HEVC之Mediasoup SDP协商编码流程(三)

一、SDP校验 1、服务端的rtp能力配置 文件位置&#xff1a;cst-medias-server/core/config.js 具体内容&#xff1a;moduls.export-mediasoup-routerOpitions-mediaCodeces 注意事项&#xff1a;对于音视频codec&#xff0c;clinet只会使用第一个识别到的codec&#xff0c;…

windows上进行git初始化时报错:fatal: unknown write failure on standard output

一、报错描述 1、git init命令一般是在命令行&#xff0c;切换到项目的根目录后执行 2、如果是windows的系统&#xff0c;我们粘贴路径时&#xff0c;需要进行转义命令行才能识别&#xff0c; 也就是像我下面写的 D:\\Users\\...3、报错信息进行解读 一般情况下&#xff0c;…

Pytorch-Lighting使用教程(MNIST为例)

一、pytorch-lighting简介 1.1 pytorch-lighting是什么 pytorch-lighting&#xff08;简称pl&#xff09;&#xff0c;基于 PyTorch 的框架。它的核心思想是&#xff0c;将学术代码&#xff08;模型定义、前向 / 反向、优化器、验证等&#xff09;与工程代码&#xff08;for-…

C++学习之避免使用野指针

现有结构体struct_a和struct_b&#xff0c;其中struct_b中包含struct_a指针作为成员变量。先基于struct_a定义一个变量a_ptr&#xff0c;之后定义一个struct_b指针变量b_ptr&#xff0c;并将a_ptr赋值给b_ptr中的struct_a类型变量。之后释放b_ptr&#xff0c; 那么a_ptr指向的内…

红队内网攻防渗透:内网渗透之windows内网权限提升技术:工具篇

红队内网攻防渗透 1. 内网权限提升技术1.1 windows内网权限提升技术--工具篇1.1.1 Web到Win系统提权-平台&语言&用户1.1.1.1 Web搭建平台差异1.1.1.2 Web语言权限差异1.1.1.3 系统用户权限差异1.1.2 Web到Win系统提权-Windows 2012宝塔面板-哥斯拉1.1.2.1 环境条件:1.…

Anthropic公司CEO谈AI发展:Cluade安全超过商业利益

Anthropic公司今年3月发布的超越GPT-4模型Claude3 opus&#xff0c;成功吸引了大量GPT-4用户“叛变”。 作为OpenAI的头号劲敌&#xff0c;Claude3发布方Anthropic公司的联合创始人兼CEO&#xff0c;达里奥阿莫迪&#xff08;DarioAmodei&#xff09;承诺&#xff1a;在能够制…

生信分析进阶4 - 比对结果的FLAG和CIGAR信息含义与BAM文件指定区域提取

BAM文件时存储比对数据的常用格式&#xff0c;可用于短reads和长reads数据。BAM是二进制压缩格式&#xff0c;SAM文件为其纯文本格式&#xff0c;CRAM为BAM的高压缩格式&#xff0c;IO效率相比于BAM略差&#xff0c;但是占用存储空间更小。 1. BAM文件的比对信息 BAM的核心信…

用c语言实现通讯录

目录 静态简易通讯录 代码&#xff1a; 功能模块展示&#xff1a; 设计思路&#xff1a; 动态简易通讯录&#xff08;本质顺序表&#xff09; 代码&#xff1a; 扩容模块展示&#xff1a; 设计思路&#xff1a; 文件版本通讯录 代码&#xff1a; 文件模块展示&#x…