本文共 3366 字,大约阅读时间需要 11 分钟。
昨夜雨疏风骤。浓睡不消残酒。试问卷帘人,却道“海棠依旧”。知否,知否?应是绿肥红瘦!
一首李清照的《如梦令·昨夜雨疏风骤》送给大家。
本篇博客只是一篇总结,自定义View往往和奇奇怪怪的需求相关。面对不断变化的需求,千万不能“死记硬背”,更重要的是要掌握自定义View的流程。
Android中每个控件都会在界面中占得一块矩形区域,这些控件大致被分为两类,即View控件和ViewGroup控件。ViewGroup控件可以包含多个View控件,并且能管理其包含的View控件。结构如下:
1. View的测量 Android系统给我们提供了MeasureSpec类来帮助我们测量View,Measure是一个32位的int值。高2位为测量的模式,低30位为测量的大小。测量的模式可以分为以下三种:
android:layout_width="100dp|match_parent"
android:layout_width="wrap_content"
控件的大小一般随着控件的子空间或内容的变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } private int measureWidth(int widthMeasureSpec) { int result = 0; int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; //单位px if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; }
2.在View中通常有以下一些比较重要的回调方法。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 回调该方法进行测量 } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // 确定显示位置 } @Override protected void onDraw(Canvas canvas) { // 画布 super.onDraw(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { // 触摸事件 return super.onTouchEvent(event); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // 组件大小改变时回调 super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onFinishInflate() { // 从XML加载组件后回调 super.onFinishInflate(); }
3. 三种方式实现自定义控件及一般步骤 1. 对已有控件进行拓展 ----> extends TextView ` @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 在回调父类方法前,实现自己的逻辑 super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 在回调父类方法后,实现自己的逻辑 }` 2. 通过组合控件来实现新的控件 ----> extends FrameLayout 1. new 元素 2. 设置属性(可以自定义属性) 3. 定义接口(若有需求) 3. 重写View实现全新控件 ----> extends View 1. onMeasure() 2. onLayout()(可选) 3. onDraw() 4. onTouchEvent()... 注:调用invalidate()方法进行重绘可实现动态效果。
1. 在res目录的values目录下创建一个attrs.xml文件。例如:
2. 获取自定义的属性
private void intView(AttributeSet attrs, Context context) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.topBar); String titleTxt = a.getString(R.styleable.topBar_titleTxt); float titleTxtSize = a.getDimension(R.styleable.topBar_titleTxtSize, 0); a.recycle(); }
3. 指定XML命名空间
xmlns:dyk="http://schemas.android.com/apk/res/com.example.testandroid"dyk:titleTxt="test"
自定义ViewGroup通常需要重写onMeasure()方法来对子View进行测量,重写onLayout()方法确定子View的位置,重写onToutchEvent()方法增加响应事件。 注:new对象时,调用一个参数的构造方法。未使用自定义属性时,调用两个参数的构造方法,使用自定义属性时调用三个参数的构造方法。