View、自定义View

**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);
//添加到VG
	addView(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 ……>


public class Topbar extends RelativeLayout {

    //设置自定义控件的父类布局的参数
    private LayoutParams titleParams_lp;
    private LayoutParams leftParams_lp;
    private LayoutParams rightParams_lp;

    //自定义的属性
    private String title_txt;
    private int title_color;
    private float titleTextSize;

    private String left_txt;
    private int leftText_color;
    private Drawable leftBackground;

    private String right_txt;
    private int rightText_color;
    private Drawable rightBackground;
    //自定义的控件
    private Button left_btn,right_btn;  //左右按钮
    private TextView title_tv;  //标题

    private topbarClickListener listener;   //自定义的接口实例对象
    //自定义接口
    public interface topbarClickListener{
        public void leftClick();
        public void rightClick();   //抽象点击方法
    }
    //自定义的点击方法---将回调回来的匿名内部类参数给系统的ClickListener()
    public void setOnTopbarClickListener(topbarClickListener listener){//传来一个参数--接口的对象
        this.listener=listener;
    }

    public Topbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.Topbar);
                //将自定义的属性从
    
    
     
     中获取出来
        title_txt=ta.getString(R.styleable.Topbar_title);
        title_color=ta.getColor(R.styleable.Topbar_titleColor,0);
        titleTextSize=ta.getDimension(R.styleable.Topbar_titleTextSize,0);

        left_txt=ta.getString(R.styleable.Topbar_leftText);
        leftText_color=ta.getColor(R.styleable.Topbar_leftTextColor,0);
        leftBackground=ta.getDrawable(R.styleable.Topbar_leftBackground);

        right_txt=ta.getString(R.styleable.Topbar_rightText);
        rightText_color=ta.getColor(R.styleable.Topbar_rightTextColor,0);
        rightBackground=ta.getDrawable(R.styleable.Topbar_rightBackground);

        ta.recycle();   //回收
//实例化控件
        title_tv=new TextView(context);
        left_btn=new Button(context);
        right_btn=new Button(context);

 //将控件与自定义的属性关联
        title_tv.setText(title_txt);
        title_tv.setTextColor(title_color);
        title_tv.setTextSize(titleTextSize);
        title_tv.setGravity(Gravity.CENTER);    //直接设定居中对齐

        left_btn.setText(left_txt);
        left_btn.setTextColor(leftText_color);
        left_btn.setBackground(leftBackground);


        right_btn.setText(right_txt);
        right_btn.setTextColor(rightText_color);
        right_btn.setBackground(rightBackground);

        setBackgroundResource(R.color.colorWhite);
    /**自定义控件的父类布局参数*/
        titleParams_lp=new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);   //布局宽 高、 对齐方式
        titleParams_lp.addRule(RelativeLayout.CENTER_IN_PARENT);
            //左边布局自适应,居左对齐
        leftParams_lp=new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        leftParams_lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);

        rightParams_lp=new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        rightParams_lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    /**将自定义的控件放进父布局中---也就是设定它们的布局位置  */
        addView(title_tv,titleParams_lp);
        addView(left_btn,leftParams_lp);
        addView(right_btn,rightParams_lp);
/**自定义的点击事件------利用回调机制----------------*/
        left_btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                listener.leftClick();
                //此时将传回来的点击事件(通过 匿名内部类参数)传递给left_btn的监听接口
            }
        });
        right_btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                listener.rightClick();
            }
        });
    }
}

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Topbar topbar= (Topbar) findViewById(R.id.tb_title);
        topbar.setOnTopbarClickListener(new Topbar.topbarClickListener() {
            @Override
            public void leftClick() {
                Toast.makeText(MainActivity.this,"我是back",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void rightClick() {
                Toast.makeText(MainActivity.this,"我是go",Toast.LENGTH_SHORT).show();
            }
        });
    }
}
     
     
    
      
      
        
       
       
        
       
       
        
       
       

        
       
       
        
       
       
        
       
       

        
       
       
        
       
       
        
       
       

    
      
      


     
     
     
     
    
    
      
      
    
    
      
      

    
      
      

     
     
    
    



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
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芒果-橙

谢谢啦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值