个性缩放图片NinePatchDrawable

来源:互联网 发布:淘宝虚拟物品退款技巧 编辑:程序博客网 时间:2024/05/17 02:16
NinePatchDrawable
    A NinePatchDrawable graphic is a stretchable bitmap image,
which Android will automatically resize to accommodate the contents of the View in which you have placed it as the background. 

An example use of a NinePatch is the backgrounds used by standard Android buttons —
buttons must stretch to accommodate strings of various lengths. 
A NinePatch drawable is a standard PNG image that incl?s an extra 1-pixel-wide border. 
It must be saved with the extension .9.png, and saved into the res/drawable/ directory of your project.

The border is used to define the stretchable and static areas of the image. 
You indicate a stretchable section by drawing one (or more) 1-pixel-wide black line(s) in the left and top part of the border. 
(You can have as many stretchable sections as you want.) The relative size of the stretchable sections stays the same, 
so the largest sections always remain the largest.

You can also define an optional drawable section of the image (effectively, the padding lines)
 by drawing a line on the right and bottom lines. If a View object sets the NinePatch as its background 
 and then specifies the View's text, it will stretch itself so that all the text fits inside only 
 the area designated by the right and bottom lines (if incl?d). If the padding lines are not incl?d, 
 Android uses the left and top lines to define this drawable area.

To clarify the difference between the different lines, 
the left and top lines define which pixels of the image are allowed to be replicated in order to stretch the image. 
The bottom and right lines define the relative area within the image that the contents of the View are allowed to lie within.
NinePatchDrawable相对于Bitmap Drawable主要有增加了两个属性。他主要定义了图片的两类可区域。
一类是一般的可扩展(放大)区域区域,他主要用来填充控件的空白区域。
另一类区域主要用于填充内容区域(比如对于button来说内容区域就是其文本区域)

注意:
This NinePatch defines one stretchable area with the left 
and top lines and the drawable area with the bottom and right lines. 
In the top image, the dotted grey lines identify the regions of the image that will be replicated in order to stretch the image. 
The pink rectangle in the bottom image identifies the region in which the contents of the View are allowed. 
If the contents don't fit in this region, then the image will be stretched so that they do.
使用Draw 9-patch创建NinePatchDrawable形式的图(.9.png)

the Draw 9-patch tool allows you to easily create a NinePatch graphic using a WYSIWYG editor.
For an introd tion to Nine-patch graphics and how they work, 
please read the section on Nine-patch in the Ninepatch Images topic.
Here's a quick guide to create a Nine-patch graphic using the Draw 9-patch tool. You'll need the PNG image with which you'd like to create a NinePatch.

   1. From a terminal, launch the draw9patch application from your SDK /tools directory.
   2. Drag your PNG image into the Draw 9-patch window (or File > Open 9-patch... to locate the file). Your workspace will now open.
      The left pane is your drawing area, in which you can edit the lines for the stretchable patches and content area. 
      The right pane is the preview area, where you can preview your graphic when stretched.
   3. Click within the 1-pixel perimeter to draw the lines that define the stretchable patches and (optional) content area. 
           Right-click (or hold Shift and click, on Mac) to erase previously drawn lines.
           可以在图片的框的四边上,按下鼠标左键并拖动可以画黑线,按下shift键的同时按鼠标左键并拖动可清除画的黑线。
        A,左边那条黑色线代表图片垂直拉伸的区域,上边的那条黑色线代表水平拉伸区域。
        他们的交集就区域代表就垂直拉伸和水平拉伸都可以进行的区域。
        注意:我开始因为它是表达的只是他们的交集区域。
        其实不是,它要表达的垂直拉伸和水平拉伸区域,不能只是交集区域。
        因为如果只是交集区域的话,图片一放大,就不是长方形了。
        B,右边的黑色线代表内容绘制的垂直区域,下边的黑色线代表内容绘制的水平区域
        他们交集的区域就是内容所要绘制到的区域。
        对于button来说就是文本的区域,这样就可以控制文本显示的区域。
        如果
下边右边的黑线不是连续的,那它按最左端(上端)和最右端(下端)组成的线段来算内容区域
        注意:右边和下边的线是可选的,左边和上边的线不能省略
        
   4. When done, select File > Save 9-patch...
      Your image will be saved with the .9.png file name.
Draw 9-patch的使用,
NinePatchDrawable的使用和一般的Drawable一样,也是放在目录drawable下,
xml中引用如android:background="@drawable/test"的形式,其中"test"为文件名
参考资料:http://www.coolapk.com/docs/guide/developing/tools/draw9patch.html

NinePatch

The NinePatch class permits drawing a bitmap in nine sections. 
The four corners are unscaled; the four edges are scaled in one axis,
and the middle is scaled in both axes. Normally, 
the middle is transparent so that the patch can provide a selection about a rectangle.
Essentially, it allows the creation of custom graphics that will scale the way that you define, 
when content added within the image exceeds the normal bounds of the graphic. 
For a thorough explanation of a NinePatch image, read the discussion in the 2D Graphics document.
The Draw 9-Patch tool offers an extremely handy way to create your NinePatch images, using a WYSIWYG graphics editor. 
他可以让我们在运行时定制stretchable的区域和区域的填充方式
它的构造函数只有一个。
Public ConstructorsNinePatch(Bitmap bitmap, byte[] chunk, String srcName)
Create a drawable projection from a bitmap to nine patches.
它的jni函数在frameworks\base\core\jni\android\graphics\NinePatch.cpp
这里的byte[] chunk数据的格式一直不明白。
最后参看Android源码总算明白了。
chunk在jni(NinePatch.cpp)中主要用来构造Res_png_9patch这个结构体
chunk的至少有个sizeof(Res_png_9patch)大,即32个字节
Res_png_9patch的申明在

frameworks\base\incl?\utils\ResourceTypes.h
网上地址:http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=incl?/utils/ResourceTypes.h
Res_png_9patch的定义在frameworks\base\libs\utils\ResourceTypes.h中。
/** ******************************************************************** *  PNG Extensions * *  New private chunks that may be placed in PNG images. * *********************************************************************** *//** * This chunk specifies how to split an image into segments for * scaling. * * There are J horizontal and K vertical segments.  These segments divide * the image into J*K regions as follows (where J=4 and K=3): * *      F0   S0    F1     S1 *   +-----+----+------+-------+ * S2|  0  |  1 |  2   |   3   | *   +-----+----+------+-------+ *   |     |    |      |       | *   |     |    |      |       | * F2|  4  |  5 |  6   |   7   | *   |     |    |      |       | *   |     |    |      |       | *   +-----+----+------+-------+ * S3|  8  |  9 |  10  |   11  | *   +-----+----+------+-------+ * * Each horizontal and vertical segment is considered to by either * stretchable (marked by the Sx labels) or fixed (marked by the Fy * labels), in the horizontal or vertical axis, respectively. In the * above example, the first is horizontal segment (F0) is fixed, the * next is stretchable and then they continue to alternate. Note that * the segment list for each axis can begin or end with a stretchable * or fixed segment. * * The relative sizes of the stretchy segments indicates the relative * amount of stretchiness of the regions bordered by the segments.  For * example, regions 3, 7 and 11 above will take up more horizontal space * than regions 1, 5 and 9 since the horizontal segment associated with * the first set of regions is larger than the other set of regions.  The * ratios of the amount of horizontal (or vertical) space taken by any * two stretchable slices is exactly the ratio of their corresponding * segment lengths. * * xDivs and yDivs point to arrays of horizontal and vertical pixel * indices.  The first pair of Divs (in either array) indicate the * starting and ending points of the first stretchable segment in that * axis. The next pair specifies the next stretchable segment, etc. So * in the above example xDiv[0] and xDiv[1] specify the horizontal * coordinates for the regions labeled 1, 5 and 9.  xDiv[2] and * xDiv[3] specify the coordinates for regions 3, 7 and 11. Note that * the leftmost slices always start at x=0 and the rightmost slices * always end at the end of the image. So, for example, the regions 0, * 4 and 8 (which are fixed along the X axis) start at x value 0 and * go to xDiv[0] and slices 2, 6 and 10 start at xDiv[1] and end at * xDiv[2]. * * The array pointed to by the colors field lists contains hints for * each of the regions.  They are ordered according left-to-right and * top-to-bottom as indicated above. For each segment that is a solid * color the array entry will contain that color value; otherwise it * will contain NO_COLOR.  Segments that are completely transparent * will always have the value TRANSPARENT_COLOR. * * The PNG chunk type is "npTc". */struct Res_png_9patch{    Res_png_9patch() : wasDeserialized(false), xDivs(NULL),                       yDivs(NULL), colors(NULL) { }    int8_t wasDeserialized;    int8_t numXDivs;    int8_t numYDivs;    int8_t numColors;    // These tell where the next section of a patch starts.    // For example, the first patch includes the pixels from    // 0 to xDivs[0]-1 and the second patch includes the pixels    // from xDivs[0] to xDivs[1]-1.    // Note: allocation/free of these pointers is left to the caller.    int32_t* xDivs;    int32_t* yDivs;    int32_t paddingLeft, paddingRight;    int32_t paddingTop, paddingBottom;    enum {        // The 9 patch segment is not a solid color.        NO_COLOR = 0x00000001,        // The 9 patch segment is completely transparent.        TRANSPARENT_COLOR = 0x00000000    };    // Note: allocation/free of this pointer is left to the caller.    uint32_t* colors;    // Convert data from device representation to PNG file representation.    void deviceToFile();    // Convert data from PNG file representation to device representation.    void fileToDevice();    // Serialize/Marshall the patch data into a newly malloc-ed block    void* serialize();    // Serialize/Marshall the patch data    void serialize(void* outData);    // Deserialize/Unmarshall the patch data    static Res_png_9patch* deserialize(const void* data);    // Compute the size of the serialized data structure    size_t serializedSize();};


注意2:xDivs和yDivs用于确定可stretchable区域。
比如:
xDivs[0]和xDivs[1]确定一块可stretchable区域,
然后xDivs[2]和xDivs[3]又确定一块可stretchable区域
yDivs和xDivs一样。
注意2:colors指明了每个区域的填充颜色。
这里的区域并不区分非stretchable区域和stretchable区域
其中NO_COLOR = 0x00000001,表示用图片的填充
TRANSPARENT_COLOR = 0x00000000表示完全透明。
区域的顺序是从左到右,再从下到下。
面详细说明byte[] chunk的和Res_png_9patch中变量的对应关系
第0个字节          wasDeserialized  备注
第1个字节                     numXDivs                  X方向可stretchable的区域数量
第2个字节                     numYDivs                  Y方向可stretchable的区域数量
第3个字节                     numColors                color数(每个区域对应一个color)
第4,5,6,7字节                xDivsz指针            在chunk中没意义
第8,9,10,11字节            yDivsz指针            在chunk中没意义
第12,13,14,15字节     paddingLeft            没发现有什么用
第16,17,18,19字节     paddingRight            没发现有什么用
第20,21,22,23字节     paddingTop            没发现有什么用
第24,25,26,27字节     paddingBottom            没发现有什么用
第28,29,30,31字节            colors指针            在chunk中没意义

从sizeof(Res_png_9patch)开始的数据(即第32个字节开始):
首先是xDivsz指针指向的内容,其大小为numXDivs个int32_t
然后是yDivs指针指向的内容,其大小为numYDivs个int32_t
最后是colors指针指向的内容,其大小为numColors个int32_t(ARGB格式)
注意:对于int32_t这种多字节的类型是高字节在内存的高位
示例1
代码1

        BitmapDrawable bitmapDrawable=(BitmapDrawable)context.getResources().getDrawable(R.drawable.icon);
        Bitmap bitmap=bitmapDrawable.getBitmap();
        int width=bitmap.getWidth();
        System.out.println("width:"+width);
 
       byte numXDivs=4;
        byte numYDivs=4;
        byte numColors=numXDivs;
        int paddingLeft=10;
        int offset=0;
        numColors=(byte)((numColors+1)*(numYDivs+1));

        int size=32+(numXDivs+numYDivs+numColors)*4;
            byte chunk[]=new byte[size];
            chunk[0]=0;
            chunk[1]=numXDivs;
            chunk[2]=numYDivs;
            chunk[3]=numColors;
            byte pVal=0;
            chunk[4]=pVal;
            chunk[5]=pVal;
            chunk[6]=pVal;
            chunk[7]=pVal;
            
            chunk[8]=pVal;
            chunk[9]=pVal;
            chunk[10]=pVal;
            chunk[11]=pVal;
            offset=12;
            putInt(chunk,offset,paddingLeft);
            offset+=4;    
            offset=32;
            putInt(chunk,offset,10);
            offset+=4;
            putInt(chunk,offset,30);
            offset+=4;
            putInt(chunk,offset,40);
            offset+=4;
            putInt(chunk,offset,width);
            offset+=4;
            
            putInt(chunk,offset,11);
            offset+=4;
            putInt(chunk,offset,18);
            offset+=4;
            putInt(chunk,offset,30);
            offset+=4;
            putInt(chunk,offset,56);
            offset+=4;
            int color=0x00000F;
            int color2=0xFFFFF0;
            int colorInc=(color2-color)/numColors;
            
for(int i=0;i<numColors;i++)
            {
                    putInt(chunk,offset,0x2F000000|color);
                offset+=4;
                color+=colorInc;
            }
            
img9Patch=new NinePatch(bitmap,chunk,null);
代码2
    static void putInt(byte array[],int offset,int val)
    {
        array[offset]=(byte)(val&0xFF);
        val=val>>8;
        array[offset+1]=(byte)(val&0xFF);
        val=val>>8;
        array[offset+2]=(byte)(val&0xFF);
        val=val>>8;
        array[offset+3]=(byte)(val&0xFF);
    }

代码3:
        RectF rect =new RectF(0,0,Game.width,Game.height);
        img9Patch.draw(canvas, rect);

注意1:rect是要把img9Patch画到的区域。