**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( ); //獲取完 要釋放
//動態添加控件--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);
public interface topbarClickListener{
void leftClick();
void rightClick();
}
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();
}
});
}
}