View、自定义View

来源:互联网 发布:喝咖啡的利弊 知乎 编辑:程序博客网 时间:2024/04/30 09:40

**view绘制**

1、控件架构

ViewGroup作为 父控件,可包含多个View控件,形成控件树

上层控件负责下层子控件的测量与绘制,并传递交互事件


2、View的测量---绘制前提

```onMeasure()-MeasureSpec类```

1)测量模式:EXACTLY(精确值)

AT_MOST (最大值)

UNSPECIFIED (不指定,在自定义view中使用)

自定义则必须重写onMeasure()方法

```~ ... onMeasure(~ ,~ ){ setMeasuredDimension( measureWidth(widthMS),measureHeight(~);}//参数是MeasureSpec的测量宽度、自定义的宽度方法~ ..int measureWidth(int measureSpec){int result=0; int specMode=MS.getMode(mS);int SpecSize=MS.getSize(mS);if(sM==MS.EXACTLY){result=specSize;} else{ result=200; //当不是EXACTLY模式,则需要给默认值if(specMode==MS.AT_MOST){result=Math.min(result,specSize);//若是AT_MOST模式,则要取出我的指定的大小与SpecSize中最小的}}return result; }


3、View的绘制

重写onDraw()方法,在Canvas对象上绘制所需对象(在其他地方通常需要创建Canvas canvas=new Canvas(bitmap) ; )

4、ViewGroup的测量

管理子View(显示大小)

**· 当VG为wrap_content,需要对子View遍历,获得所有子View大小,从而决定自己的大小**

**·在其他模式,则通过具体的指定值来设置自身的大小**

1)VG在测量时通过遍历所有子View,从而调用子View的Measure方法来获得每一个子View的测量结果

2)子View测量后,View的Layout方法设定其放置位置

3)VG执行layout过程时,遍历调用子View的Layout方法,指定其具体显示的位置,决定其布局位置(在自定义VG时,重写onLayout()方法控制子View显示位置,若需要支持wrap_content,必须重写onMeasure() )


5、VG绘制

指定VG背景颜色,必须调用onDraw()方法,调用dispatchDraw()绘制子View

6、自定义View

比较重要的回调方法(根据实际需要)

onFinishInflate( ):从XML加载组件后回调

onSizeChanged():组件大小改变时回调

onMeasure():回调该方法进行测量 onLayout():回调确定显示的位置

onTouchEvent():监听到触摸时间时回调

**实现自定义控件方法**

1)对现有控件拓展

2)通过组合实现新控件

3)重写View实现全新控件

*1、对现有控件进行拓展--可在onDraw()中实现*


//初始化画笔Paint mPaint=new Paint();mPaint.setColor(getResources().getColor(~ .blue));mPaint.setStyle(Paint.Style.FILL);~...onDraw( ){ //在回调法雷方法前,实现自己的逻辑,对TextView来说,就是在绘制文本内容前super.onDraw(); //在 ...后,则在 ... 后 }


2、复合控件--组合

(1)定义属性


//在res-values下创建attrs.xml的属性定义文件<resource>   <declare-styleablename="Topbar">      <attr name ="title" format="string" />      <attrname="leftBackground"format="color|reference"/>   </></>……


(2)创建控件继承VG`


//获取自定义属性TypedArray ta=context.obtainStyledAttributes(attrs,.styleable.Topbar);mLeftTextColor=ta.getColor(R.~~.Topbar_leftTextColor, 0);ta.recycle( ); //获取完 要释放


(3)组合控件(左-中-右)


//动态添加控件--addView ,添加到定义的Topbar中,设置属性值mLeftButton=new Button(context);mTitleView=new TextView(~);……mLeftButton.setTextColor(mLeftTextColor);……//为组件元素设置相应的布局元素mLeftParams=new LayoutParams(L~P~.WRAP_CONTENT,L~P~.M~P~);mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);//添加到VGaddView(mLeftButton ,mLeftParams);



利用回调机制设计按钮的点击事件
 <1>定义接口---UI模板类中创建方法
public interface topbarClickListener{void leftClick();void rightClick();}


<2>暴露接口给调用者---模板方法中,增加点击事件(调用接口点击方法)
mRightButton.setOnclickListener(new OnClickListener(){
~……
...onClick(){mListener.rightClick();}
}
public void setOnTopbarClickListener(topbarClickListener mListener){
this.mListener=mListener;
}
<3>实现接口回调——匿名内部类,主类调用
mTopbar.setOnTopbarClickListener(new ~……);

(4)引用UI模板
指定命名空间:xmlns:myspace="……/res-auto"
使用属性:myspace:leftBackground="……"
写到布局文件中,其他地方可用include引用:<com.xys.mytopbar.Topbar ……>





3、重写View实现全部控件

 继承View类,重写onDraw()/onMeasure()实现绘制,重写onTouchEvent()实现交互逻辑



7、自定义ViewGroup

重写onMeasure()对子View的测量,父onLayout()确定子位置,onTouchEvent()响应事件
eg:实现类似ScrollView功能

      (1)放置子View--利用遍历的方式对子View测量、设定位置

~onMeasure(){
~ int  count=getChildCount();
for(int i=0 ; i<count ; i++){
View childView=getChildAt(i);
measureChild(childView ,widthMeasureSpec,heightMeasureSpec);
}
}
//每个子View占一屏高度,则VG高度为子View个数乘以屏幕高度
   ~onLayout(){
~   int childCount=getChildCount();
     MarginLayoutParams mlp=()getLayoutParams();//设置VG高度
     mlp.height=mScreenHeight*childCount;
     setLayoutParams(mlp);
     for(int i=0; i<childCount; i++){
View child=getChildAt(i);
if(child.getVisibility()!=View.GONE)
child.layout(1,i*mScreenHeight,r,(i+1)*mScreenHeight);
     }
 }

(2)添加响应事件才能滑动(滑动到一段距离会跳一整页)

~onTouchEvent(){
int y=()event.getY();

}





 

0 0
原创粉丝点击