Android 自定義控件之組合方式

抬頭圖片.jpg

前言

近期從一個小公司辭職了见坑,決定復習下之前學習過的內(nèi)容嚷掠。所以發(fā)布一篇自定義控件的文章,加深自己的印象荞驴,也同時為以后再找工作做準備不皆。廢話不多說,現(xiàn)在開始熊楼。

自定義控件介紹

Android當中自定義控件的開發(fā)霹娄,Android中所有的控件都是繼承View類。以下圖片是各控件繼承關(guān)系圖


4115762-ec0d29c74a7935a2.jpg

其實所謂的自定義控件其實就是繼承View類鲫骗,并且重寫里面的內(nèi)部方法犬耻。通常來說,自定義控件有三種方式:
1.自定義View: 繼承View执泰。
2.基于現(xiàn)有的組件:繼承View的派生類枕磁。
3.組合的方式:自定義控件中包含其他組件。

今天呢术吝,我們就來介紹一下組合的方式實現(xiàn)自定義View计济,其他兩種方式等待小編再學習學習之后再發(fā)表。

實踐

說再多的理論不如實踐來得實在排苍,一下是從網(wǎng)上下載的一張設計圖沦寂。


timg.jpg

分析

如果我們要實現(xiàn)這種界面,看起來是挺簡單的淘衙,也不用怎么自定義传藏,但是相對于有部分人想偷懶的人來說(為了長遠方便發(fā)展)。還是自定義一下好一點,這樣毯侦,當我們再別的布局文件中還需要用到的話西壮,直接當控件使用就好。是不是很方便叫惊??
其實說白了呢做修,就是把下圖自定義成一個控件霍狰,之后用到的時候直接當控件使用就好。


Item_20191007202538.jpg

實現(xiàn)的思路其實也挺簡單饰及,自定義一個組合的View蔗坯,線性布局橫向包裹,依次排列ImageView燎含、TextView宾濒、TextView、ImageView屏箍。廢話不多說绘梦,看下如何實現(xiàn)吧。

1.定義自定義控件布局(custom_item_view)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

<!--   線性布局水平對齊包裹-->
    <LinearLayout
        android:id="@+id/setting_item"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#ffffff"
        android:padding="5dp"
        android:orientation="horizontal">

        <!--   自定義控件中第一個圖片-->
        <ImageView
            android:id="@+id/setting_item_logo"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"/>
        <!--   自定義控件中標題-->
        <TextView
            android:id="@+id/setting_item_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="5dp"
            android:gravity="center"
            android:textColor="#000000"
            android:textSize="18sp"/>
        <!--   為了實現(xiàn)赴魁,用一個TextView將后邊的控件顯示在右邊
                 也可以用RelativeLayout實現(xiàn)-->
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"/>
        <!--   自定義控件中概述-->
        <TextView
            android:id="@+id/setting_item_desc"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginRight="5dp"
            android:gravity="center"
            android:textColor="#999999"
            android:textSize="15sp"/>
        <!--   自定義控件中第二個圖片-->
        <ImageView
            android:id="@+id/setting_item_more"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"/>
    </LinearLayout>
    <!--   自定義控件中下劃線-->
    <View
        android:id="@+id/setting_item_line"
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:background="#888888"/>
</LinearLayout>

2.新建一個attrs.XML文件設置自定義控件屬性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomSettingItemView">
<!--        Item標題-->
        <attr name="settingItemTitle" format="string"/>
<!--        Item描述-->
        <attr name="settingItemDesc" format="string"/>
<!--        第一張圖片-->
        <attr name="settingLogoSrc" format="reference"/>
<!--        第二張圖片-->
        <attr name="settingMoreSrc" format="reference"/>
<!--        下劃線顯示與否-->
        <attr name="settingItemUnderLineVisibility" format="boolean"/>
    </declare-styleable>
</resources>

3.繼承FrameLayout卸奉,復寫構(gòu)造函數(shù)

讀取布局文件中的屬性參數(shù)(見init方法):
如果在布局中傳入了自定義的參數(shù),可以在構(gòu)造函數(shù)中從AttributeSet讀取并設置給控件颖御。

package com.example.customview_setting_item.customView;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.customview_setting_item.R;

/**
 * Create by 25497 on 2019/10/6
 * The project name is CustomView-setting_item
 * Leo Mark
 *
 * Desc:  自定義控件(繼承FrameLayout)
 **/
public class CustomSettingItemView extends FrameLayout {

    private Context mContext;
    private View mainView;

    private LinearLayout settingItem;
    private ImageView settingItemLogo;//第一張圖片
    private ImageView settingItemMore;//第二張圖片
    private TextView settingItemTitle;//標題
    private TextView settingItemDesc;//概述
    private View settingItemUnderLine;//下劃線

    private String settingItemTitleText;//標題內(nèi)容
    private String settingItemDescText;//概述內(nèi)容
    private int settingItemLogoSrc;//第一張圖片路徑
    private int settingItemMoreSrc;//第二張圖片路徑
    private boolean settingItemLineVisibility;//下劃線顯示與否判斷

    public String getSettingItemTitleText() {
        return settingItemTitleText;
    }

    public void setSettingItemTitleText(String settingItemTitleText) {
        if (settingItemTitleText!=null){
            this.settingItemTitleText = settingItemTitleText;
            settingItemTitle.setText(settingItemTitleText);//將內(nèi)容設置進控件中
        }

    }

    public String getSettingItemDescText() {
        return settingItemDescText;
    }

    public void setSettingItemDescText(String settingItemDescText) {
        if (settingItemDescText!=null) {
            this.settingItemDescText = settingItemDescText;
            settingItemDesc.setText(settingItemDescText);//將內(nèi)容設置進控件中
        }
    }

    public int getSettingItemLogoSrc() {
        return settingItemLogoSrc;
    }

    public void setSettingItemLogoSrc(int settingItemLogoSrc) {
        if (settingItemLogoSrc!=10000) {
            this.settingItemLogoSrc = settingItemLogoSrc;
            settingItemLogo.setImageResource(settingItemLogoSrc);//將圖片地址設置進控件中
        }
    }

    public int getSettingItemMoreSrc() {
        return settingItemMoreSrc;
    }

    public void setSettingItemMoreSrc(int settingItemMoreSrc) {
        if (settingItemMoreSrc!=10000) {
            this.settingItemMoreSrc = settingItemMoreSrc;
            settingItemMore.setImageResource(settingItemMoreSrc);//將圖片地址設置進控件中
        }
    }

    public boolean getSettingItemLineVisibility() {
        return settingItemLineVisibility;
    }

    public void setSettingItemLineSize(boolean settingItemLineVisibility) {
            this.settingItemLineVisibility = settingItemLineVisibility;
            //判斷是否顯示下劃線
            if (settingItemLineVisibility){
                settingItemUnderLine.setVisibility(VISIBLE);
            }else{
                settingItemUnderLine.setVisibility(INVISIBLE);
            }
    }

    public CustomSettingItemView(@NonNull Context context) {
        super(context);
    }

    public CustomSettingItemView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public CustomSettingItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    public CustomSettingItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    /**
     * 定義自定義控件中的屬性
     * @param context
     * @param attrs
     */
    private void init(Context context, AttributeSet attrs) {
        this.mContext=context;
        LayoutInflater inflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mainView=inflater.inflate(R.layout.custom_setting_item_view,this,true);
        initView(mainView);//初始布局中的控件

        TypedArray typedArray=mContext.obtainStyledAttributes(attrs, R.styleable.CustomSettingItemView);
        setSettingItemTitleText(typedArray.getString(R.styleable.CustomSettingItemView_settingItemTitle));
        setSettingItemDescText(typedArray.getString(R.styleable.CustomSettingItemView_settingItemDesc));
        setSettingItemLogoSrc(typedArray.getResourceId(R.styleable.CustomSettingItemView_settingLogoSrc,10000));
        setSettingItemMoreSrc(typedArray.getResourceId(R.styleable.CustomSettingItemView_settingMoreSrc,10000));
        setSettingItemLineSize(typedArray.getBoolean(R.styleable.CustomSettingItemView_settingItemUnderLineVisibility,true));
    }

    /**
     * 初始化控件
     * @param mainView
     */
    private void initView(View mainView) {
        settingItemTitle=mainView.findViewById(R.id.setting_item_title);
        settingItemDesc=mainView.findViewById(R.id.setting_item_desc);
        settingItemLogo=mainView.findViewById(R.id.setting_item_logo);
        settingItemMore=mainView.findViewById(R.id.setting_item_more);
        settingItemUnderLine=mainView.findViewById(R.id.setting_item_line);
    }
}

4.修改主函數(shù)布局文件

創(chuàng)建主函數(shù)入口MainActivity,布局文件中榄棵,把剛剛自定義的當控件使用就好,也可代碼中動態(tài)設置潘拱,我這里就隨便找了之前使用過的圖片來展示疹鳄。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="測試標題1"
        app:settingItemDesc="測試詳情1"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="測試標題2"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="測試標題3"
        app:settingItemDesc="測試詳情3"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="測試標題4"
        app:settingItemDesc="測試詳情4"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"
        app:settingItemUnderLineVisibility="false"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:settingItemTitle="測試標題5"
        app:settingItemDesc="測試詳情5"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="測試標題6"
        app:settingItemDesc="測試詳情6"
        app:settingLogoSrc="@mipmap/soufa"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="測試標題7"
        app:settingItemDesc="測試詳情7"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>

</LinearLayout>
運行在虛擬機之后的效果圖
微信截圖_20191007213952.jpg

總結(jié)

以上是自定義控件的組合實現(xiàn),在實際開發(fā)中芦岂,肯定不是那么簡單瘪弓,但是萬變不離其中,只要我們懂思路方法盔腔,就不用管項目經(jīng)理啥子無理需求了杠茬。當然,這也只是簡單實現(xiàn)弛随,如果想要實現(xiàn)更多的效果瓢喉。可以通過前面寫的第一種自定義View,繼承View舀透、重寫組件的onMeasure栓票、onLayout、onDraw來實現(xiàn)。

好了走贪,關(guān)于自定義View的其中一種方式就是這樣子了佛猛,如果有錯誤,期待您批評改正坠狡。碼字不易继找,望您收藏、轉(zhuǎn)發(fā)逃沿、點贊婴渡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凯亮,隨后出現(xiàn)的幾起案子边臼,更是在濱河造成了極大的恐慌,老刑警劉巖假消,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柠并,死亡現(xiàn)場離奇詭異,居然都是意外死亡富拗,警方通過查閱死者的電腦和手機臼予,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來媒峡,“玉大人瘟栖,你說我怎么就攤上這事×掳ⅲ” “怎么了半哟?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長签餐。 經(jīng)常有香客問我寓涨,道長,這世上最難降的妖魔是什么氯檐? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任戒良,我火速辦了婚禮,結(jié)果婚禮上冠摄,老公的妹妹穿的比我還像新娘糯崎。我一直安慰自己,他們只是感情好河泳,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布沃呢。 她就那樣靜靜地躺著,像睡著了一般拆挥。 火紅的嫁衣襯著肌膚如雪薄霜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音惰瓜,去河邊找鬼否副。 笑死,一個胖子當著我的面吹牛崎坊,可吹牛的內(nèi)容都是我干的备禀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奈揍,長吁一口氣:“原來是場噩夢啊……” “哼痹届!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起打月,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚕捉,沒想到半個月后奏篙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡迫淹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年秘通,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敛熬。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡肺稀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出应民,到底是詐尸還是另有隱情话原,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布诲锹,位于F島的核電站繁仁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏归园。R本人自食惡果不足惜黄虱,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庸诱。 院中可真熱鬧捻浦,春花似錦、人聲如沸桥爽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聚谁。三九已至母剥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背环疼。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工习霹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人炫隶。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓淋叶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伪阶。 傳聞我的和親對象是個殘疾皇子煞檩,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355