一、如何自定义控件
不同的需求,使用不同的方法自定义控件。
(1)在原生的控件的基本功能上进行扩展,这时只要extends并对控件进行扩展,通过重写它的整件,onDraw,但是始终保持父类方法的调用。
(2)要用几个控件的功能的和,可以将几个控件组合起来。
(3)完全自定义一个新的控件,也就是直接从View,ViewGroup开始绘制控件。
Android的UI界面都是从View和ViewGroup和其派生类组合而成了。其中View中所有UI的基类,ViewGroup是容纳这些组件的容器,本身也是从View派生过来的。
ViewGroup可以通过重写onMeasure,onLayout为加入其中的View进行布局和处理。下面我们先学习View类派生自定义组件。
二、android自定义View
方法:
extends View --->重写构造函数---->重写onDraw()等函数。
如果自定义的View要有自定义的属性,则要在values下建立attrs.xml。在其中定义属性,使用到的自定义的xml布局文件中要加入
xmlns:前缀="http://schemas.android.com/apk/res/自定义的View所在的包路径".
在使用自定义的属性时候,使用
前缀:属性名
如 myTextview:textColor=" "
- View类的方法
Creation | Constructors | There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file. |
| onFinishInflate() | Called after a view and all of its children has been inflated from XML. |
Layout | onMeasure(int, int) | Called to determine the size requirements for this view and all of its children. |
onLayout(boolean, int, int, int, int) | Called when this view should assign a size and position to all of its children. | |
onSizeChanged(int, int, int, int) | Called when the size of this view has changed. | |
Drawing | onDraw(android.graphics.Canvas) | Called when the view should render its content. |
Event processing | onKeyDown(int, KeyEvent) | Called when a new hardware key event occurs. |
onKeyUp(int, KeyEvent) | Called when a hardware key up event occurs. | |
onTrackballEvent(MotionEvent) | Called when a trackball motion event occurs. | |
onTouchEvent(MotionEvent) | Called when a touch screen motion event occurs. | |
Focus | onFocusChanged(boolean, int, android.graphics.Rect) | Called when the view gains or loses focus. |
onWindowFocusChanged(boolean) | Called when the window containing the view gains or loses focus. | |
Attaching | onAttachedToWindow() | Called when the view is attached to a window. |
onDetachedFromWindow() | Called when the view is detached from its window. | |
onWindowVisibilityChanged(int) | Called when the visibility of the window containing the view has changed. |
- 一般情况下,我们要重写下面的方法
1.构造器
至少用来得到Context.
2.onFinishInflate()
这是一个回调方法,当应用从xml布局文件加载组件并利用它来构建界面后,这个方法就会调用。
3.onMeasure(int ,int )
调用这个方法来检测 View组件及它所包含的所有子组件的大小、
4.onLayout(boolean ,int ,int ,int ,int )
当组件要分配其子组件的位置,大小时,这个方法就会被调用,View类中布局发生变化时会调用,这个方法是所有的View,ViewGroup及其派生类都具有的方法,重载这个方法,可以在布局发生改变时作定制处理,这在实现一些特效时很有用。
5.onSizeChanged(int,int ,int ,int)
当这个组件的大小改变时调用。
6.onDraw(Canvas)
当组件将要绘制它的内容时回调这个方法并进行绘制。这个方法是所有的View,ViewGroup及其派生类都具有的方法,也是android UI绘制最重要的方法。重载这个方法,并在重载的方法里基于canvas绘制自己的各种图形。
7.onKeyDown(in ,KeyEvent)/onKeyUp(int ,KeyEvent)
按下和松开一个按键时触发。
8.onTouchEvent(MotionEvent)
当发生触摸屏事件时触发。
9.onWindowFocusChanged(boolean)
包含组件的窗口得到或者失去焦点时触发的方法。
10.onFocusChanged(boolean,int ,Rect)
组件得到或者失去焦点时触发的方法。
11.onWindowVisibilityChanged(int )
当包含这个组件的窗口可见性发生变化时触发。
- 补充两个ViewGroup常常重写的方法
1.protected void dispatchDraw(Canvas canvas)
ViewGroup类及其派生类具有的方法,用于控制子View绘制的分发,重载这个类可以改变子View的绘制,从而实现一些复杂的效果。
2.protected boolean drawChild(Canvas canvas, View child,long drawingTime)
ViewGroup及其派生的类具有的方法,可以直接绘制具体的子 View,重载这个类可以控制某个具体的子View.
三、示例
我们做一个ball,让其跟随手指运行,在程序中,先得到MotionEvent的位置,再在这个位置重绘就可以了。
代码如下
package chuiyuan.lsj.androidjava.utils;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by lsj on 2015/9/26.
*/
public class BallView extends View{
private float x = 40;
private float y =50;
private float r =15 ;
public BallView(Context context, AttributeSet attr){
super(context, attr);
}
@Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
//创建画笔
Paint paint= new Paint();
//设置画笔颜色
paint.setColor(Color.RED);
//画circle
canvas.drawCircle(x, y, r, paint);
}
//注释时使用的 是CustumViewActivity中的监听
@Override
public boolean onTouchEvent(MotionEvent event) {
setX(event.getX());
setY(event.getY());
invalidate(); //刷新
return true; //一定要返回true,说明成功了
}
@Override
public float getX() {
return x;
}
@Override
public void setX(float x) {
this.x = x;
}
@Override
public float getY() {
return y;
}
@Override
public void setY(float y) {
this.y = y;
}
public float getR() {
return r;
}
public void setR(float r) {
this.r = r;
}
}
在测试类中
package chuiyuan.lsj.androidjava.view;
import android.view.MotionEvent;
import android.view.View;
import chuiyuan.lsj.androidjava.R;
import chuiyuan.lsj.androidjava.base.BaseActivity;
import chuiyuan.lsj.androidjava.utils.BallView;
/**
* Created by lsj on 2015/9/26.
*/
public class CustumViewActivity extends BaseActivity{
BallView ballView ;
@Override
protected void findView() {
setContentView(R.layout.activity_cumstomview);
}
@Override
protected void initView() {
ballView = (BallView)findViewById(R.id.ballview);
//下面的换成了BallView中的onTouchEvent
ballView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//得到坐标并设置小球
ballView.setX(event.getX());
ballView.setY(event.getY());
//通知ball重绘,会调用onDraw(),一定要在UI线程中
ballView.invalidate();
//表示执行成功
return true;
}
});
}
@Override
protected void setOnClickListener() {
}
@Override
public void onClick(View v) {
}
}
我们可以看到,为了实现跟随的效果,我们还要实现对它的监听,实际上正如注释中那样,可以通过经常要重载的方法来实现 :onTouchEvent方法。