[转载]android之自定义view 一 – g.hui – 博客园.
概述
当Android系统提供的UI组件不足以满足我们的需求时,我们可以自己继承View来设计自己的View。然后,选择重写部分的方法。通常可以被重写的方法如下:
1)构造函数,View有三个构造函数:
public View (Context context) 当我们通过代码创建view时需要复写此方法。
public View (Context context, AttributeSet attrs) 当我们通过xml创建view时需要复写此方法。
public View (Context context, AttributeSet attrs, int defStyle) 通过源码我们可以知道其实public View (Context context, AttributeSet attrs) 调用的也是三个参数的构造函数public View (Context context, AttributeSet attrs, int defStyle)。我们一般不需要复写此构造函数。
2)回调函数
onFinishInflate():当应用从XML布局文件加载该组件并用它构建完界面之后,该方法就会被回调。
onMeasure(int,int):用来检测View及它所包含的子View的大小
onLayout(boolean,int,int,int):当此View需要分配其子组件的位置、大小时会被回调。
onSizeChanged(int,int,int,int):当该组件大小被改变时回调
onDraw(Canvas):当该组件将要绘制时被回调
onKeyDown(int,KeyEvent):当此View被按下时被回调
onKeyUp(int,KeyEvent):当此View被松开时被回调
onTrackballEvent(MotionEvent):当发生轨迹球事件时
onTouchEvent(MotionEvent):当发生触摸事件时
onWindowFocusChanged(boolean):当焦点发生改变时
onAttachedToWindow():当此组件被添加到某个窗口时
onDetachedFromWindow():当从某个窗口上被分离时
onWindowVisibilityChanged(int):当包含该组件的窗口的可见性发生改变时触发
步骤
1)继承View(当然也可以选择它的某些子类,根据自己的实际需求选择)
2)重写两个构造函数:上面说过View有三个构造函数,我们只需要复写前两个即可。
注意:其实,不是我们一定要复写那两个构造函数,如果我们只通过代码的方式添加我们自定义的View的话可以只复写单参的构造函数。若我们只通 过XML布局的方式往Activity中添加我们自定义的View时,可以只复写双参的构造函数。但为了防止出错,建议把单参的、双参的都复写了。
3)选择复写部分回调函数,我们根据自己的需求选择复写一些回调函数。一般都 会onDraw(Canvas)方法。
4)当我们完成了上面的步骤后,我们就完成了自定义View。我们可以通过两种方式将它添加到我们的Activity中
a.通过代码方式
b.通过XML方式
具体请看下面的例子代码:
实例
模拟一个跟随手机移动的小球。
package com.example.customview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; public class CustomView1 extends View { public float currentX = 46; public float currentY = 57; Paint p; private void init() { p = new Paint(); p.setColor(Color.GREEN); } public CustomView1(Context context) { super(context); System.out.println("---------1-----------"); init(); } public CustomView1(Context context, AttributeSet attrs) { super(context, attrs); System.out.println("---------2-----------"); init(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(currentX, currentY, 20, p); } }
1)通过代码引入CustomView
package com.example.customview; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.RelativeLayout; import android.app.Activity; public class CustomViewActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_view); final CustomView1 cs = new CustomView1(this); RelativeLayout Rlayout = (RelativeLayout) findViewById(R.id.RLayout); Rlayout.addView(cs); cs.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { cs.currentX = event.getX(); cs.currentY = event.getY(); cs.invalidate(); return true; } }); } }
此时我们的xml布局文件如下:
<!-- <com.example.customview.CustomView1 android:id="@+id/cs" android:layout_width="fill_parent" android:layout_height="fill_parent" /> -->
2)通过XML引入CustomView
package com.example.customview; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.app.Activity; public class CustomViewActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_view); final CustomView1 cs = (CustomView1) findViewById(R.id.cs); cs.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { cs.currentX = event.getX(); cs.currentY = event.getY(); cs.invalidate(); return true; } }); } }
此时我们的xml布局文件如下:
大家可以注意一下Logcat的输出,对比一下,当我们选择这两种不同的引入自定义View方式时构造函数的调用情况。
PS:我们知道View的子类有许多独特的属性,比如TextView的text属性,color属性等。那么我们能不能给我们自定义的View也添加一些自定义的属性呢?答案当然是可以的,我们放到下一讲中来说。