自定義 View 之組合大法

自定義View分類

Android 中自定義 View 個(gè)人覺得分類有兩種:

  • 自定義的 ViewGroup ,通過繼承現(xiàn)有的 ViewGroup 將已有的控件組合起來方便實(shí)用。
  • 自定義 View 新啼,系統(tǒng)完全沒有的控件需要自己繪制燥撞。這類自定義 View 的發(fā)揮余地也最大物舒,可以隨意揮動(dòng)你的畫筆實(shí)現(xiàn)各種炫酷的形狀火诸。

今天要說的組合大法即第一種方式置蜀,將現(xiàn)有的控件組合起來實(shí)用悉盆。先看一張圖:

enter description here
enter description here

這樣的一個(gè)菜單 Item 布局是不是很常見秋秤,如果每次都來寫這樣的布局再一個(gè)個(gè)找到上面的控件再進(jìn)行賦值是不是會(huì)覺得很煩脚翘,做了很多重復(fù)的工作来农。這時(shí)候如果吧這個(gè)布局封裝成一個(gè)控件备图,就能少寫重復(fù)代碼。

定制步驟

1抠藕、寫出這個(gè)控件的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:background="@drawable/menuitem_background"
    android:elevation="3dp"
    android:orientation="vertical"
    android:padding="4dp">

    <ImageView
        android:id="@+id/icon_left"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:padding="4dp"
        android:scaleType="fitCenter"
        android:src="@drawable/image_reward" />

    <TextView
        android:id="@+id/menu_text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginStart="4dp"
        android:layout_toEndOf="@id/icon_left"
        android:gravity="center_vertical"
        android:text="菜單" />

    <ImageView
        android:id="@+id/icon_right"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentEnd="true"
        android:padding="8dp"
        android:src="@drawable/arrow_right" />
</RelativeLayout>

ps :里面的字符串資源和長度還是老老實(shí)實(shí)按需要寫在 string 和 dimens 文件中。這里是個(gè)不好的習(xí)慣零院,實(shí)際開發(fā)注意就行

2告抄、創(chuàng)建 attrs 文件打洼,如果有的話直接在里面寫自定義控件的一些屬性

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="MenuItemView">
        <!--布局中的文字-->
        <attr name="text" format="string" />
        <!--布局中左邊的icon-->
        <attr name="leftIcon" format="reference" />
        <!--布局中右邊的icon-->
        <attr name="rightIcon" format="reference" />
        <!--文字的大小-->
        <attr name="textSize" format="dimension" />
        <!--文字的顏色-->
        <attr name="textColor" format="color" />
    </declare-styleable>
</resources>

這樣在需要寫的布局中就可以像 android:text="xxx" 一樣對這些屬性進(jìn)行設(shè)置
attrs 文件定義屬性時(shí)需要注意炫惩,屬性名稱重復(fù)時(shí)需要將該屬性提取為公共屬性:

    //如果再定義一個(gè)自定義控件阿浓,屬性還按照這樣來編譯會(huì)報(bào)錯(cuò)體會(huì)屬性名已經(jīng)出現(xiàn)過
    <declare-styleable name="RowText">
        <!--布局中的文字-->
        <attr name="text" format="string" />
        <!--文字的大小-->
        <attr name="textSize" format="dimension" />
        <!--文字的顏色-->
        <attr name="textColor" format="color" />
    </declare-styleable>
    
//解決辦法筋蓖,將共有屬性提取出來
    
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--布局中的文字-->
    <attr name="text" format="string" />
    <!--文字的大小-->
    <attr name="textSize" format="dimension" />
    <!--文字的顏色-->
    <attr name="textColor" format="color" />

    <declare-styleable name="MenuItemView">
        <!--布局中左邊的icon-->
        <attr name="leftIcon" format="reference" />
        <!--布局中右邊的icon-->
        <attr name="rightIcon" format="reference" />
        <!--布局中的文字-->
        <attr name="text" />
        <!--文字的大小-->
        <attr name="textSize" />
        <!--文字的顏色-->
        <attr name="textColor" />
    </declare-styleable>

    <declare-styleable name="RowText">
        <!--布局中的文字-->
        <attr name="text" />
        <!--文字的大小-->
        <attr name="textSize" />
        <!--文字的顏色-->
        <attr name="textColor" />
    </declare-styleable>
</resources>

3、繼承ViewGroup自定義自己的ViewGroup,并在構(gòu)造方法中將attrs的屬性與ViewGroup中的控件關(guān)聯(lián)起來

例如本例使用的 RelativeLayout 设哗,則自定義 View 的代碼如下:

    public MenuItem(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public MenuItem(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        inflate(context, R.layout.menuitem_layout, this);
        ButterKnife.bind(this);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MenuItemView);
        //關(guān)聯(lián)textColor
        int textColor = ta.getColor(R.styleable.MenuItemView_textColor, Color.GRAY);
        menuText.setTextColor(textColor);
        //關(guān)聯(lián)TextSize
        float textSize = ta.getDimension(R.styleable.MenuItemView_textSize, getResources().getDimension(R.dimen.default_textsize));
        menuText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
        //關(guān)聯(lián)Icon
        int leftIconId = ta.getResourceId(R.styleable.MenuItemView_leftIcon, R.drawable.image_reward);
        iconLeft.setImageDrawable(getResources().getDrawable(leftIconId, null));
        int rightIconId = ta.getResourceId(R.styleable.MenuItemView_rightIcon, R.drawable.arrow_right);
        iconRight.setImageDrawable(getResources().getDrawable(rightIconId, null));
        //關(guān)聯(lián)Text
        String text = ta.getString(R.styleable.MenuItemView_text);
        if (text != null)
            menuText.setText(text);
        ta.recycle();
    }

如果要獲取控件的或者設(shè)置控件的一些屬性可再寫一些 public 方法提供回調(diào):

    //設(shè)置text
    public void setMenuText(String text) {
        menuText.setText(text);
    }
    //獲取text
    public CharSequence getText() {
        return menuText.getText();
    }

4、最后在布局中使用該控件:

    <com.pandaq.mvpdemo.customview.MenuItem
        android:id="@+id/https_unfriendly"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:text="HTTPS unfriendly"
        app:textColor="@color/black"
        app:textSize="14sp" />

關(guān)于 attrs 中的屬性說明

format 一共有如下幾種類型:

  • reference // 資源Id战虏,如圖片之類的
//定義
<attr name="leftIcon" format="reference" />
//控件初始化獲取方式
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView);
//這里以圖片資源為例,第一個(gè)參數(shù)為attrs中定義的烦感,第二個(gè)為取值失敗時(shí)的默認(rèn)值
int reference = ta.getResourceId(R.styleable.MenuItemView_leftIcon,R.drawable.image_reward);
  • color // 顏色屬性
//定義
<attr name="textColor" format="color" />
//控件初始獲取方式
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
//第一個(gè)參數(shù)為attrs中定義的參數(shù),第二個(gè)為取值失敗時(shí)的默認(rèn)值
int color = ta.getColor(R.styleable.MenuItemView_textColor,Color.RED);
  • boolean // 布爾值
//定義
<attr name="focusable" format="boolean"/>
//代碼中獲取方式
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
//第一個(gè)參數(shù)為attrs中定義的參數(shù)绿渣,第二個(gè)為取值失敗時(shí)的默認(rèn)值
boolean focusable = ta.getBoolean(R.styleable.MenuItemView_focusable,true);
  • dimension //尺寸值,dp燕耿,px中符,sp等
//定義
<attr name="textSize" format="dimension" />
/**
 *getDimension() 返回值為float類型
 *getDimensionPixelSize() 返回的是四舍五入后的整型值
 *getDimensionPixeOffset() 返回的是舍棄小數(shù)部分的整型值
 */
 TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
float textSize = ta.getDimension(R.styleable.MenuItemView_textSize, getResources().getDimension(R.dimen.default_textsize));
  • enum // 枚舉類型
//定義
<attr name="orientation">
    <enum name="horizontal" value="0" />
    <enum name="vertical" value="1" />
</attr>   
  • float //浮點(diǎn)型
//定義
<attr name="floatNumber" format="float"/>
//java代碼中獲取屬性
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
float number = ta.getFloat(R.styleable.floatNumber,0.0);
  • fraction //百分?jǐn)?shù)
//定義
<attr name="fraction" format="fraction"/>
//java代碼中獲取屬性
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
float fraction = ta.getFraction(R.styleable.fraction,100,30,0.3);
  • integer //整型
//定義
<attr name="number" format="integer"/>
//java代碼中獲取屬性
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
int number = ta.getInt(R.styleable.number,0);
//或者得到一個(gè)Integer對象
Integer a = ta.getInteger(R.styleable.number, 0);
  • string //字符串類型
//定義
<attr name="text" format="string"/>
//java代碼中獲取屬性
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MenuItemView)
String text = ta.getString(R.styleable.MenuItemView_text);

完整代碼

查看demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市誉帅,隨后出現(xiàn)的幾起案子淀散,更是在濱河造成了極大的恐慌右莱,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吧凉,死亡現(xiàn)場離奇詭異隧出,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)阀捅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門凄诞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轴咱,“玉大人窖剑,你說我怎么就攤上這事需了⌒莱” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵禽拔,是天一觀的道長茧痕。 經(jīng)常有香客問我令野,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上报强,老公的妹妹穿的比我還像新娘。我一直安慰自己哮缺,他們只是感情好埠胖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布圈盔。 她就那樣靜靜地躺著宽闲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上躲叼,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天或听,我揣著相機(jī)與錄音元镀,去河邊找鬼卿闹。 笑死锻霎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蜀细。 我是一名探鬼主播奠衔,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼生兆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起徘公,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤缝其,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后徘六,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體内边,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年待锈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漠其。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡竿音,死狀恐怖和屎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情春瞬,我是刑警寧澤柴信,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站宽气,受9級(jí)特大地震影響随常,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萄涯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一绪氛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涝影,春花似錦枣察、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臂痕。三九已至,卻和暖如春宛琅,著一層夾襖步出監(jiān)牢的瞬間刻蟹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工嘿辟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舆瘪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓红伦,卻偏偏與公主長得像英古,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子昙读,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容