在Android中,所有的UI界面都是由View类和ViewGroup类及其子类组合而成,其中View类是所有UI组件的基类,而ViewGroup是容纳这些UI组件的容器,其本身也是View类的子类。在ViewGroup中,除了可以包含普通的View外,还可以再次包含ViewGroup。
虽然Android提供了许多继承了View类的UI组件,但有时还是不能满足开发者的需求,这时,我们就需要通过继承View类来开发自己的UI组件。
开发自定义的UI组件大致可以分为以下3个步骤:
1、 创建一个继承android.view.View类的View子类,并且重写构造方法。
2、 根据需要重写相应的方法。
3、 在项目的Activity中,创建并实例化自定义的View子类。
下面我们来看一个例子,该程序运行效果如下图所示:
上图中的这只dog就是我们自定义的UI组件,它不仅能显示一个dog的图片,还能响应触摸事件,根据触摸点的坐标动态改变显示位置。
主布局main.xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:id="@+id/mylayout"
>
</FrameLayout>
程序使用FrameLayout,指定了背景图片是@drawable/background。
下面我们创建自定义UI组件,将其代码放在单独的DogView.java文件中:
package com.liuhaoyu;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class DogView extends View {
public float bitmapX; // 保存dog显示的X坐标
public float bitmapY; // 保存dog显示的Y坐标
public DogView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint(); // 创建并实例化Paint的对象
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),
R.drawable.dog); // 根据图片生成位图对象
canvas.drawBitmap(bitmap, bitmapX, bitmapY, paint); // 绘制
if (bitmap.isRecycled()) { // 判断图片是否回收
bitmap.recycle(); // 强制回收图片
}
}
}
这个自定义的UI组件是一只能显示在指定坐标上的dog。可以看到类DogView继承了 View类,重写了一个带参数Context的构造方法和onDrow()方法。这对应我们上面所讲的步骤的第1和第2步。
最后,对应第3步,我们来看主Activity,它定义在MainActivity.java文件中:
package com.liuhaoyu;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.mylayout);
final DogView dog = new DogView(MainActivity.this); // 创建自定义DogView类对象dog。
dog.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
dog.bitmapX = event.getX(); // 设置dog显示位置的X坐标
dog.bitmapY = event.getY(); // 设置dog显示位置的Y坐标
dog.invalidate(); // 重绘dog组件
return true;
}
});
frameLayout.addView(dog); // 将dog添加到布局管理器中
}
}
可以看到,我们new了一个自定义组件DogView类的对象dog放在主布局控制中,并让该对象监听触摸事件,根据触摸点的坐标,设置dog对象的显示位置。