本文實例為大家分享了Android復(fù)合控件實現(xiàn)通用標(biāo)題欄的具體代碼,供大家參考,具體內(nèi)容如下
創(chuàng)新互聯(lián)建站主要從事成都網(wǎng)站設(shè)計、做網(wǎng)站、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)鳳山,十年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
效果圖
估計大家應(yīng)該和我一樣,每次去看別人博客的時候,都喜歡一拉到底,先看看有沒有效果圖,符不符合自己的需求,符合咱就繼續(xù)看,不符合免得浪費表情,所以效果圖先上為敬
寫在前面的一點兒廢話
作為Android的菜鳥一枚,一直覺得能夠?qū)懽远x控件是一個很炫酷的技能,最近看了徐宜生老師的群英傳之后,感覺收獲還是挺多的。這篇文章就主要記錄的是學(xué)習(xí)自定義控件中最簡單的復(fù)合控件的過程。雖然現(xiàn)在MD中Toolbar已經(jīng)完全滿足各種各樣的需求,但對于我這種菜鳥來說自己動手寫一個還是能學(xué)到很多東西的!
1、自定義控件的屬性
既然是自定義的控件,肯定得提供屬性選項,以方便實現(xiàn)不同的樣式。提供自定義的屬性是很簡單的,在res資源目錄下的values目錄下創(chuàng)建一個attrs.xml的屬性集定義的xml文件,在該文件中自定義各種必要的屬性
<?xml version="1.0" encoding="utf-8"?>
既然自定義了屬性,就需要在自定義控件模板中去獲取這些屬性的賦值,以處理得到相應(yīng)的顯示效果。在這里,系統(tǒng)提供了TypeArray類,獲取到該類的實例后就可通過getString()等方法獲得布局文件中設(shè)置的屬性值
private void getTypeArray(Context context, AttributeSet attrs) { //將attrs.xml中定義的屬性存儲到TypeArray中 TypedArray typeArray=context.obtainStyledAttributes(attrs,R.styleable.NormalTopBar); leftText=typeArray.getString(R.styleable.NormalTopBar_leftText); leftTextColor=typeArray.getColor(R.styleable.NormalTopBar_leftTextColor, Color.BLACK); leftTextSize=typeArray.getDimension(R.styleable.NormalTopBar_leftTextSize,12); leftImageId=typeArray.getResourceId(R.styleable.NormalTopBar_leftImageSrc,0); titleText=typeArray.getString(R.styleable.NormalTopBar_titleText); titleTextColor=typeArray.getColor(R.styleable.NormalTopBar_titleTextColor,Color.BLACK); titleTextSize=typeArray.getDimension(R.styleable.NormalTopBar_titleTextSize,20); rightText=typeArray.getString(R.styleable.NormalTopBar_rightText); rightTextColor=typeArray.getColor(R.styleable.NormalTopBar_rightTextColor,Color.BLACK); rightTextSize=typeArray.getDimension(R.styleable.NormalTopBar_rightTextSize,12); rightImageId=typeArray.getResourceId(R.styleable.NormalTopBar_rightImageSrc,0); typeArray.recycle();//獲取完所有屬性后需要調(diào)用recycle來避免重新創(chuàng)建發(fā)生的錯誤 }
參數(shù)中attrs是控件構(gòu)造函數(shù)中傳入的屬性集參數(shù),而R.styleable.NormalTopBar就是在attrs.xml文件中定義的該控件屬性集的名字。
2、動態(tài)添加控件組合成自定義符合控件
標(biāo)題欄中一般包括了左邊的按鈕,中間的標(biāo)題,右邊的按鈕。在本文中,我把該控件分成了5個部分,左邊有一個ImageView和一個TextView用于用戶點擊,中間有一個TextView用于顯示標(biāo)題,右邊和左邊一樣,成對稱分布,然后這些控件的父控件是RelativeLayout,方便子控件的布局。了解了有哪些控件之后,就可以初始化這些控件對象,然后分別指定合適的布局,動態(tài)添加布局中。
private void addAllView(Context context) { leftTextView =new TextView(context); rightTextView =new TextView(context); titleTextView=new TextView(context); leftImage=new ImageView(context); rightImage=new ImageView(context); leftImage.setId(R.id.leftimageid); leftImage.setImageResource(leftImageId); //leftImage.setAdjustViewBounds(true); leftTextView.setText(leftText); leftTextView.setTextSize(leftTextSize); leftTextView.setTextColor(leftTextColor); titleTextView.setText(titleText); titleTextView.setTextSize(titleTextSize); titleTextView.setTextColor(titleTextColor); titleTextView.setGravity(Gravity.CENTER);//一定要設(shè)置textview內(nèi)容的位置 rightTextView.setText(rightText); rightTextView.setTextSize(rightTextSize); rightTextView.setTextColor(rightTextColor); rightImage.setId(R.id.rightimageid); rightImage.setImageResource(rightImageId); //為組建設(shè)置相應(yīng)的布局 if(leftImageId!=0&&leftText!=null){ leftImageParams=new LayoutParams(dpToPx(context,35), dpToPx(context,35)); leftImageParams.addRule(ALIGN_PARENT_LEFT,TRUE); leftImageParams.addRule(CENTER_VERTICAL,TRUE); addView(leftImage,leftImageParams); leftTextParams =new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); leftTextParams.addRule(RelativeLayout.RIGHT_OF,R.id.leftimageid); leftTextParams.addRule(CENTER_VERTICAL,TRUE); leftTextView.setGravity(Gravity.LEFT); addView(leftTextView, leftTextParams); }else if(leftImageId!=0&&leftText==null){ leftImageParams=new LayoutParams(dpToPx(context,35), dpToPx(context,35)); leftImageParams.addRule(ALIGN_PARENT_LEFT,TRUE); leftImageParams.addRule(CENTER_VERTICAL,TRUE); addView(leftImage,leftImageParams); }else{ leftTextParams =new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); leftTextParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE); leftTextParams.addRule(CENTER_VERTICAL,TRUE); addView(leftTextView, leftTextParams); } titleParams=new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); titleParams.addRule(CENTER_IN_PARENT,TRUE); titleParams.addRule(TEXT_ALIGNMENT_CENTER); addView(titleTextView,titleParams); if(rightImageId!=0&&rightText!=null){ rightTextParams =new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); rightTextParams.addRule(RelativeLayout.LEFT_OF,R.id.rightimageid); rightTextParams.addRule(RelativeLayout.CENTER_VERTICAL,TRUE); rightTextView.setGravity(Gravity.RIGHT); addView(rightTextView, rightTextParams); rightImageParams=new LayoutParams(dpToPx(context,35), dpToPx(context,35)); rightImageParams.addRule(CENTER_VERTICAL,TRUE); rightImageParams.addRule(ALIGN_PARENT_RIGHT,TRUE); addView(rightImage,rightImageParams); }else if(rightImageId!=0&&rightText==null){ rightImageParams=new LayoutParams(dpToPx(context,35), dpToPx(context,35)); rightImageParams.addRule(CENTER_VERTICAL,TRUE); rightImageParams.addRule(ALIGN_PARENT_RIGHT,TRUE); addView(rightImage,rightImageParams); }else{ rightTextParams =new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); rightTextParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE); rightTextParams.addRule(RelativeLayout.CENTER_VERTICAL,TRUE); addView(rightTextView, rightTextParams); } }
這一段代碼首先是初始化得到各子控件的實例對象,然后將屬性值賦值給對應(yīng)的控件,接著利用LayoutParams類對各子空間的大小和位置進(jìn)行設(shè)定,最后利用addView方法即可將這些子控件添加到控件整體布局中。
這段代碼中,主要的難點在于運用LayoutParams,要注意該布局的外層viewGroup是RelativeLayout,所以在定義和初始化的時候都需要使用RelativeLayout.LayoutParams.另外LayoutParams的構(gòu)造函數(shù)中的參數(shù)用于控制大小,我在設(shè)置ImageView對應(yīng)的LayoutParams時,最開始把寬和高都設(shè)置為WRAP_CONTENT,但是運行后效果不理想,imageview寬度占據(jù)了一半的空間,最后決定對該控件的大小指定尺寸大小,不過要注意構(gòu)造函數(shù)中的數(shù)值單位是px,所以需要先定義一個函數(shù)將dp轉(zhuǎn)為px再賦值給構(gòu)造函數(shù)。
這段代碼的另外一個難點是,當(dāng)我兩側(cè)的按鈕同時有文字和圖標(biāo)時,對于ImageView和TextView的定位是個問題。在下面代碼中
leftTextParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
這行代碼將TextView定位在了父控件的左側(cè),而當(dāng)左側(cè)同時有ImageView和TextView時二者肯定就會重疊,這肯定不是想要的結(jié)果。所以需要把ImageView仍定位在最左邊,然后TextView定位在前者的右邊,而在方法addRule()中,可以使用 addRule(RelativeLayout.RIGHT_OF,int view) 來把對應(yīng)的控件定位在參數(shù)中view控件的右邊,但是該參數(shù)需要的是資源ID,可問題是在上面我們是動態(tài)添加的ImageView,并沒有在xml文件中定義id。我嘗試了直接用imageview.getId(),但得到的結(jié)果經(jīng)調(diào)試發(fā)現(xiàn)是-1,并不能實現(xiàn)想要的效果,最后一搜找到了一個方法,首先在資源目錄res下的values下再新建一個ids.xml的文件,然后在文件中定義一個類型為id的item
<?xml version="1.0" encoding="utf-8"?>
然后利用ImageView.setId(R.id.leftimageid) 就能給動態(tài)添加的控件賦值一個不會與其他資源id重復(fù)的id,接著就可以在布局中使用。
3、定義接口暴露給調(diào)用者
到目前位置,編寫的自定義控件已經(jīng)可以在xml布局文件中使用,而且也能在界面上顯示出來,但是左右兩側(cè)的按鈕點擊事件對于不同的使用者或者不同的頁面,所要完成的動作肯定是不一樣的,所以得暴露一個接口給調(diào)用者自己去實現(xiàn)。
public interface normalTopClickListener{ void onLeftClick(View view); void onRightClick(View view); }
然后給調(diào)用者提供一個set函數(shù)讓調(diào)用者來實現(xiàn)該接口中的方法
public void setTopClickListener(normalTopClickListener mListener){ this.mClickListener =mListener; }
最后在控件模板中,在左右控件的點擊事件里去調(diào)用接口的方法,即可得到調(diào)用者的具體實現(xiàn)
private void addOnClick() { leftTextView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mClickListener.onLeftClick(view); } }); leftImage.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mClickListener.onLeftClick(view); } }); rightTextView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mClickListener.onRightClick(view); } }); rightImage.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mClickListener.onRightClick(view); } }); }
github源碼
結(jié)語
終于寫完了第一篇博客,說句實在的,第一次寫起來感覺真不簡單。如果文中有任何錯誤或者建議,歡迎指出,不勝感激
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。