android图形系统详解三:形状Drawable和九宫格
形状Drawable
当你想动态画2维图形,ShapeDrawable对象是可能是你合适的选择.使用ShapeDrawable,你可以随意画出原始的形状并且应用到任何风格.
ShapeDrawable是一个Drawable的派生类,所以你可以用于任何想使用Drawable的地方—比如可能是一个View的背景,通过setBackgroundDrawable()所设置.当然,你也可以把你的形状作为它自己的自定义View绘制,然后以你喜欢的方式添加到你的Layout.因为ShapeDrawable有它自己的draw()方法,你可以创建一个View的子类然后在View.onDraw()的方法中画这个ShapeDrawable.下面是一个简单的View派生类,它仅把ShapeDrawable当作一个View绘出:
[java] view plaincopy
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
在构造函数中,以OvalShape定义了一个ShapeDrawable.然后给它设置了颜色和形状的边界.如果你不设置边界,形状是不会被画出的,如果你不设置颜色,将以黑色画之.
使用自定义View,你可以画任何东西.在上面的例子中,我们可以在一个Activity中用程序随意作画:
[java] view plaincopy
CustomDrawableView mCustomDrawableView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView);
}
如果你想在XMLlayout中画这个自定义drawable而不是在Activity中,那么这个CustomDrawableView类必须重写View(Context,AttributeSet)构造方法,此方法在从XML初始化一个View时被调用.然后添加一个CustomDrawable元素到XML,像这样:
[html] view plaincopy
<com.example.shapedrawable.CustomDrawableView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
ShapeDrawable类(就像android.graphics.drawable包中的其它一些Drawable类型)允许你使用公开方法来定义drawable的各种属性.你要调整的一些属性可能有alpha透明,颜色过虑,抖动,opacity和color等.
你也可以使用XML定义原始的drawable形状.更多的信息请看Drawable资源文档中的ShapeDrawables章节.
九宫格NinePatch
一个NinePatchDrawable图形是一个可拉申的位图,在把它作为View的背景时,Android自动把它的大小拉伸来适应View的内容.一个例子就是标准按钮使用NinePatch作为自己的背景— 按钮必须能被拉申来适应文本的长度.NinePatchdrawable是一个标准的PNG图像,但它包含了一个额外的1像素宽的边框.它必须保存为.9.png这样的扩展名,并且放在你的工程的res/drawable/文件夹下.
边框被用来定义图像的可拉伸区和静态区.你通过在上边框和左边框画1个(或多个)1像素宽的黑线来表明可伸缩区域(其它边框部分需保持完全透明或白色).你可以设定任意数量的可伸缩段:它们的相对大小不变,所以最大的段总是保持最大.
你也可以通过在右边框和下边框画线来定义一个图像的可选的可绘制段(实际上,叫做填充线段).如果一个View对象设置了NinePatch作为背景然后又指定了自己的文本,它将拉伸自己以使所有的文本恰好处于被右和下的线段所指定的区域内.如果填充线段不存在,Android使用左和上的线段来定义这个可绘制区域.
左和上的线段定义了图像的哪些像素可以在拉伸时被复制;下和右的线段定义了图像的内容应被放入的区域,这些区域的位置都是相对的.
下面是一个用NinePatch文件定义一个按钮的例子:
这个NinePatch用上和左线段定义了一个可拉伸区域并用右和下线段定义了可绘制区域.在第一个图中,灰色虚线表明了拉伸时要被复制的区域,红色框表明了View的内容应在的区域.如果内容不适合这个区域,那么图像将被拉伸直到能适合.
画9-patch的工具提供了一个极顺手的方式来创建你的NinePatch图像,它有一个WYSIWYG图像编辑器.如果你定义的可拉伸区域有产生像素复写的风险时,它甚至会发出警告.
XML例子
下面是一个 layoutXML例子来演示如何添加一个NinePatch图像到一对按钮中.(NinePatch图像被保存为res/drawable/my_button_background.9.png)
[html] view plaincopy
<Button id="@+id/tiny"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:text="Tiny"
android:textSize="8sp"
android:background="@drawable/my_button_background"/>
<Button id="@+id/big"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:text="Biiiiiiig text!"
android:textSize="30sp"
android:background="@drawable/my_button_background"/>
注意width和height被设置为"wrap_content"使得按钮能恰好包含文本.
下图是两个从XML和and上面所显示的NinePatch图像所画出的按钮.注意按钮的宽和高如何跟据文本而变化,以及背景图如何拉伸以适应它.