- 自定义view方法执行顺序
- 03-18 11:32:30.198 14844-14844/? I/tag: ---- public CoustomView(Context context, AttributeSet attrs) ----
- 03-18 11:32:30.198 14844-14844/? I/tag: ---- onFinishInflate() ----
- 03-18 11:32:30.227 14844-14844/? I/tag: ---- onAttachedToWindow ----
- 03-18 11:32:30.228 14844-14844/? I/tag: ---- onMeasure ----
- 03-18 11:32:30.294 14844-14844/? I/tag: ---- onMeasure ----
- 03-18 11:32:30.295 14844-14844/? I/tag: ---- onSizeChanged = w = 1080 h = 135 oldW = 0 oldH = 0
- 03-18 11:32:30.295 14844-14844/? I/tag: ---- onLayout ----
- 03-18 11:32:30.310 14844-14844/? I/tag: ---- onMeasure ----
- 03-18 11:32:30.310 14844-14844/? I/tag: ---- onLayout ----
- 03-18 11:32:30.311 14844-14844/? I/tag: ---- onDraw ----
- 03-18 11:32:30.311 14844-14844/? I/tag: ---- dispatchDraw =
2. void onFinishInflate();
当系统解析XML中声明的View后回调此方法,调用顺序:内层View->外层View,如果是viewgroup,适合在这里获取子View。注意点
:
如果View没有在XML中声明而是直接在代码中构造的,则不会回调此方法
此时无法获取到View的宽高和位置
3. void onAttachedToWindow();
当view 被添加到window中回调,调用顺序:外层View->内层View。在XML中声明或在代码中构造,并调用addview(this view)
方法都会回调该方法。注意点
:
此时View仅仅被添加到View,而没有开始绘制所以同样获取不到宽高和位置
4. void onDetachedFromWindow();
看名字就知道是与void onAttachedToWindow();
对应的方法,在VIew从Window中移除时回调,如执行removeView()
方法。注意点
:
如果一个View从window中被移除了,那么其内层View(如果有)也会被一起移除,都会回调该方法,且会先回调内层View的onDetachedFromWindow()
方法。
5. void onWindowFocusChanged(boolean hasWindowFocus);
当View所在的Window获得或失去焦点时被回调此方法。除了常见的设置view的onGlobalLayoutListener,也可以通过这个方法取到VIew的宽高和位置;也适合在判断当失去焦点时停止一些工作,如图片轮播,动画执行等,当获取到焦点后继续执行。hasWindowFocus
:View所在Window是否获取到焦点,当该Window获得焦点时,hasWindowFocus等于true,否则等于false。
6. boolean onTouchEvent(MotionEvent event);
当手指触摸View的时候回调该方法,前提是触摸事件没有被拦截或者被子View消费掉。该方法是事件分发流程中最后的消费者。event
:触摸事件对象,包含了该事件的所有信息,如触摸的类型(down、move、up),触摸位置等。返回值
:true:事件被消费了,false:没有被消费,事件传递到外层View,super方法:同false。
自定义View流程:
步骤 | 关键字 | 作用 |
---|---|---|
1 | 构造函数 | View初始化 |
2 | onMeasure | 测量View大小 |
3 | onLayout | 确定子View布局(自定义View包含子View时有用) |
4 | onDraw | 实际绘制内容 |
5 | onDraw | 实际绘制内容 |
About
总结自定义view的好文章 http://www.gcssloop.com/customview/CustomViewIndex/
自定义控件的生命周期
- onFinishInflate() 当View中所有的子控件均被映射成xml后触发
- onMeasure( int , int ) 确定所有子元素的大小
- onLayout( boolean , int , int , int , int ) 当View分配所有的子元素的大小和位置时触发
- onSizeChanged( int , int , int , int ) 当view的大小发生变化时触发,启动时间在onDraw之前
- onDraw(Canvas) view渲染内容的细节
- onKeyDown( int , KeyEvent) 有按键按下后触发
- onKeyUp( int , KeyEvent) 有按键按下后弹起时触发
- onTrackballEvent(MotionEvent) 轨迹球事件
- onTouchEvent(MotionEvent) 触屏事件
- onFocusChanged( boolean , int , Rect) 当View获取或失去焦点时触发
- onWindowFocusChanged( boolean ) 当窗口包含的view获取或失去焦点时触发
- onAttachedToWindow() 当view被附着到一个窗口时触发
- onDetachedFromWindow() 当view离开附着的窗口时触发,Android123提示该方法和 onAttachedToWindow() 是相反的
- onWindowVisibilityChanged( int ) 当窗口中包含的可见的view发生变化时触发
1,基准线居中的写法
mPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
float fontHeight = fontMetrics.bottom - fontMetrics.top;
float baseY = getHeight() - (getHeight() - fontHeight) / 2 - fontMetrics.bottom;
canvas.drawText(buttonText, getWidth() / 2, baseY, mPaint);
2,
android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
线程安全的,并且这些操作必须在UI线程中调用。
canvas.drawArc(RectFoval, float startAngle, float sweepAngle, boolean useCenter,Paint paint);
startAngle--开始角度最右边是0°,最下面是90°
sweepAngle--转过角度从0开始
3,【基本语法】public void drawRoundRect (RectF rect, float rx, float ry, Paint paint)
参数说明 画圆角矩形
rect:RectF对象。
rx:x方向上的圆角半径。
ry:y方向上的圆角半径。
paint:绘制时所使用的画笔。
4,在onDraw里面不调用invalidate(); 不然一直刷新
postInvalidateDelayed(200);//延迟刷新
5,控件设置长宽,位置Margins
LinearLayout.LayoutParamslinearParams = (LinearLayout.LayoutParams) iv_guide_up.getLayoutParams();// 取控件mGrid当前的布局参数
linearParams.height= heightNeedGuiInt;//当控件的高强制设成50象linearParams.setMargins(10,200, 30, 40);
iv_guide_up.setLayoutParams(linearParams);// 使设置好的布局参数应用到控件
或者view.getLayoutParams().height = 100;
view.requestLayout();
requestLayout和invalidate区别
view调用invalidate将导致当前view的重绘(draw调用),view的父类将不会执行draw方法;viewGroup调用invalidate会使viewGroup的子view调用draw,也就是viewGroup内部的子view进行重绘;
而requestLayout方法只会导致当前view的measure和layout,而draw不一定被执行,只有当view的位置发生改变才会执行draw方法,因此如果要使当前view重绘需要调用invalidate