All Downloads are FREE. Search and download functionalities are using the official Maven repository.

freeseawind.ninepatch.common.AbstractNinePatch Maven / Gradle / Ivy

The newest version!
package freeseawind.ninepatch.common;

import java.awt.Rectangle;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import freeseawind.ninepatch.common.Row.Type;

/**
 * @author freeseawind@github
 *
 */
public abstract class AbstractNinePatch
{
    /**
     * 拉伸区域,像素值必须为黑色 0xFF000000
     */
    public static final int PATCH_PIXES = 0xFF000000;
    private int lastWidth;
    private int lastHeight;
    private int patchWidth;
    private int patchHeight;
    private int horizontalPatchNum;
    private int verticalPatchNum;
    private List> columns;
    private Padding padding;
    private T image;
    private RepeatType repeatType;

    public AbstractNinePatch(T image)
    {
        this(image, null);
    }
    
    public AbstractNinePatch(T image, RepeatType repeatType)
    {
        image = toCompatibleImage(image);
        
        countPatch(image);
        
        this.image = image;
        
        this.repeatType = repeatType;
    }

    /**
     *
     * @param g2d
     * @param x
     * @param y
     * @param scaledWidth
     * @param scaledHeight
     */
	public void drawNinePatch(E g2d, int x, int y, int scaledWidth, int scaledHeight)
	{
		// 修复BUG防止拉伸大小小于等于原图大小
        if (scaledWidth <= 1 || scaledHeight <= 1)
        {
            return;
        }

        try
        {
            if(lastWidth != scaledWidth || lastHeight != scaledHeight)
            {
                lastWidth = scaledWidth;

                lastHeight = scaledHeight;

                resetData(scaledWidth, scaledHeight);
            }

            if(patchWidth == scaledWidth && patchHeight == scaledHeight)
            {
                drawImage(g2d, image, x, y, scaledWidth, scaledHeight);

                return;
            }

            translate(g2d, x, y);

            int startX = 0;
            int startY = 0;
            int minWidth = patchWidth;
            int minHeight = patchHeight;

            if(horizontalPatchNum > 1)
            {
                minWidth = (patchWidth / horizontalPatchNum);
            }

            if(verticalPatchNum > 1)
            {
                minHeight = (patchHeight / verticalPatchNum);
            }

            int columnCount = 0;

            // 逐行绘制
            for(List rows : columns)
            {
                int rowCount = 0;

                int height = patchHeight;

                boolean isFirst = true;

                int preRowHeight = 0;
                
                // 防止图片拉伸高度大于实际需要拉伸高度
                if(startY >= scaledHeight)
                {
                    break;
                }

                for(Row row : rows)
                {
                    Rectangle rect = row.getRectangle();

                    int width = rect.width;
                    
                    // 防止图片拉伸宽度大于实际需要拉伸宽度
                    if(startX >= scaledWidth)
                    {
                        break;
                    }

                    if(Type.HORIZONTALPATCH == row.getType() || Type.TILEPATCH == row.getType())
                    {
                        // 计算拉伸的宽度
                        width = (patchWidth - minWidth * (rowCount + 1));

                        if(width < minWidth)
                        {
                            width = patchWidth - (minWidth * rowCount);
                        }
                        else
                        {
                            width = minWidth;
                        }

                        rowCount++;
                    }
                    else if(Type.HORIZONTALPATCH == row.getType())
                    {
                        // 计算拉伸的高度
                        if(isFirst)
                        {
                            height = (patchHeight - minHeight * (columnCount + 1));

                            if(height < minHeight)
                            {
                                height = patchHeight - (minHeight * columnCount);
                            }
                            else
                            {
                                height = minHeight;
                            }

                            columnCount++;

                            isFirst = false;
                        }
                    }

                    // 绘制固定区域
                    if(Type.FIX == row.getType())
                    {
                        drawImage(g2d, image, rect.x, rect.y, rect.width, rect.height, startX, startY, rect.width, rect.height);

                        startX += rect.width;

                        preRowHeight = rect.height;
                    }
                    else if(Type.HORIZONTALPATCH == row.getType())
                    {
                        // 绘制水平拉伸区域
                        drawImage(g2d, image, rect.x, rect.y, rect.width, rect.height, startX, startY, width, rect.height);

                        startX += width;

                        preRowHeight = rect.height;
                    }
                    else if(Type.VERTICALPATCH == row.getType())
                    {
                        // 垂直拉伸
                        drawImage(g2d, image, rect.x, rect.y, rect.width, rect.height, startX, startY, rect.width, height);

                        startX += rect.width;

                        preRowHeight = height;
                    }
                    else if(Type.TILEPATCH == row.getType())
                    {
                        // 平铺
                        if(repeatType != null)
                        {
                            repeatImage(g2d, image, rect.x, rect.y, rect.width, rect.height, startX, startY, width, height);
                        }
                        else
                        {
                            drawImage(g2d, image, rect.x, rect.y, rect.width, rect.height, startX, startY, width, height);
                        }

                        startX += width;

                        preRowHeight = height;
                    }
                }

                startX = 0;
                startY += preRowHeight;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            translate(g2d, -x, -y);
        }
    }

    public List> countColumn(NinePatchRegion xRegions, NinePatchRegion yRegions)
    {
        boolean isPatchY = false; // 当前是否处于拉伸区域
        int i = 0; // 固定区域起始索引
        int j = 0;// 拉伸区域起始索引
        int patchNum = yRegions.getPatchRegions().size();
        int fixNum = yRegions.getFixRegions().size();

        Region yRegion = null; // 循环出口条件

        List> columns = new LinkedList>();// 九宫格行集合

        do
        {
            yRegion = null;

            if (isPatchY && patchNum >= j + 1)
            {
                yRegion = yRegions.getPatchRegions().get(j++);
            }

            if (!isPatchY && fixNum >= i + 1)
            {
                yRegion = yRegions.getFixRegions().get(i++);
            }

            if(yRegion != null)
            {
                columns.add(countRow(yRegion, xRegions, isPatchY));
            }

            isPatchY = !isPatchY;
        }
        while (yRegion != null);

        return columns;
    }

    /**
     * 计算点九图的每一列区域
     * @param yRegion
     * @param xRegions
     * @param isPatchY
     * @return 返回当前行
     */
    public List countRow(Region yRegion, NinePatchRegion xRegions, boolean isPatchY)
    {
        boolean isPatchX = false;
        int i = 0;
        int j = 0;
        int patchNum = xRegions.getPatchRegions().size();
        int fixNum = xRegions.getFixRegions().size();

        Region xRegion = null;

        List column = new LinkedList();

        do
        {
            xRegion = null;

            if (isPatchX && patchNum >= j + 1)
            {
                xRegion = xRegions.getPatchRegions().get(j++);
            }

            if (!isPatchX && fixNum >= i + 1)
            {
                xRegion = xRegions.getFixRegions().get(i++);
            }

            if(xRegion != null)
            {
                Row.Type rowType = getRowType(isPatchX, isPatchY);

                int height = yRegion.getEnd() - yRegion.getStart();

                int width = xRegion.getEnd() - xRegion.getStart();

                Rectangle rect = new Rectangle(xRegion.getStart() + 1, yRegion.getStart() + 1, width, height);

                Row row = new Row(rect, rowType);

                column.add(row);
            }

            isPatchX = !isPatchX;
        }
        while (xRegion != null);

        Collections.sort(column);

        return column;
    }



    /**
     * 获取内容显示区域的间距
     * @param w 内容面板的宽度
     * @param h 内容面板的高度
     * @param xRegions x坐标集合
     * @param yRegions y坐标集合
     * @return
     */
    public Padding getPadding(int w, int h, List xRegions, List yRegions)
    {
        Region xRegion = xRegions.get(0);
        Region yRegion = yRegions.get(0);

        int left = xRegion.getStart();
        int top = yRegion.getStart();
        int right = w - xRegion.getEnd();
        int bottom = h - yRegion.getEnd();

        return new Padding(left, top, right, bottom);
    }

    /**
     * 根据像素值集合计算当前像素区域中的固定区域和拉伸区域
     * @param pixels 需要查找的像素集合
     * @return
     */
    public NinePatchRegion getPatches(int[] pixels)
    {
        int start = 0;

        int lastPixel = pixels[0];

        List fixArea = new LinkedList();

        List patchArea = new LinkedList();

        for(int i = 1; i <= pixels.length; i++)
        {
            if(i < pixels.length && lastPixel == pixels[i])
            {
                continue;
            }

            // 区间对象
            Region region = new Region(start, i);

            if (PATCH_PIXES == lastPixel)
            {
                patchArea.add(region);
            }
            else
            {
                fixArea.add(region);
            }

            start = i;

            if(i < pixels.length)
            {
                lastPixel = pixels[i];
            }
        }

        // 像素集合中没有找到特殊像素
        if(start == 0)
        {
            Region region = new Region(start, pixels.length);

            if (PATCH_PIXES == lastPixel)
            {
                patchArea.add(region);
            }
            else
            {
                fixArea.add(region);
            }
        }

        return new NinePatchRegion(fixArea, patchArea);
    }
    
    /**
     * 平铺图片
     * @param g2d
     * @param image
     * @param x
     * @param y
     * @param sw
     * @param sh
     * @param dx
     * @param dy
     * @param dw
     * @param dh
     */
    public void repeatImage(E g2d,
                            T image,
                            int x,
                            int y,
                            int sw,
                            int sh,
                            int dx,
                            int dy,
                            int dw,
                            int dh)
    {
        if (repeatType == null)
        {
            return;
        }

        if (repeatType == RepeatType.HORIZONTAL)
        {
            int hornaizeW = dw;

            // 
            do
            {
                if (hornaizeW - sw < 0)
                {
                    sw = hornaizeW;
                }

                hornaizeW -= sw;

                drawImage(g2d, image, x, y, sw, sh, dx, dy, sw, dh);

                dx += sw;

            }
            while (hornaizeW > 0);
        }
        else if (repeatType == RepeatType.VERTICAL)
        {
            int verticalH = dh;

            // ˮƽÀ­Éì
            do
            {
                if (verticalH - sh < 0)
                {
                    sh = verticalH;
                }

                verticalH -= sh;

                drawImage(g2d, image, x, y, sw, sh, dx, dy, dw, sh);

                dy += sh;

            }
            while (verticalH > 0);
        }
    }
    
    /**
     * 计算点九图片信息
     * 

|1| 2 |3|

*

|4| 5 |6|

*

|7| 8 |9|

* 计算图片中每一行里的固定区域、垂直拉伸区、水平拉伸区和平铺区域以及内容显示间距 * @param image */ protected void countPatch(T image) { // 图片实际宽度, 不包含左右控制区域 int width = getImageWidth(image) - 2; // 图片实际高度, 不包含上下控制区域 int height = getImageHeight(image) - 2; // 行 int[] row = null; // 列 int[] column = null; // 获取左侧拉伸区域的像素 column = getPixels(image, 0, 1, 1, height); // 获取左侧垂直列 NinePatchRegion left = getPatches(column); // 获取顶部拉伸区域的像素值, 不包含左右控制区域,所以向右偏移一个像素 row = getPixels(image, 1, 0, width, 1); // 获取顶部水平行 NinePatchRegion top = getPatches(row); // 水平拉伸区域素数量 this.horizontalPatchNum = top.getPatchRegions().size(); // 垂直拉伸区域数量 this.verticalPatchNum = left.getPatchRegions().size(); this.columns = countColumn(top, left); // 获取底部水平内容拉伸区域像素集合 row = getPixels(image, 1, height + 1, width, 1); // 获取右侧垂直内容拉伸区域像素集合 column = getPixels(image, width + 1, 1, 1, height); NinePatchRegion bottom = getPatches(row); NinePatchRegion right = getPatches(column); this.padding = getPadding(width, height, bottom.getPatchRegions(), right.getPatchRegions()); } protected T toCompatibleImage(T image) { return image; } /** * 从指定的矩形区域中读取像素数据 * @param img * @param x 起始x坐标 * @param y 起始y坐标 * @param w 矩形的宽度 * @param h 矩形的高度 * @return 指定矩形区域像素数据整型数组 */ public abstract int[] getPixels(T img, int x, int y, int w, int h); /** * 获取图片宽度 * @param img * @return */ public abstract int getImageWidth(T img); /** * 获取图片高度 * @param img * @return */ public abstract int getImageHeight(T img); /** * * @param g2d * @param x * @param y */ public abstract void translate(E g2d, int x, int y); /** * * @param g2d * @param image * @param x * @param y * @param scaledWidth * @param scaledHeight */ public abstract void drawImage(E g2d, T image, int x, int y, int scaledWidth, int scaledHeight); /** * * @param g2d * @param image * @param sx * @param sy * @param sw * @param sh * @param dx * @param dy * @param dw * @param dh */ public abstract void drawImage(E g2d, T image, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh); /** * * @param scaleWidth * @param scaleHeight */ private void resetData(int scaleWidth, int scaleHeight) { this.patchWidth = scaleWidth; this.patchHeight = scaleHeight; boolean isFirst = true; boolean isNewColumn = true; for(List rows : columns) { for(Row row : rows) { if(Type.FIX == row.getType() && isFirst) { patchWidth -= row.getRectangle().width; } //BUG FIX: 修复显示区域计算问题 if(Type.FIX == row.getType() && isNewColumn) { patchHeight -= row.getRectangle().height; isNewColumn = false; } } isNewColumn = true; isFirst = false; } } private Type getRowType(boolean isPatchX, boolean isPatchY) { if (!isPatchX && !isPatchY) { return Type.FIX; } if (!isPatchX && isPatchY) { return Type.VERTICALPATCH; } if (isPatchX && !isPatchY) { return Type.HORIZONTALPATCH; } return Type.TILEPATCH; } public Padding getPadding() { return padding; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy