Android自定义控件
安卓在使用中大多数使用已有的一些控件,用法比较简单,还有一部分是比较复杂的、用户自己想的控件,这些就需要进行自定义控件,今天就来简单说一下自定义控件。
1、绘制过程
- 创建一个类,继承View类
- onMeasure()方法,测量计算视图的大小
- onLayout()方法,设置视图在屏幕中显示的位置
- onDraw()方法,绘制视图
以上就是自定义控件的绘制过程。
2、主要内容解释
- measure操作
用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:
(1)onMeasure(),确定视图大小,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
(2)关于MeasureSpec:
UPSPECIFIED:父容器对于子容器没有任何限制,子容器想要多大就多大.
EXACTLY:父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间.
AT_MOST:子容器可以是声明大小内的任意大小.
- layout操作
用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:
(1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;
(2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;
- draw操作
利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。其内部定义了绘图的基本操作:
(1)绘制背景;
(2)如果要视图显示渐变框,这里会做一些前期工作;
(3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示。
(4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;
(5)应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge,如果需要可以开始绘制渐变框;
(6)绘制滚动条;
从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。
- 自定义View的方法
- onFinishInflate(): 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
- onMeasure():检测View组件及其子组件的大小
- onLayout(): 当该组件需要分配其子组件的位置、大小时
- onSizeChange():当该组件的大小被改变时
- onDraw(): 当组件将要绘制它的内容时
- onKeyDown: 当按下某个键盘时
- onKeyUp: 当松开某个键盘时
- onTrackballEvent: 当发生轨迹球事件时
- onTouchEvent: 当发生触屏事件时
- onWindowFocusChanged(boolean):当该组件得到、失去焦点时
- onAtrrachedToWindow():当把该组件放入到某个窗口时
- onDetachedFromWindow():当把该组件从某个窗口上分离时触发的方法
- onWindowVisibilityChanged(int):当包含该组件的窗口的可见性发生改变时触发的方法
3、效果图展示
4、代码展示
在java代码中我加了很多注释,方便进行理解、学习。
布局文件
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:id="@+id/container" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical"> 6 7 <sample.sdk.qy.com.androiddemo.Customize 8 android:layout_width="match_parent" 9 android:layout_height="match_parent" 10 android:layout_margin="20dp" 11 /> 12 13 </LinearLayout>
自定义控件类
1 public class Customize extends View { 2 private final static String TAG = Customize.class.getSimpleName(); 3 private Paint mPaint; 4 private RectF oval; 5 6 public Customize(Context context) { 7 super(context); 8 init(); 9 } 10 11 public Customize(Context context, AttributeSet attrs) { 12 super(context, attrs); 13 init(); 14 } 15 16 public Customize(Context context, AttributeSet attrs, int defStyleAttr) { 17 super(context, attrs, defStyleAttr); 18 init(); 19 } 20 21 private void init(){ 22 mPaint = new Paint(); 23 mPaint.setAntiAlias(true); 24 oval=new RectF(); 25 } 26 @Override 27 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 29 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 30 int widthSize = MeasureSpec.getSize(widthMeasureSpec); 31 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 32 int heightSize = MeasureSpec.getSize(heightMeasureSpec); 33 switch (widthMode) { 34 case MeasureSpec.EXACTLY: 35 break; 36 case MeasureSpec.AT_MOST: 37 break; 38 case MeasureSpec.UNSPECIFIED: 39 break; 40 } 41 } 42 43 @Override 44 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 45 super.onLayout(changed, left, top, right, bottom); 46 47 } 48 49 @Override 50 protected void onDraw(Canvas canvas) { 51 super.onDraw(canvas); 52 //设置演颜色 53 mPaint.setColor(Color.GREEN); 54 // FILL填充, STROKE描边,FILL_AND_STROKE填充和描边 55 mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 56 //获取控件的宽度和高度 57 int with = getWidth(); 58 int height = getHeight(); 59 //设置圆的半径 60 float radius = with / 4; 61 //画圆,设置颜色 62 canvas.drawCircle(with / 2, with / 2, radius, mPaint); 63 mPaint.setColor(Color.BLUE); 64 //用于定义的圆弧的形状和大小的界限 65 oval.set(with / 2 - radius, with / 2 - radius, with / 2 66 + radius, with / 2 + radius); 67 //根据进度画圆弧 68 canvas.drawArc(oval, 270, 90, true, mPaint); 69 //画出另一个圆弧 70 mPaint.setColor(Color.YELLOW); 71 canvas.drawArc(oval, 360, 120, true, mPaint); 72 } 73 }
MainActivity类
1 public class MainActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 8 } 9 10 }