Android 自定义View - 启航 一般View定义
Android应用程序使用View和ViewGroup来构建用户界面,它们都是继承自View类(或其子类)例如:Button、TextView、EditText等。各类View搭配上Style和Animation可以编织出非常丰富的UI,足以应付绝大部分的需求。但有时候我们也需要一些特别的View ,以带给用户与众不同的体验。
在此我打算写一个大长篇都是关于android View的,主要内容为:SDK上部分文章翻译(英文水平有限尽请拍砖);自定义的View、android源代码分析、开源View代码分析;各类App应用的界面模仿;以理论+代码示例+实践 的方式指导本系列博文的撰写。
——因为本人水平有限,而且写系列经常虎头蛇尾,所以这个系列就不写总目录了。如果哪天您发现本系列不在更新,而我又开始了另一个“大长篇”,那么请扔鸡蛋吧。(但是我们不退票!)
——出于前车之鉴,本系列中的源码将不提供打包服务。
言归正传,在我们编写android程序时一般是自定义以一个类继承自Activity 并且重写onCreate方法:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
setContentView()方法包含多个重载其中一个便是“setContentView(View view)”,也就是说可以直接通过一个View的实例来构建内容。我们尝试放入一个TextView,上面的代码变成了这样:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
//
setContentView(R.layout.main);
TextView sayHello = new
TextView(this);
sayHello.setText("Hello world! I'm a
TextView.");
setContentView(sayHello);
}
运行这段代码,在模拟器上你应该可以看到以下结果:
如此简单不是吗?好吧让我们再让它丰富点:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
//
setContentView(R.layout.main);
// TextView sayHello = new
TextView(this);
// sayHello.setText("Hello world! I'm a
TextView.");
setContentView(new SayHello(this));
}
class SayHello extends View{
public SayHello(Context context)
{
super(context);
}
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(canvas);
Paint mPaint=new Paint()
;
mPaint.setTextSize(22f);
mPaint.setColor(Color.RED);
canvas.drawText("Hello
world! I'm a TextView.", 0, 100, mPaint);
}
}
这次我们自定义了一个局部类SayHello 继承自View并且重写了 onDraw 方法(需要注意的是由于View没有无参构造函数所以我们为其指定实现哪一个构造函数)。在onDraw 方法中我们定义了一个Paint,现在你只需要理解它有绘画的功能即可,那么它要在哪里绘画呢?答案就是在Canvas上,可以把Canvas理解成画布。
现在我们设置mPaint的字体大小为22F 颜色为红色,然后在画布上写出“Hello
world。。。”这几个红色的字,并且把onCreate里的setContentView 为setContentView(new
SayHello(this));
最后在模拟器上你应该看到的是:
so cool! 不是吗?
不!不对,我们在Android的开发View不是这样的,它应该是通过 Xml.......@##¥%
好吧 让我们再把例子修改一下。
首先我们将SayHello 类提取出来,并且将它放入一个单独的类文件中,接下来就是重点:我们需要添加另外的一些构造函数以便给View传递参数,最好你看到的SayHello 类应该是这样的:
public class SayHello extends View
{
public SayHello(Context
context)
{
super(context);
}
public SayHello(Context context, AttributeSet
attrs) {
this(context, attrs,0);
}
public SayHello(Context
context, AttributeSet attrs,int defStyle)
{
super(context, attrs,
defStyle);
}
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(canvas);
Paint mPaint=new Paint()
;
mPaint.setTextSize(22f);
mPaint.setColor(Color.RED);
canvas.drawText("Hello
world! I'm a TextView.", 0, 100, mPaint);
}
}
这里简单讲解一下新增的构造函数的作用,在新的构造函数中为View的构造函数传递了AttributeSet attrs,int defStyle两个参数,这代表着该View可以通过XML 来创建并且接受Style来设定样式。等到相关博文时会再具体讲解。
接下来,我们恢复Activity类里的onCreate方法让它看起来像这个样子:
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
和一开始没啥两样对吧。
最后我们需要去修改布局文件main 在文件里加入以下 xml标签:
<com.××××.customview.SayHello
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</com.××××.customview.SayHello>
(注意××××,代表SayHello类所在的包,这里需要的是全名)。
然后再次运行程序,你应该看到以下结果:
是不是和我们平常定义View时很像了?
你感觉得还不够,还缺乏些什么?
好吧,你很聪明,我们的Text应该是在XML上通过某个属性配置而成的,而不是写在代码里!
为了将SayHello的属性暴露到XMl上首先我们需要在res/value 文件夹下新建一个XMl文件,命名为:atts。
在里面添加如下代码:
<?xml version="1.0"
encoding="utf-8"?>
<resources>
<declare-styleable
name="SayHello">
<attr name="content"
format="string"></attr>
<attr name="text_color"
format="color"></attr>
</declare-styleable>
</resources>
需要注意的是这里是没有智能提示的
然后我们需要修改SayHello类,还记得那个AttributeSet吗?我们将通过它来获取XML配置上的属性值。修改后的SayHello类代码是这样的:
private int mColor;
private String
mContent;
public SayHello(Context context, AttributeSet
attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray
typeArray =
context.obtainStyledAttributes(attrs,
R.styleable.SayHello);
mColor=typeArray.getColor(R.styleable.SayHello_text_color,
0XFF00FF00);
mContent=typeArray.getString(R.styleable.SayHello_content);
}
@Override
protected void onDraw(Canvas
canvas) {
super.onDraw(canvas);
Paint mPaint = new
Paint();
mPaint.setTextSize(22f);
mPaint.setColor(mColor);
canvas.drawText(mContent,
0, 100, mPaint);
}
现在可以去XML上为哥哥属性添加值了,不过先别着急我们的得将命名空间告诉它。
在布局文件的根源是上(通常是Layout)添加: xmlns:SayHello="http://schemas.android.com/apk/res/com.XXXX.customview"
SayHello 可以为您任意想要定义的名字,它将作为属性的前缀使用就像android:Layout 一样而我们的为:SayHello:content,后半段http://schemas.android.com/apk/res/ 为固定值,紧接着的是你整个APP的包命名,你不知道自己包名称?赶去去 AndroidManifest.xml文件中看看吧(注意该包名需要保持和manifest中的 package 保持一致,否则会提示无法找到XML属性)。
最后我们终于可以在XML上定义自己想要的字体颜色的内容了:
<com.XXXX.customview.SayHello
android:layout_width="fill_parent"
android:layout_height="wrap_content"
SayHello:text_color="#1212f0"
SayHello:content="this is a xml attr
view">
</com.XXXX.customview.SayHello>
运行程序您应该会看到以下结果:
这就是我们View 一般的定义方式和过程。
——启航。
//本笔记从 麦库中复制过来, 图片连不上,请见谅