NinePatchChunk.java分析
最近在Swing中使用.9图片,用到了NinePatchChunk.java文件,但是发现有时会出现无法完美展示的情况,决定修复一下这个问题,顺便研究一些.9的绘制过程
通过分析发现draw函数先是计算出固定宽高大小,再计算出拉升区域大小,最后遍历固定大小和拉伸大小的矩形,进行拉升的覆盖。
在分析的时候发现,我所遇到的bug是通过计算固定高得到拉伸高度时,如果有一边被填满就无法计算准确这个值引起的。
这里:
int remainderHorizontal = 0;
int remainderVertical = 0; if (mFixed.size() > 0) {
int start = mFixed.get(0).y;
for (Rectangle rect : mFixed) {
if (rect.y > start) {
endRow = true;
measuredWidth = true;
}
if (!measuredWidth) {
remainderHorizontal += rect.width;
}
if (endRow) {
remainderVertical += rect.height;
endRow = false;
start = rect.y;
}
}
} data.mRemainderHorizontal = scaledWidth - remainderHorizontal;
data.mRemainderVertical = scaledHeight - remainderVertical;
解决方法之一就是不使用填满边的.9图。当然也可以修改代码来解决。
绘制的代码:
private void draw(BufferedImage image, Graphics2D graphics2D, int x, int y, int scaledWidth,
int scaledHeight) {
if (scaledWidth <= 1 || scaledHeight <= 1) {
return;
} Graphics2D g = (Graphics2D)graphics2D.create();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR); try {
if (mPatches.size() == 0) {
g.drawImage(image, x, y, scaledWidth, scaledHeight, null);
return;
} g.translate(x, y);
x = y = 0; DrawingData data = computePatches(scaledWidth, scaledHeight); int fixedIndex = 0;
int horizontalIndex = 0;
int verticalIndex = 0;
int patchIndex = 0; boolean hStretch;
boolean vStretch; float vWeightSum = 1.0f;
float vRemainder = data.mRemainderVertical; vStretch = mVerticalStartWithPatch;
while (y < scaledHeight - 1) {
hStretch = mHorizontalStartWithPatch; int height = 0;
float vExtra = 0.0f; float hWeightSum = 1.0f;
float hRemainder = data.mRemainderHorizontal; while (x < scaledWidth - 1) {
Rectangle r;
if (!vStretch) {
if (hStretch) {
r = mHorizontalPatches.get(horizontalIndex++);
float extra = r.width / data.mHorizontalPatchesSum;
int width = (int) (extra * hRemainder / hWeightSum);
hWeightSum -= extra;
hRemainder -= width;
g.drawImage(image, x, y, x + width, y + r.height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += width;
} else {
r = mFixed.get(fixedIndex++);
g.drawImage(image, x, y, x + r.width, y + r.height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += r.width;
}
height = r.height;
} else {
if (hStretch) {
r = mPatches.get(patchIndex++);
vExtra = r.height / data.mVerticalPatchesSum;
height = (int) (vExtra * vRemainder / vWeightSum);
float extra = r.width / data.mHorizontalPatchesSum;
int width = (int) (extra * hRemainder / hWeightSum);
hWeightSum -= extra;
hRemainder -= width;
g.drawImage(image, x, y, x + width, y + height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += width;
} else {
r = mVerticalPatches.get(verticalIndex++);
vExtra = r.height / data.mVerticalPatchesSum;
height = (int) (vExtra * vRemainder / vWeightSum);
g.drawImage(image, x, y, x + r.width, y + height, r.x, r.y,
r.x + r.width, r.y + r.height, null);
x += r.width;
} }
hStretch = !hStretch;
}
x = 0;
y += height;
if (vStretch) {
vWeightSum -= vExtra;
vRemainder -= height;
}
vStretch = !vStretch;
} } finally {
g.dispose();
}
}
计算patch长度和固定长度的remainder的代码
private DrawingData computePatches(int scaledWidth, int scaledHeight) {
DrawingData data = new DrawingData();
boolean measuredWidth = false;
boolean endRow = true;
int remainderHorizontal = 0;
int remainderVertical = 0;
if (mFixed.size() > 0) {
int start = mFixed.get(0).y;
for (Rectangle rect : mFixed) {
if (rect.y > start) {
endRow = true;
measuredWidth = true;
}
if (!measuredWidth) {
remainderHorizontal += rect.width;
}
if (endRow) {
remainderVertical += rect.height;
endRow = false;
start = rect.y;
}
}
}
data.mRemainderHorizontal = scaledWidth - remainderHorizontal;
data.mRemainderVertical = scaledHeight - remainderVertical;
data.mHorizontalPatchesSum = 0;
if (mHorizontalPatches.size() > 0) {
int start = -1;
for (Rectangle rect : mHorizontalPatches) {
if (rect.x > start) {
data.mHorizontalPatchesSum += rect.width;
start = rect.x;
}
}
} else {
int start = -1;
for (Rectangle rect : mPatches) {
if (rect.x > start) {
data.mHorizontalPatchesSum += rect.width;
start = rect.x;
}
}
}
data.mVerticalPatchesSum = 0;
if (mVerticalPatches.size() > 0) {
int start = -1;
for (Rectangle rect : mVerticalPatches) {
if (rect.y > start) {
data.mVerticalPatchesSum += rect.height;
start = rect.y;
}
}
} else {
int start = -1;
for (Rectangle rect : mPatches) {
if (rect.y > start) {
data.mVerticalPatchesSum += rect.height;
start = rect.y;
}
}
}
return data;
}
NinePatchChunk.java分析的更多相关文章
- java分析源码-ReentrantLock
一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...
- JAVA分析html算法(JAVA网页蜘蛛算法)
近来有些朋友在做蜘蛛算法,或者在网页上面做深度的数据挖掘.但是遇到复杂而繁琐的html页面大家都望而却步.因为很难获取到相应的数据. 最古老的办法的是尝试用正则表达式,估计那么繁琐的东西得不偿失,浪费 ...
- Java 分析工具汇总
http://blog.csdn.net/fenglibing/article/details/6411999 jps jps -mlvV jmap jmap -heap <pid> ...
- hello.java分析
如下图源码所示: 该段代码声明了一个entity实体类,该类有一个变量name,对该变量写了对应的get和set方法.类中还有一个空的构造方法hello(). @RequestScoped用于指定一个 ...
- Week4——Hello.java分析
如下图源码所示: 该段代码声明了一个entity实体类,该类有一个变量name,对该变量写了对应的get和set方法.类中还有一个空的构造方法hello(). @RequestScoped用于指定一个 ...
- 启动入口Start.java分析
框架的启动器在包:org.ofbiz.base.start 入口为:Start.java的main方法 Start.java启动器内容: 步骤 详情 入参校验 help/status/shutdown ...
- Intent.java分析
代码位于frameworks/base/core/java/anroid/Content/Intent.java Intent是对要进行操作的一种抽象描述.用action抽象操作,用data(andr ...
- java分析工具arthas
wget https://alibaba.github.io/arthas/arthas-boot.jar java -jar arthas-boot.jar --target-ip 0.0.0.0
- java 分析方法调用过程
StackTraceElement[] s = new Exception().getStackTrace(); for(int i=0;i<s.length;i++) System.out.p ...
随机推荐
- 全国绿色计算大赛 模拟赛第一阶段(Python)
第1关求和 class Task: def getSum(self, num1, num2): sum = 0 for i in range(num1, num2 + 1): while (i != ...
- PHP—通过HTML网页请求,PHP页面显示源码不能解析
对于初学者来说,可能会碰到这样一个问题,那就是我们通过html网页,在表单的action中填入后台处理的php文件后,虽然可以跳转到php网页上,但是却显示一大堆php源码而不是处理请求.像这样: ...
- db2事务日志已满解决办法
查看事务日志配置(MICRO_11为数据库名称): db2 get db cfg for MICRO_11 运行结果: 日志文件大小(4KB) (LOG ...
- FreeRTOS--疑难杂症
花了3个晚上,把这个章节看完,受益匪浅. 最有用的应该是与中断相关的错误,优先排查中断优先级设置. 堆栈溢出检查,可能用到,一般先把堆栈设置的足够大,只要没有溢出就是好事,溢出了,掌握了栈溢出钩子函数 ...
- NOR flash and NAND flash
(1)读写的基本单位 应用程序对NOR芯片操作以"字"为基本单位.为了方便对大容量NOR闪存的管理,通常将NOR闪存分成大小为128KB或者64KB的逻辑块,有时候块内还分成扇区. ...
- jquery给span赋值
span是最简单的容器,可以当作一个形式标签,其取值赋值方法有别于一般的页面元素. //赋值 $("#spanid").html(value) //取值 $("#span ...
- JavaEE JDBC 了解JNDI
了解JNDI @author ixenos Web与企业应用中的连接管理 1. 数据库连接方式: (1)使用配置文件 (2)使用JNDI 2. 在Web或企业环境中部署 JDBC应用时,数据库连接管理 ...
- bzoj1007 [HNOI2008]水平可见直线 - 几何 - hzwer.com
Description Input 第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi Output 从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必 ...
- CSU - 1333 1333: Funny Car Racing(spfa)
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1333 这题多了一个限制条件是每一条路都会规律的开放a时间关闭b时间,车子必须在开放的时候进入,在关 ...
- 1、Java并发性和多线程-并发性和多线程介绍
以下内容转自http://ifeve.com/java-concurrency-thread/: 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行 ...