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;
    }
原文地址:https://www.cnblogs.com/TLightSky/p/3479961.html