现在的位置: 首页 > 综合 > 正文

Android点9图原理以及读取点9图的源代码

2017年02月23日 ⁄ 综合 ⁄ 共 10983字 ⁄ 字号 评论关闭

当我们需要自己绘制点9图时,比如游戏里面的某些ui元素,重写的view绘制需要canvas绘制点等情况时。

Android的.9图原理:(讲最特殊情况,即四个角不可拉伸,中间拉伸)。

1、使用边上一像素来标记一个图的可拉伸信息。

2、从中可读出四个信息,上边不可拉伸的高度,下边不可拉伸的高度,左边不可拉伸的宽度,右边不可拉伸的宽度

3、四个信息即可标识出一个九宫格,此处我就不画图了。

4、四个角为不可拉伸部分,上、下两边中间部分只能横向拉伸,左、右两边的中间部分只能竖直拉伸,中间板块为两个方向均可以拉伸。

Android读取.9图信息的代码(此代码不是本人自己所写,是本人的一个同伴查询Android源代码后写出来的,感谢一下这位小伙伴先)此代码大家可以直接拿出去用。

import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.Color;


public class NinePatchLoad {

 private static final int TRANSPARENT = Color.TRANSPARENT;
    private static final int BLACK = Color.BLACK;

    /**
     * Computes and returns the 9-patch chunks.
     * @param image the image containing both the content and the control outer line.
     * @return the {@link NinePatchChunk}.
     */
    public static NinePatchChunk load(Bitmap image) {
     
     ensure9Patch(image);
        return createChunk(image);
    }

    /**
     * Finds the 9-patch patches and padding from a
{@link
BufferedImage} image that contains
     * both the image content and the control outer lines.
     */
    private static NinePatchChunk createChunk(Bitmap image) {
     
        // the size of the actual image content
        int width = image.getWidth() - 2;
        int height = image.getHeight() - 2;

        int[] row = null;
        int[] column = null;

        // extract the patch line. Make sure to start at 1 and be only as long as the image content,
        // to not include the outer control line.
        row = getPixels(image, 1, 0, width, 1, row);
        column = getPixels(image, 0, 1, 1, height, column);

        boolean[] result = new boolean[1];
        Pair<List<Pair<Integer>>> left = getPatches(column, result);
        boolean mVerticalStartWithPatch = result[0];

        result = new boolean[1];
        Pair<List<Pair<Integer>>> top = getPatches(row, result);
        boolean mHorizontalStartWithPatch = result[0];
       
        int[] horizontalPatch;
       
        if (mHorizontalStartWithPatch) {
      horizontalPatch = getAlternativeLength(top.mSecond, top.mFirst);
     } else {
      horizontalPatch = getAlternativeLength(top.mFirst, top.mSecond);
     }
       
        int[] verticalPatch;
       
        if (mVerticalStartWithPatch) {
      verticalPatch = getAlternativeLength(left.mSecond, left.mFirst);
     } else {
      verticalPatch = getAlternativeLength(left.mFirst, left.mSecond);
     }
       
        int tLeft, tMiddle, tRight, lTop, lMiddle, lBottom;
       
        if (horizontalPatch.length == 3) {
         tLeft = horizontalPatch[0];
         tMiddle = horizontalPatch[1];
         tRight = horizontalPatch[2];
        } else {
         tLeft = 1;
         tRight = 1;
         tMiddle = width - 2;
        }
       
        if (verticalPatch.length == 3) {
         lTop = verticalPatch[0];
         lMiddle = verticalPatch[1];
         lBottom = verticalPatch[2];
        } else {
         lTop = 1;
         lBottom = 1;
         lMiddle = height - 2;
        }
       
        Bitmap finalBitmap =  Bitmap.createBitmap(image,
          1, 1, image.getWidth() - 2, image.getHeight() - 2);
        image.recycle();
       
        return new NinePatchChunk(finalBitmap,
                tLeft, tMiddle, tRight, lTop, lMiddle, lBottom,
                horizontalPatch, verticalPatch,
                mHorizontalStartWithPatch, mVerticalStartWithPatch);
    }
   
    private static int[] getPixels(Bitmap img, int x, int y, int w, int h, int[] pixels) {
        if (w == 0 || h == 0) {
            return new int[0];
        }
       
        if (pixels == null) {
            pixels = new int[w * h];
        } else if (pixels.length < w * h) {
            throw new IllegalArgumentException("Pixels array must have a length >= w * h.");
        }

        img.getPixels(pixels, 0, w, x, y, w, h);
        return pixels;
    }
   
    // "a" should >= "b", and take "a" first and then "b", to fill an array alternatively.
    private static int[] getAlternativeLength(List<Pair<Integer>> a, List<Pair<Integer>> b) {
     
     int [] result = new int[a.size() + b.size()];
     
     int diff = a.size() - b.size();
     
     if (diff < 0 || diff > 1) {
      return null;
     }
     
     int i = 0;
     
     while(i < b.size()) {
      result[i*2] = a.get(i).mSecond - a.get(i).mFirst;
      result[i*2+1] = b.get(i).mSecond - b.get(i).mFirst;
      i++;
     }
     if (diff > 0) {
      result[i*2] = a.get(i).mSecond - a.get(i).mFirst;
     }
     
     return result;
    }
   

    /**
     * Computes a list of Patch based on a pixel line.
     *
     * This returns both the fixed areas, and the patches (stretchable) areas.
     *
     * The return value is a pair of list. The first list ({@link Pair#mFirst}) is the list
     * of fixed area. The second list ({@link Pair#mSecond}) is the list of stretchable areas.
     *
     * Each area is defined as a Pair of (start, end) coordinate in the given line.
     *
     * @param pixels the pixels of the control line. The line should have the same length as the
     *           content (i.e. it should be stripped of the first/last control pixel which are not
     *           used)
     * @param startWithPatch a boolean array of size 1 used to return the boolean value of whether
     *           a patch (stretchable area) is first or not.
     * @return
     */
    private static Pair<List<Pair<Integer>>> getPatches(int[] pixels, boolean[] startWithPatch) {
        int lastIndex = 0;
        int lastPixel = pixels[0];
        boolean first = true;

        List<Pair<Integer>> fixed = new ArrayList<Pair<Integer>>();
        List<Pair<Integer>> patches = new ArrayList<Pair<Integer>>();

        for (int i = 0; i < pixels.length; i++) {
            int pixel = pixels[i];
            if (pixel != lastPixel) {
                if (lastPixel == BLACK) {
                    if (first) startWithPatch[0] = true;
                    patches.add(new Pair<Integer>(lastIndex, i));
                } else {
                    fixed.add(new Pair<Integer>(lastIndex, i));
                }
                first = false;

                lastIndex = i;
                lastPixel = pixel;
            }
        }
        if (lastPixel == BLACK) {
            if (first) startWithPatch[0] = true;
            patches.add(new Pair<Integer>(lastIndex, pixels.length));
        } else {
            fixed.add(new Pair<Integer>(lastIndex, pixels.length));
        }

        if (patches.size() == 0) {
            patches.add(new Pair<Integer>(1, pixels.length));
            startWithPatch[0] = true;
            fixed.clear();
        }

        return new Pair<List<Pair<Integer>>>(fixed, patches);
    }
   
    private static void ensure9Patch(Bitmap image) {
     
        int width = image.getWidth();
        int height = image.getHeight();
        for (int i = 0; i < width; i++) {
            int pixel = image.getPixel(i, 0);
            if (pixel != TRANSPARENT && pixel != BLACK) {
                image.setPixel(i, 0, TRANSPARENT);
            }
            pixel = image.getPixel(i, height - 1);
            if (pixel != TRANSPARENT && pixel != BLACK) {
                image.setPixel(i, height - 1, TRANSPARENT);
            }
        }
        for (int i = 0; i < height; i++) {
            int pixel = image.getPixel(0, i);
            if (pixel != TRANSPARENT && pixel != BLACK) {
                image.setPixel(0, i, TRANSPARENT);
            }
            pixel = image.getPixel(width - 1, i);
            if (pixel != TRANSPARENT && pixel != BLACK) {
                image.setPixel(width - 1, i, TRANSPARENT);
            }
        }
    }

    /**
     * A pair of values.
     *
     * @param <E>
     */
    static class Pair<E> {

        E mFirst;
        E mSecond;

        Pair(E first, E second) {
            mFirst = first;
            mSecond = second;
        }

        @Override
        public String toString() {
            return "Pair[" + mFirst + ", " + mSecond + "]";
        }
    }

保持点9图信息的Java been

import android.graphics.Bitmap;

/**
 * Contains info of Nine Patch
 */
public class NinePatchChunk {

    // instance variables
    private Bitmap mImage;
   
    // ��һ�������Ƿ���Ժ�������
    private boolean mHorizontalStartWithPatch;
    // ��һ�������Ƿ������������
    private boolean mVerticalStartWithPatch;
    private float w;
    private float h;
    private float leftW;
    private float tMiddle;
    private float rightW;
   
    private float topH;
    private float lMiddle;
    private float bottomH;
   
   
    private int[] horizontalPatch;
    private int[] verticalPatch;

    public NinePatchChunk(){
     
    }
    public NinePatchChunk(Bitmap image,
           int tL, int tM, int tR,
           int lT, int lM, int lB,
           int[] hPatch, int[] vPatch,
           boolean hStart, boolean vStart) {
     mImage = image;
     w = image.getWidth();
     h = image.getHeight();
     leftW = tL;
     tMiddle = tM;
     rightW = tR;
     topH = lT;
        lMiddle = lM;
        bottomH = lB;
        horizontalPatch = hPatch;
        verticalPatch = vPatch;
        mHorizontalStartWithPatch = hStart;
        mVerticalStartWithPatch = vStart;
    }
   
    public Bitmap getImage() {
        return mImage;
    }
   
    /**
     * The horizontal division of patches
     * @return
     */
    public int[] getHorizontalPatch() {
     
     return horizontalPatch;
    }
   
    /**
     * The vertical division of patches
     * @return
     */
    public int[] getVerticalPatch() {
     
     return verticalPatch;
    }
   
    /**
     * If the first horizontal area can be stretched
     * @return
     */
    public boolean isStartWithPatchHorizontal() {
     return mHorizontalStartWithPatch;
    }
   
    /**
     * If the first vertical area can be stretched
     * @return
     */
    public boolean isStartWithPatchVertical() {
     return mVerticalStartWithPatch;
    }
   
    public String toString() {
     String str = "";
     str += "        " +  mHorizontalStartWithPatch + "\n";
     str += mVerticalStartWithPatch + "   ";
     for (int a : horizontalPatch) {
      str += a + "  ";
     }
     str += "\n  ";
     for (int a : verticalPatch) {
      str += a + "\n  ";
     }
     return str;
    }
    public float getW(){
     return w;
    }
    public void setW(float w) {
  this.w = w;
 }
 public float getH() {
  return h;
 }
 public void setH(float h) {
  this.h = h;
 }
 public float getLiftW() {
  return leftW;
 }
 public void setLiftW(float leftW) {
  this.leftW = leftW;
 }
 public float getRightW() {
  return rightW;
 }
 public void setRightW(float rightW) {
  this.rightW = rightW;
 }
 public float getTopH() {
  return topH;
 }
 public void setTopH(float topH) {
  this.topH = topH;
 }
 public float getButtonH() {
  return bottomH;
 }
 public void setButtonH(float buttonH) {
  this.bottomH = buttonH;
 }
 
}

这里代码写的不是很好,大家见谅吧。

可以看得出来,这个JavaBeen对象中就能得到此.9图的拉伸信息,然后我们在绘制时即可用此信息进行绘制。

Android里面绘制bitmap一般有两种方式,canvas绘制和OpenGL绘制,有了点9图的拉伸信息了,使用Canvas去绘制应该不是问题很大。

大致说一下OpenGL里面的绘制吧

1、构建一个能使用OpenGL绘制的简单纹理矩形。(在OpenGL里面个人喜欢把一个矩形叫做一个ImageView,这个View里面有这个View的大小、位置、纹理坐标等信息,绘制时需要传入其对应的纹理ID,这个纹理ID是绑定了Bitmap的纹理ID)

 public static void drawPortrait(int shaderIndex,FloatBuffer positionBf,FloatBuffer textureCoordBf,int textureId){
  GLES20.glUseProgram(programHandle[shaderIndex][shader]);
  GLES20.glUniformMatrix4fv(programHandle[shaderIndex][uMVPMatrix], 1, false,MatrixState.getFinalMatrix(), 0);
  GLES20.glVertexAttribPointer(programHandle[shaderIndex][aPosition], 3,GLES20.GL_FLOAT, false, 0, positionBf);
  GLES20.glVertexAttribPointer(programHandle[shaderIndex][aTextureCoord], 2,GLES20.GL_FLOAT, false, 0,textureCoordBf);
  GLES20.glEnableVertexAttribArray(programHandle[shaderIndex][aPosition]);
  
  GLES20.glEnableVertexAttribArray(programHandle[shaderIndex][aTextureCoord]);
  
  
  GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  
  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
  
  GLES20.glUniform1i(programHandle[shaderIndex][sTexture], 0);
  GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

  GLES20.glDisableVertexAttribArray(programHandle[shaderIndex][aPosition]);

  GLES20.glDisableVertexAttribArray(programHandle[shaderIndex][aTextureCoord]);
 }

programHandle数组是装了OpenGL ES 2.0里面Shader程序的各个变量的引用id,OpenGL具体怎么绘图请看其相关的文章吧。

2、根据点九图信息构建九个这样的矩形。绘制点9图需要九个这样的ImageView,然后需要注意的一点是纹理的坐标是0到1,所以需要计算好每个view对应的纹理坐标是多少,根据点九图的信息来换算。

3、根据实际要绘制的大小计算九个View的大小以及位置信息,当你要把点9图绘制成一个W*H的矩形时,需要计算好九宫格中每个矩形的大小和位置,这个位置的计算请根据Opengl里面的坐标设置来换算,这个知识点比较多,就不多讲了。

4、调用OpenGL的具体绘制方法进行绘制。

本人倒是有使用OpenGL绘制点9图的代码(自实现),但是设计到OpenGL,里面就有一大堆东西,此处就不细说了哈。



抱歉!评论已关闭.