Android自定義控件之創(chuàng)建可復(fù)用的組合控件
前面已學(xué)習(xí)了一種自定義控件的實(shí)現(xiàn),是Andriod 自定義控件之音頻條,還沒學(xué)習(xí)的同學(xué)可以學(xué)習(xí)下,學(xué)習(xí)了的同學(xué)也要去溫習(xí)下,一定要自己完全的掌握了,再繼續(xù)學(xué)習(xí),貪多嚼不爛可不是好的學(xué)習(xí)方法,我們爭取學(xué)習(xí)了一種技術(shù)就會一種技術(shù),而且不光看了就算了,最好的方法就是看完我自己再練習(xí)下,再擴(kuò)展下,在原來的基礎(chǔ)上在添加一些東西,比如,增加一些功能實(shí)現(xiàn)等等。
今天我們打算學(xué)習(xí)下另外一種自定義控件,就是創(chuàng)建可重復(fù)使用的組合控件,那么問題來了:
什么是可重復(fù)使用?
就是在應(yīng)用中,可以在多個地方共同使用一套代碼。這樣不僅能減少我們的工作量,而且還能保持應(yīng)用風(fēng)格的一致,這種應(yīng)用最多最直接的體現(xiàn)就是統(tǒng)一風(fēng)格樣式的標(biāo)題欄。
那什么又是組合控件呢?
組合控件,顧名思義就是多個控件組合在一起,相互協(xié)作共同完成某些特定的功能。
下面我們就針對app應(yīng)用中風(fēng)格統(tǒng)一的標(biāo)題欄來開始我們的學(xué)習(xí)。
首先,既然是一組組合的控件,那就必須有一個可以來包含這些控件的容器,我們所接觸的可以存放控件的容器很多,比如LinearLayout、RelativeLayout等等多種Layout,今天我們就選擇RelativeLayout來做我們的容器。和以前一樣,我們先定義一個CompositeViews類來繼承RelativeLayout類,并重寫它的構(gòu)造方法,代碼如下:
public class CompositeViews extends RelativeLayout{ public CompositeViews(Context context) { this(context,null); } public CompositeViews(Context context, AttributeSet attrs) { this(context, attrs,0); } public CompositeViews(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } }
接下來,我們再定義三個TextView控件,分別是mLefeText,mRightText,textTitle用來顯示“返回”,“搜索”以及“標(biāo)題”并且使用LayoutParams規(guī)定它們在容器里面的對齊方式。請看代碼:
public class CompositeViews extends RelativeLayout{ private TextView mLefeText; private TextView mRightText; private TextView textTitle; private LayoutParams leftLayoutParams; private LayoutParams ridhtLayoutParams; private LayoutParams titleLayoutParams; public CompositeViews(Context context) { this(context,null); } public CompositeViews(Context context, AttributeSet attrs) { this(context, attrs,0); } public CompositeViews(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); }
initView(context)方法中是用來初始化三個組合控件的,請看:
private void initView(Context context) { mLefeText = new TextView(context); mRightText = new TextView(context); textTitle = new TextView(context); /* * 左按鈕位置 */ leftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); leftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE); mLefeText.setText("返回"); mLefeText.setTextSize(22); /* * 右按鈕位置 */ ridhtLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); ridhtLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE); mRightText.setText("搜索"); mRightText.setTextSize(22); /* * 中間標(biāo)題位置 */ titleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); titleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE); textTitle.setText("這是一個標(biāo)題"); textTitle.setTextSize(22); }
ok,以上的代碼已經(jīng)實(shí)現(xiàn)了組合控件的顯示和對齊方式,我們把定義的View添加到布局文件中并在Activity加載吧
activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:background="#999999" android:layout_height="wrap_content" android:orientation="vertical"> <com.sanhuimusic.mycustomview.view.CompositeViews android:id="@+id/topBar" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
MainActivity:
public class MainActivity extends AppCompatActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
我們先來運(yùn)行看下結(jié)果
ok,已顯示出來了,但是相信大家也看出來了,這上面的代碼中,各個控件中的屬性是都是我們固定寫死的,既然我們是創(chuàng)建可服用的控件,固定寫死的東西肯定是不可取的,那么我們怎么可以靈活地獲取控件的屬性,以至于能達(dá)到復(fù)用呢?
這就必須要接觸另外一種技術(shù)了,就是自定義屬性。用我們自定義的屬于可以在每次使用我們定義的控件時為其分配屬性即可。下面我們來學(xué)習(xí)下自定義屬性。
自定義屬性其實(shí)也是相當(dāng)?shù)暮唵危紫?,我們現(xiàn)在資源文件res下values目錄下新建一個attrs.xml文件(eclipse自帶,as自建),新建的attrs.xml是一個包含如下代碼的文件:
<?xml version="1.0" encoding="utf-8"?> <resources> </resources>
在resources中有各種屬性供我們使用,同學(xué)們可以自己看下。根據(jù)我們現(xiàn)在的需求,我們選擇使用declare-styleable來聲明我們的屬性集,然后為其定義特有的name屬性,這個name是供我們在使用自定義屬性時,通過它可以查找到里面的所有屬性。請看如下代碼:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CompositeViews"> <attr name="titleText" format="string"/> <attr name="titleTextSize" format="dimension"/> <attr name="titleColor" format="color"/> <attr name="titleBackground" format="color|reference"/> <attr name="leftTextColor" format="color"/> <attr name="leftBackground" format="color|reference"/> <attr name="leftText" format="string"/> <attr name="leftTextSize" format="dimension"/> <attr name="rightTextColor" format="color"/> <attr name="rightBackground" format="color|reference"/> <attr name="rightText" format="string"/> <attr name="rightTextSize" format="dimension"/> </declare-styleable> </resources>
單獨(dú)拿一行屬性來解析下它所代表的含義:如
好了,自定義屬性我們已學(xué)習(xí)完畢,那么該怎么使用我們自己定義的屬性呢?其實(shí)也很簡單,在我們的activity_main.xml文件中直接使用我們定義的屬性就可以了,但是在使用是之前必須在指定引用第三方控件的命名空間,在跟布局文件中添加如下一行代碼:
xmlns:custom="http://schemas.android.com/apk/res-auto"
custom是我們第三方命名空間的名字,可以任意命名,我們在使用自定義屬性時必須以它開頭。請看代碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:background="#999999" android:layout_height="wrap_content" android:orientation="vertical"> <com.sanhuimusic.mycustomview.view.CompositeViews android:id="@+id/topBar" android:layout_width="wrap_content" android:layout_height="wrap_content" custom:titleText="@string/titleText" custom:titleColor="#000000" custom:titleTextSize="@dimen/titleTextSize" custom:titleBackground="#999999" custom:leftText="@string/leftText" custom:leftTextColor="#FFFFFF" custom:leftBackground="#666666" custom:leftTextSize="@dimen/leftTextSize" custom:rightText="@string/rightText" custom:rightTextColor="#FFFFFF" custom:rightBackground="#666666" custom:rightTextSize="@dimen/rightTextSize" /> </LinearLayout>
我們是使用custom加上我們自定義屬性里面< attr name="titleText" format="string"/>里的name值來動態(tài)設(shè)置屬性值的,如:custom:titleText="@string/titleText"。
ok,在我們xml文件中已設(shè)定好屬性值,那么該怎么顯示出來呢?這個是需要通過一個類型組TypedArray來獲取的,它里面包含各種從AttributeSet屬性集中獲取屬性的方法,所以我們修改上面的構(gòu)造方法和initView(context)方法,如下所示:
private void initView(Context context, AttributeSet attrs) { mLefeText = new TextView(context); mRightText = new TextView(context); textTitle = new TextView(context); /** * 獲取自定義屬性 */ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CompositeViews); String titleText = typedArray.getString(R.styleable.CompositeViews_titleText); float titleTextSize = typedArray.getDimension(R.styleable.CompositeViews_titleTextSize, 16); int titleColor = typedArray.getColor(R.styleable.CompositeViews_titleColor,0); Drawable titleBackground = typedArray.getDrawable(R.styleable.CompositeViews_titleBackground); String leftText = typedArray.getString(R.styleable.CompositeViews_leftText); int leftTextColor = typedArray.getColor(R.styleable.CompositeViews_leftTextColor, 0); float leftTextSize = typedArray.getDimension(R.styleable.CompositeViews_leftTextSize, 16); Drawable leftBackground = typedArray.getDrawable(R.styleable.CompositeViews_leftBackground); String rightText = typedArray.getString(R.styleable.CompositeViews_rightText); int rightTextColor = typedArray.getColor(R.styleable.CompositeViews_rightTextColor, 0); float rightTextSize = typedArray.getDimension(R.styleable.CompositeViews_rightTextSize, 16); Drawable rightBackground = typedArray.getDrawable(R.styleable.CompositeViews_rightBackground); typedArray.recycle(); /* * 左按鈕位置 */ leftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); leftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE); mLefeText.setText(leftText); mLefeText.setTextColor(leftTextColor); mLefeText.setTextSize(leftTextSize); mLefeText.setBackground(leftBackground); addView(this.mLefeText,leftLayoutParams); /* * 右按鈕位置 */ ridhtLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); ridhtLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE); mRightText.setText(rightText); mRightText.setTextColor(rightTextColor); mRightText.setTextSize(rightTextSize); mRightText.setBackground(rightBackground); addView(mRightText,ridhtLayoutParams); /* * 中間標(biāo)題位置 */ titleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); titleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE); textTitle.setText(titleText); textTitle.setTextSize(titleTextSize); textTitle.setTextColor(titleColor); textTitle.setBackground(titleBackground); addView(textTitle,titleLayoutParams); }
代碼解釋:首先通過上下文context獲取到屬性存放到TypedArray 中,然后通過TypedArray 里封裝好的各種方法獲取對應(yīng)的屬性值,然后再分別為我們的控件設(shè)置屬性。這樣就完成了,自定義屬性的使用,并且復(fù)用度高,每當(dāng)需要使用標(biāo)題欄是都只需要在xml中添加我們定義的View控件,為其配置屬性即可使用,節(jié)約了開發(fā)時間,提高了效率,并且還保持的app風(fēng)格的一致。
好,到這里感覺已經(jīng)講完了整個過程吧,其實(shí)還有一個重要的實(shí)現(xiàn)還沒有講。我們的控件已經(jīng)可以呈現(xiàn)出來了,但是怎么完成里面控件的作用呢?
這里比較常見的做法是利用回調(diào)機(jī)制來實(shí)現(xiàn)功能的開發(fā),首先我們先定義一個接口,創(chuàng)建兩個方法,用于左右控件的點(diǎn)擊事件。
public interface TopBarClickListener{ void leftClickListener(); void rightClickListener(); }
然后在構(gòu)造方法中為左右控件添加點(diǎn)擊事件,但不實(shí)現(xiàn)功能,等待調(diào)用者自己實(shí)現(xiàn):
private void setListener() { mLefeText.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mTopBarClickListener.leftClickListener(); } }); mRightText.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mTopBarClickListener.rightClickListener(); } }); }
再者,把定義好的接口暴露給調(diào)用者:
public void setOnTopBarClickListener(TopBarClickListener topBarClickListener){ mTopBarClickListener = topBarClickListener; }
最后,誰調(diào)用,誰實(shí)現(xiàn)。這就完成了不同界面復(fù)用控件實(shí)現(xiàn)不同的功能的便利。在這里我們只在MainActivity中打印Toast就可以了。
public class MainActivity extends AppCompatActivity { private CompositeViews topBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); topBar = (CompositeViews) findViewById(R.id.topBar); topBar.setOnTopBarClickListener(new CompositeViews.TopBarClickListener(){ @Override public void leftClickListener() { ToastUtil.makeText(MainActivity.this,"您點(diǎn)擊了返回鍵",Toast.LENGTH_SHORT).show(); } @Override public void rightClickListener() { ToastUtil.makeText(MainActivity.this,"您點(diǎn)擊了搜索鍵",Toast.LENGTH_SHORT).show(); } }); } }
OK,看看結(jié)果吧
好,已經(jīng)可以實(shí)現(xiàn)我們的需求了,是不是學(xué)會很多呢。
今天主要講了android自定義View中另一種的實(shí)現(xiàn),并且還學(xué)習(xí)了自定義屬性,同學(xué)們下去好好消化下,并自己動手現(xiàn)實(shí)一兩個例子吧,好了,今天就講到這里,謝謝大家。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義控件之繼承ViewGroup創(chuàng)建新容器
- android自定義控件創(chuàng)建翻頁接口詳細(xì)代碼
- android 自定義控件 自定義屬性詳細(xì)介紹
- android開發(fā)教程之自定義控件checkbox的樣式示例
- android自定義控件和自定義回調(diào)函數(shù)步驟示例
- Android中自定義控件的declare-styleable屬性重用方案
- 詳解Android自定義控件屬性TypedArray以及attrs
- Android開發(fā)之自定義控件用法詳解
- Android自定義控件之圓形/圓角的實(shí)現(xiàn)代碼
- Android自定義控件的創(chuàng)建方法
相關(guān)文章
Android自定義View實(shí)現(xiàn)旋轉(zhuǎn)的圓形圖片
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)旋轉(zhuǎn)的圓形圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01Android編程使用LinearLayout和PullRefreshView實(shí)現(xiàn)上下翻頁功能的方法
這篇文章主要介紹了Android編程使用LinearLayout和PullRefreshView實(shí)現(xiàn)上下翻頁功能的方法,涉及Android界面布局與邏輯處理相關(guān)操作技巧,需要的朋友可以參考下2017-08-08AndroidStudio中重載方法@Override的使用詳解
這篇文章主要介紹了AndroidStudio中重載方法@Override的使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04Flutter?點(diǎn)擊兩次退出app的實(shí)現(xiàn)示例
本文主要介紹了Flutter?點(diǎn)擊兩次退出app的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05Android使用WindowManager制作一個可拖動的控件
這篇文章主要為大家詳細(xì)介紹了Android使用WindowManager制作一個可拖動的控件的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-08-08Android開發(fā)筆記之:Splash的實(shí)現(xiàn)詳解
本篇文章是對Android中Splash的實(shí)現(xiàn)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05談?wù)剬ndroid View事件分發(fā)機(jī)制的理解
本篇文章主要介紹了談?wù)剬ndroid View事件分發(fā)機(jī)制的理解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01Android開發(fā)實(shí)現(xiàn)日期時間控件選擇
這篇文章主要為大家詳細(xì)介紹了Android開發(fā)實(shí)現(xiàn)日期時間控件選擇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09