Android 自定義控件之組合方式

抬頭圖片.jpg

前言

近期從一個小公司辭職了,決定復(fù)習下之前學習過的內(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)上下載的一張設(shè)計圖。


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文件設(shè)置自定義控件屬性

<?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,復(fù)寫構(gòu)造函數(shù)

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

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)容設(shè)置進控件中
        }

    }

    public String getSettingItemDescText() {
        return settingItemDescText;
    }

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

    public int getSettingItemLogoSrc() {
        return settingItemLogoSrc;
    }

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

    public int getSettingItemMoreSrc() {
        return settingItemMoreSrc;
    }

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

    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)設(shè)置,我這里就隨便找了之前使用過的圖片來展示。

<?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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容