自定义控件流程
加载:初始化数据(画笔paint颜色,样式;) 测量 布局 绘制
3个 构造方法
第1个一般用来new 控件 第2个用在布局文件中,系统解析xml文件吧属性 封装成集合,调用第2个构造(生命在xml中要包名+类名) 第3个可以加入样式 注意:前两个构造用this,不管用那个构造最后都走到第三个构造,这样就可以集中管理;否则,写在第一个里的方法(初始化用,避免要写三个同样的方法 ),直接写在xml中有系统创建是不会调用。而集中管理则会统一调用第三个。
public class CanvasTestView extends View {
public CanvasTestView ( Context context) {
this ( context, null) ;
}
public CanvasTestView ( Context context, @Nullable AttributeSet attrs) {
this ( context, attrs, 0 ) ;
}
public CanvasTestView ( Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super ( context, attrs, defStyleAttr) ;
init ( ) ;
}
}
绘制
onDraw() 用canvas画 画直线lineTo 画曲线,弧线, 平移,缩放,旋转 save ,restore 文字 invalidate();重走ondraw
生命周期方法
onSizeChanged :这个方法是在onMeasure方法执行后执行,最终的测量结果已经产生;可以用来获得屏幕的宽高 然后计算要绘制的图像的位置
监听方法
onTouchEvent参数:触摸事件,return true 表示自己处理不分发了
自定义viewGroup(可以放子视图)
onLayout 可以先向group里addview,然后拿到孩子视图进行layout摆放
自定义view的制作
全部都可以画出来的,就是单个的view,不用measure和layout,步骤:
自己初始好paint ,path 计算好位置 用canvas 画 用onTouchEvent 来确定 事件并处理
event.getAction()获取行为MotionEvent.ACTION_DOWN,ACTION_MOVE,ACTION_UP 用event.getX(), event.getY()获取位置
与getRawY的区别是前者是距离控件,后者是距离屏幕(包含状态栏,就是整个手机,但是view操作的view里的坐标,所以获取了距离之后还要减掉状态栏的高度)
private int getStatusBarHeight ( View view) {
Rect rect = new Rect ( ) ;
view. getWindowVisibleDisplayFrame ( rect) ;
return rect. top;
}
这里对比onClicklistener是针对单个控件的操作,想对控件内部的细节操作用onTouchEvent 处理;而且onTouchEvent 是在view的内部处理,onClicklistener要有使用view的组件来设定
位置摆放规则的viewgroup可以直接在xml中定义好各个子view的布局然后继承现成的viewgroup,如:LinearLayout,步骤:
定义自定义viewGroup的视图(由于是规则的,所以可以写死在xml中) 完成自定义viewGroup的监听事件,如popwindow的弹出;并完成popwindow的视图 需要的数据有使用这个控件的,如activity 在onCreate方法里为控件设置,要知道activity的onResume方法完毕,才会对activity里的view进行measure和layout
针对位置摆放不规则的viewGroup,继承原生的viewgroup,里面的子view要手动处理
定义好子控件的xml 使用控件的,如:activity,把需要的数据,图片资源为控件设置好。 onMeasure()方法:遍历每个孩子,用getchildcount和getchildat,对孩子measure测量测量传的是尺寸的描述heightMeasureSpec
在VIewGroup中系统默认只处理当前控件,不对子视图测量,要自己重写这个方法,步骤 onLayout()方法:遍历每个孩子,用getchildcount和getchildat,通过测量大小getMeasuredWidth,对孩子layout摆放
onMeasure方法学习(默认的super.onMeasure完成不了需要,1.只测了自己不测孩子,2.测量自己不能达到需求,有时超过了屏幕的限制)
MeasureSpec测量描述值 measure(MeasureSpec)对控件测量,最终调用setMeasuredDimension setMeasuredDimension设置最终的测量宽高,一定要走
针对自己的测量分为:未指定,精确
精确(matchparent):如果用户设定的值超大就会显示宽高不协调,所以要自己确定 获取屏幕宽高最小值
private int getDefaultWidth ( ) {
DisplayMetrics outMetrics = getResources ( ) . getDisplayMetrics ( ) ;
int width = outMetrics. widthPixels;
int height = outMetrics. heightPixels;
int result = Math. min ( width, height) ;
return result;
}
未指定(wrapcontent):当布局里没有孩子,或者孩子是动态添加返回值就是0,这样图像就不能显示 getSuggestedMinimumWidth
protected int getSuggestedMinimumWidth ( ) {
return ( mBackground == null) ? mMinWidth : max ( mMinWidth, mBackground. getMinimumWidth ( ) ) ;
}
后面子view的大小要更加父view的测量尺寸,同步改变
自定义组合控件
布局要善于利用include的思路,但是在include中不能设置属性 所以引出自定义组合控件,在控件中把视图填充,然后设置属性
注意inflate,第三参为
null:返回的view是本身,不带根部就参数,此时用addview加入根布局的话是不带根布局参数,要自己布局。 this:就是把view带着根布局参数填充到控件当中 要自定义要填充的view的类型,那么可以使用自定义属性。 示例
< resources>
< declare-styleable name = " SlidingMenu" >
< attr name = " touchModeBehind" >
< enum name = " margin" value = " 0" />
< enum name = " fullscreen" value = " 1" />
< enum name = " none" value = " 2" />
</ attr>
< attr name = " shadowDrawable" format = " reference" />
</ declare-styleable>
</ resources>
然后在自定义view里获取自定义属性值集合TypeArray存,用完要recycle回收 总结:自定义组合控件就是把控件封装到一个viewgroup里面,对子view的设置通过xml文件,和暴露给外面的方法灵活处理
有关值动画(ValueAnimator):当动画的执行不好直接处理,可以采用值动画,通过监听变化的值,不断地重绘图形。对应的是ObjectAnimator(要指定动画执行的object(view))
事件分发
四个方法:dispatchtouchevent,ontouchevent(想吃),onintercepttouchevent(特别想吃),requestdisallowintercepttouchevent(别抢) 事件是从外向内(先让大家都知道这个事),再从内向外传递,默认都不处理交给最外面的activity的ontouchevent处理
事件优先交个子视图 除非自己一定要处理这件事,否则不会拦截 所有的布局最外层都是Framelayout down事件确定目标target
onTouch onClick 是不同的 前者要按下移动;如果一个控件重写了onTouchEvent 返回True,且设置onTouch监听返回True,事件交给监听处理,监听优先级高。
WindowManager:这个类可以在任何的界面情况下添加一个额外的视图
manager = ( WindowManager) context. getSystemService ( Context. WINDOW_SERVICE) ;
gooView = new GooView ( context) ;
gooView. setOnGooViewChangeListener ( this ) ;
params = new WindowManager. LayoutParams ( ) ;
params. height = WindowManager. LayoutParams. WRAP_CONTENT
params. width = WindowManager. LayoutParams. WRAP_CONTENT
params. format = PixelFormat. TRANSLUCENT;
manager. addView ( gooView, params) ;