画面分割和偏移计算
首先计算出Unit可见部分的准确范围,具体计算公式可以参考我以前的文章《自定义控件——原创仿地图瓦片动态加载_阶段1_动态添加和移除View》的末尾部分,如果有Unit部分可见区域越过了父控件的边界,例如Unit左边框比父控件左边框坐标值还要小,那么截图块的区域横坐标就是父控件左边框了,同样的推导也可以用于确定右边、上边、底边的位置,从而最终确定对绘制图层的截图图块的准确区域。具体运算代码如下,targetRect即是要目标区域,getX()得到的是Unit控件初始化时的左上角坐标,getWidth()、getHeight()是控件初始化后的宽度、高度,getScaleX()、getScaleY()分别是当前宽度、高度缩放到原来的比例:
//获取本控件在屏幕可见区域对应的位图像素,并制作成Bitmap显示
Rect targetRect = new Rect(0, 0, 0, 0);
//计算本Unit需要截取父控件固定画布Bitmap的范围Start:
if (getX() + (1 - getScaleX()) / 2 * getWidth() < parent.getLeft()) { //左边缘小于0
targetRect.left = parent.getLeft();
} else {
targetRect.left = (int)(getX() + (1 - getScaleX()) / 2 * getWidth());
}
if (getX() + (1 - getScaleX()) / 2 * getWidth() + getWidth() * getScaleX() > parent.getRight()) { //单元的右边缘大于父控件右边缘
targetRect.right = parent.getRight();
} else {
targetRect.right = (int)(getX() + (1 - getScaleX()) / 2 * getWidth() + getWidth() * getScaleX());
}
if (getY() + (1 - getScaleY()) / 2 * getHeight() < parent.getTop()) {
targetRect.top = parent.getTop();
} else {
targetRect.top = (int)(getY() + (1 - getScaleY()) / 2 * getHeight());
}
if (getY() + (1 - getScaleY()) / 2 * getHeight() + getHeight() * getScaleY() > parent.getBottom()) {
targetRect.bottom = parent.getBottom();
} else {
targetRect.bottom = (int)(getY() + (1 - getScaleY()) / 2 * getHeight() + getHeight() * getScaleY());
}
? ? ? ?我的Unit控件是继承于ImageView的,所以如果此时把截取下来的像素块生成Bitmap之后直接使用setBitmap的话,会使得原来的图像被覆盖为该像素块的画面的同时,该像素块的画面的画面可能会和原来在绘图图层时产生了位置或大小上的误差。所以当某个Unit的实际可见区域的左上角坐标在父控件左边界之外时,要把图块左边界右移到父控件的左边界对齐,即向右移动“父控件左边界 - Unit左边界”那么长的距离,而且由于该距离是视觉上的距离,而不是控件内部参考系的距离,所以还要除以“缩放比例”得到控件内部参考系的距离。而越过父控件右边界时,则Unit实际显示的横向范围是“父控件右边界 - Unit可见区域左边界”,然后再除以缩放比例得到控件内部参考系的长度(不是可见区域多长就是多长,可以理解控件按比例缩小放大其实只是拉远拉近了,不代表控件内部长度发生了变化,所以一定要除以缩放比例才能把可见长度变成控件内部长度),上边和底边的运算也类似,然后得到图块的拉伸的具体范围。然后再把该范围的宽高除以图片的宽高,以偏移值即其实的x、y值为中心缩放图块,再使用matrix工具缩放图块后写到原本的cacheBitmap中叠加起来,并保存到外存中。换算方法可能比较绕口,可以参考我之前的文章《Android View跟随手势漫游缩放方法》、Bitmap无图像损失的截取和保存方法:《Android开发中一种原封不动地保存Bitmap数据的办法》。具体代码如下:
? ?
//如果Unit的做边框在父控件左侧外面,则需要把像素块移动到Unit可见区域的骑士位置再拉伸。所以这里计算左边框要偏移多少
float dx = 0;
float dy = 0;
if(getX() + (1 - getScaleX()) / 2 * getWidth() < 0){
dx = -(getX() + (1 - getScaleX()) / 2 * getWidth()) / getScaleX(); //左偏了多少,图片就要右偏多少,而且即使格子缩小了也只是视觉上缩少了,格子的像素量不变,所以截出来的图的坐标还要反向放大进行偏移
}
if(getY() + (1 - getScaleY()) / 2 * getHeight() < 0){
dy = -(getY() + (1 - getScaleY()) / 2 * getHeight()) / getScaleY();
}
matrix.postTranslate(dx, dy);
//之前的步骤计算了图片覆盖的左起点和顶起点,现在计算图片覆盖的右终点和底终点
float parentWidth = ((FrameLayout) getParent()).getRight(); //父控件右边终点
float parentHeight = ((FrameLayout) getParent()).getBottom();
float unitRightBoarder = (getX() + (1 - getScaleX()) / 2 * getWidth() + getWidth() * getScaleX()); //本Unit在屏幕实际的右边界位置
/**如果Unit右边界位置超出父控件右边界,则“Unit可见区域右边界 = 父控件右边界 - Unit实际可见左边界”并反向放大至和图片等效比例尺。
/否则直接用Unit真实右边界**/
float rightBoarder = unitRightBoarder > parentWidth ?
(parentWidth - (getX() + (1 - getScaleX()) / 2 * getWidth())) / getScaleX() :
getWidth() ;//右边框
//原理同上
float unitBottomBoarder = (getY() + (1 - getScaleY()) / 2 * getHeight() + getHeight() * getScaleY());
float bottomBoarder = unitBottomBoarder > parentHeight ?
(parentHeight - (getY() + (1 - getScaleY()) / 2 * getHeight())) / getScaleY(http://www.amjmh.com/v/): //(屏幕边界 - View实际起始边界) / 缩放率 反向放大
getHeight() ;
//图片在Unit中实际应显示范围
RectF visibleRect = new RectF(dx, dy, rightBoarder, bottomBoarder);
//以实际应显示范围的左上角作为缩放中心,长、宽分别除以像素块的长、宽,得到像素块应该拉伸或者收缩的比例:
matrix.postScale(visibleRect.width() / newBitmap.getWidth(), visibleRect.height() / newBitmap.getHeight(), dx, dy);
canvas.drawBitmap(newBitmap, matrix, null);
setImageBitmap(cacheBitmap);
//保存本次绘图
saveUnitBitmap();
原文地址:https://www.cnblogs.com/hyhy904/p/11373124.html
- 最简单的web服务器实现(一)(r4笔记第68天)
- 算法09 五大查找之:哈希查找
- JSP面试题都在这里
- Java基础-07(01).总结private,this,封装,static,成员方法变量,局部变量匿名对象
- HTTP就是这么简单
- 重温二分查找算法(r4笔记第66天)
- 【不用框架】文件上传和下载
- JSP第七篇【简单标签、应用、DynamicAttribute接口】
- Java基础-07(02).总结private,this,封装,static,成员方法变量,局部变量匿名对象
- 通过shell脚本快速定位active session问题(r4笔记第65天)
- 01 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之业务分析与DAO层
- JSP第六篇【自定义标签之传统标签】
- 过滤器监听器面试题都在这里
- 02 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之Service层
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- golang gctrace分析gc过程
- golang 标准库 time/rate 介绍
- golang map的并发读写导致panic
- 正则表达式
- redis设计与实现系列1-SDS
- LinkedList - 876. Middle of the Linked List
- Array - 48. Rotate Image
- string- 43. Multiply Strings
- Array - 34. Find First and Last Position of Element in Sorted Array
- Array - 31. Next Permutation
- Docker快速部署一个属于你自己的博客
- golang实现BST和AVL
- golang实现跳表(SkipList)
- 一致性哈希的golang实现
- Array - 75. Sort Colors