【安卓自定義控件系列】安卓自定義控件之組合控件


在安卓開發中,谷歌已經爲咱們提供了許多原生控件,基本上可以知足咱們平常的開發需求,可是某些項目中原生控件可能達不到產品所要求的各式各樣的酷炫效果或功能效果,這個時候咱們只能本身自定義控件來知足項目需求,咱們知道自定義控件包括三種方式:java

1繼承控件,即繼承谷歌提供的原生控件,在此基礎上提供一些原生控件不具有的功能,如github上各類酷炫效果的開源組件基本上都是採用的這種方式.android

2組合控件:即組合多個原生控件來達到某些單個原生控件本來不具有的功能,這個在平常開發中應該是使用的比較多的,如基本上每一個App都存在一個標題欄,而這些標題欄是能夠被複用的,此時咱們能夠將其抽象出來組合爲一個控件,這樣在須要標題欄的地方直接使用該控件。(固然也能夠採用include佈局的方式,可是這樣僅僅只是界面複用而已,功能不能複用)git

3自繪控件:即直接繼承自View類,而後本身重寫onDraw方法,某些狀況下可能須要重寫onMeasure方法。github


這三種方式,第一種方式咱們使用的不多,由於github上大量優秀的開源組件就是採用的這種方式,以下拉刷新上拉加載的listView,側滑刪除的listView等,所以咱們只須要直接拿來用就能夠了,不要去重複造輪子,固然若是是學習自定義控件的知識的話,咱們也能夠直接去閱讀這些開源項目的源代碼,第二種方式咱們使用的比較多的地方就是一個App的標題欄,一般都是採用的這種方式來完成的,第三種方式在通常的項目中不多使用到,除非項目須要完成一些複雜的效果。本博客將以第二中方式即組合控件爲例來說解安卓自定義控件的使用,將以模仿騰訊QQ的標題欄爲例來教你們如何自定義組合控件。首先咱們來看一下騰訊QQ的標題欄。而後按照這個樣子咱們本身模仿自定義一個標題欄控件。固然QQ的標題欄仍是比較複雜的,由於標題欄中的文字會隨着用戶點擊底部不一樣的button而顯示不一樣的內容,固然這個功能個也很好實現,關鍵是若是要截圖的話得截幾張圖,這裏我就選擇最具表明性的一個界面,其他的看官能夠本身用QQ試一下。app


能夠看到在左側是一個ImageView,中間是兩個button,點擊不一樣button顯示不一樣內容,固然這是在消息界面,所以中間是兩個button,而在聯繫人與動態界面中間只顯示文字而已,所以此時中間是TextView,右側基本上也是一樣的道理。因此第一步咱們須要在layout佈局文件中組合控件來到達這樣的一個界面效果。函數

common_title_bar的layout文件以下:佈局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/relativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:background="#fff"
       >

    <hq.king.view.CircleImageView
        android:paddingLeft="4dp"
        android:id="@+id/title_bar_leftImg"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="7dp"
        android:background="@drawable/title_bar_image_shape"
        app:civ_border_width="1dp"
        app:civ_border_color="@color/blue"
        />
 
    <TextView
        android:id="@+id/center_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="14dp" />

    <Button
        android:id="@+id/title_bar_rightBtn"
        android:layout_width="35dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="7dp"
        android:layout_marginRight="3dp"
        android:background="#fff"/>


    <LinearLayout
        android:id="@+id/title_bar_linearLayout"
        android:layout_width="150dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:layout_marginLeft="60dp"
        android:layout_toRightOf="@+id/imageView1" >



        <Button
            android:id="@+id/title_bar_linear_leftBtn"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:background="@drawable/title_bar_linear_leftbtn_shape"
             />

        <Button
            android:id="@+id/title_bar_linear_rightBtn"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:background="@drawable/title_bar_linear_rightbtn_shape"/>
        
    </LinearLayout>
</RelativeLayout>
能夠看到該佈局的根佈局是一個RelativeLayout,固然這個是和具體的組合控件的界面相關的,不過像這種標題欄咱們通常都使用RelativeLayout佈局,而後在該佈局中咱們基本上按照前面的分析組合了幾個原生的控件,固然那個ImageView爲了達到和騰訊QQ同樣的效果,我採用的是開源的CircleImageView,這些組合控件之間的位置關係經過相對佈局來控制。

接下來就是自定義組合控件了,代碼以下:學習

public class TitleBarView extends RelativeLayout {

	private Context mContext;
	Button rightBtn;
	TextView center_tv;
	LinearLayout title_linearlayout;
	Button linear_leftBtn;
	Button linear_rightBtn;
	ImageView leftImg;
	
	public TitleBarView(Context context) {
		super(context);
		mContext=context;
		findView();
		// TODO Auto-generated constructor stub
	}

	public TitleBarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext=context;
		findView();
	}
	public void findView()
	{
		
		LayoutInflater.from(mContext).inflate(R.layout.common_title_bar, this);
		
		 leftImg=(ImageView) findViewById(R.id.title_bar_leftImg);
		 rightBtn=(Button)findViewById(R.id.title_bar_rightBtn);
		 center_tv=(TextView) findViewById(R.id.center_tv);
		 title_linearlayout=(LinearLayout) findViewById(R.id.title_bar_linearLayout);
		 linear_leftBtn=(Button) findViewById(R.id.title_bar_linear_leftBtn);
		 linear_rightBtn=(Button) findViewById(R.id.title_bar_linear_rightBtn);
		
		
		
	}
	public void setCommonTitle(int leftImg_vi,int centerLinear_vi,int textView_vi,int rightBtn_vi)
	{
	   
		leftImg.setVisibility(leftImg_vi);
		title_linearlayout.setVisibility(centerLinear_vi);
		center_tv.setVisibility(textView_vi);
		rightBtn.setVisibility(rightBtn_vi);
		
	}
	public void setDefaultImgLeft(int icon){
		Drawable img=mContext.getResources().getDrawable(icon);
		leftImg.setImageDrawable(img);;
	}
	public void setUserImgLeft(Bitmap bitmap)
	{
		leftImg.setImageBitmap(bitmap);
		
	}
	public void setBtnRight(int icon)
	{
		rightBtn.setText(icon);
		
	}
	public void setBtnRightText(String str)
	{
		rightBtn.setText(str);
		
	}
	
	public void setBtnRightIcon(int icon)
	{
		
		Drawable img=mContext.getResources().getDrawable(icon);
		rightBtn.setBackgroundDrawable(img);
		
	}
	public void setBtnRightDrawable(Drawable img)
	{
		
		rightBtn.setBackgroundDrawable(img);
		
	}
	
	public void setTitleLeft(int resId){
		linear_leftBtn.setText(resId);
	}
	
	public void setTitleRight(int resId){
		linear_rightBtn.setText(resId);
	}
	public void setTitleText(int txtRes){
		center_tv.setText(txtRes);
	}
	
	public void setLefImgtOnclickListener(OnClickListener listener){
		leftImg.setOnClickListener(listener);
	}
	
	public void setBtnRightOnclickListener(OnClickListener listener){
		rightBtn.setOnClickListener(listener);
	}
	
	public ImageView getTitleLeft(){
		return leftImg;
	}
	
	public Button getTitleRight(){
		return rightBtn;
	}

	
	
}
能夠看到,自定義的TitleBarView繼承自RelativeLayout,由於咱們前面佈局文件中根佈局使用的是RelativeLayout,固然也能夠不這麼作,但這樣作規範一些,而後自定義控件TitleBarView的構造函數中使用LayoutInflater.from(mContext).inflate(R.layout.common_title_bar, this);語句將common_title_bar佈局文件中的佈局解析出來,固然我這裏爲了代碼規範,在自定義控件TitleBarView的構造函數中使用的是findView()函數,而後在該函數中對控件進行初始化,這樣作代碼邏輯清晰。而後在該TitleBarView中提供一些

方法來控制組合控件的可見性與某些功能,由於咱們知道騰訊QQ的標題欄隨着底部不一樣button被點擊標題欄中間會顯示不一樣的控件,這咱們在前面已經分析過,所以咱們須要提供一個控制這些組合控件可見性的方法,除了可見性外還需提供一些功能方法,這個視具體業務需求而定,這樣會具有更好的擴展性。this


經過前面兩個步驟,一個自定義的組合控件就已經完成了,餘下的就是如何使用了,這個也很簡單,在須要使用該自定義控件的佈局文件中使用該自定義控件完整的路徑名便可,即包名+類名,以下所示:spa

<com.example.view.TitleBarView
    android:id="@+id/title_bar"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    >
    
</com.example.view.TitleBarView>

運行以後效果以下:



這樣一個高仿騰訊QQ的標題欄就作出來了,固然這個運行結果是個人高仿騰訊QQ即時IM項目的運行結果,前面的代碼也是在該項目中用到的代碼,該項目已開源,若是看官想體驗完整的效果能夠 follow個人github,start與fork個人開源項目,個人githubhttps://github.com/HuTianQi


若是你們以爲不錯記得小手一抖點個贊哦,歡迎你們關注個人博客帳號,將會不按期爲你們分享技術乾貨,福利多多哦!

相關文章
相關標籤/搜索