最近在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; }