組合組件のCusRelativeLayout(Android-自定義相對布局)

最近在對公司的項目進(jìn)行重構(gòu),在此坐下記錄。

公司項目中的布局文件,可以抽出大部分公用組件,進(jìn)行自定義組合組件,將這些公共的組件組合起來,在里面提供相應(yīng)方法及變量,這樣以后改界面就容易多了,只需改一處,處處都能生效;同時調(diào)用什么的,更方便快捷,代碼也能得到規(guī)范及統(tǒng)一,特別是組件變量的命名。

每個界面中,用到的公共部分,總結(jié)起來有這么幾個:

  • mTitleView 標(biāo)題欄
  • mEmptyView 數(shù)據(jù)為空時的列表空界面
  • mListView 數(shù)據(jù)列表
  • mFailView 網(wǎng)絡(luò)請求失敗時,數(shù)據(jù)重新刷新頁
  • mLoadView 網(wǎng)絡(luò)請求時,數(shù)據(jù)加載的進(jìn)度動畫

由于我們項目中大部分應(yīng)用的布局為RelativeLayout(相對布局),因此將自定義一個組件,并繼承RelativeLayout,作為跟布局,引用到布局可以當(dāng)做RelativeLayout那么處理,非常棒?。?!

    public class CusRelativeLayout extends RelativeLayout

然后編寫相應(yīng)組件的布局文件xml

  • mTitleView --> layout_cus_titleview
  • mEmptyView --> layout_cus_emptyview
  • mListView --> layout_cus_listview
  • mFailView --> layout_cus_failview
  • mLoadView --> layout_cus_loadview

在構(gòu)造函數(shù)中初始化,通過inflate方式生成布局對象,同時也獲取自定義屬性,并執(zhí)行相應(yīng)組件初始化操作

public CusRelativeLayout(Context context) {
        super(context);
        initView(context, null);
}

public CusRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context, attrs);
}

public CusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
    mContext = context;
    mEmptyText = context.getString(R.string.userhome_allempty);
    int marginTop = -1;
    boolean hasTitleView = true, hasListView = true;
    TypedArray a = null;
    if (attrs != null) {
        a = context.obtainStyledAttributes(attrs,R.styleable.CusRelativeLayout);
        mEmptyText = (String)a.getText(R.styleable.CusRelativeLayout_cus_empty_text);
        marginTop = a.getDimensionPixelOffset(R.styleable.CusRelativeLayout_cus_margin_top, -1);
        hasTitleView = a.getBoolean(R.styleable.CusRelativeLayout_cus_has_titleview, hasTitleView);
        hasListView = a.getBoolean(R.styleable.CusRelativeLayout_cus_has_listview, hasListView);
        }

        mLoadView = (ImageView) inflate(mContext, R.layout.layout_cus_loadview, null);
        mEmptyView = (TextView) inflate(mContext, R.layout.layout_cus_emptyview, null);
        mFailView = inflate(mContext, R.layout.layout_cus_failview, null);
        LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        
        ...and so on

自定義屬性

    <declare-styleable name="CusRelativeLayout">
        <attr name="cus_empty_text" format="string"/><!--空界面,文案-->
        <attr name="cus_margin_top" format="dimension"/><!--空界面、失敗請求頁marginTop-->
        <attr name="cus_has_titleview_btn_back_visible" format="boolean"/><!--加載標(biāo)題欄組件-返回鍵 默認(rèn)false-->
        <attr name="cus_is_btn_cancel" format="boolean"/><!--返回鍵變?yōu)槿∠?默認(rèn)false-->
        <attr name="cus_has_listview" format="boolean"/><!--加載列表組件 默認(rèn)true-->
        <attr name="cus_has_titleview" format="boolean"/><!--加載標(biāo)題欄組件 默認(rèn)true-->
        <attr name="cus_click_titleview_listview_go_to_up" format="boolean"/><!--點(diǎn)擊標(biāo)題欄,列表回到頂部 默認(rèn)false-->
</declare-styleable>

生成的組件對象,此時并未add進(jìn)布局里,所以布局里面仍然為空,什么都木有,需要調(diào)用addView(View view)方法

注意!由于是相對布局,因此需要后面添加的View會覆蓋在前面添加的View,因此我的組件,需要在布局Add完所有子View之后,在進(jìn)行Add,這樣顯示的時候就可以覆蓋其前面的子類,因此Add View的順序也很重要,我們可以在onFinishInflate方法中Add 我們的公共View,該方法是布局Inflate完View之后執(zhí)行的回調(diào)。

/**
     * Finalize inflating a view from XML.  This is called as the last phase
     * of inflation, after all child views have been added.
     *
     * <p>Even if the subclass overrides onFinishInflate, they should always be
     * sure to call the super method, so that we get called.
     */
    protected void onFinishInflate() {
    }

我的add view代碼

@Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (mListView != null) {
            addView(mListView);
        }
        addView(mEmptyView);
        addView(mFailView);
        addView(mLoadView);
        if (mTitleView != null) {
            addView(mTitleView);
        }
    }

余下則編寫相應(yīng)的方法,抽出常用的部分寫成方法并暴露給調(diào)用者,這部分代碼就省略,每個人的業(yè)務(wù)不一樣,方法提供也不一樣,具體可以提供顯示、隱藏相應(yīng)組件等方法。

這樣我們的自定義RelativeLayout已經(jīng)完成,可以看下如何調(diào)用,就跟我們使用自定義布局一樣,在xml文件里,作為跟布局即可

<?xml version="1.0" encoding="utf-8"?>
<com.babychat.view.Custom.CusRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/rel_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cus_click_titleview_listview_go_to_up="true"
    app:cus_has_titleview_btn_back_visible="true">

</com.babychat.view.Custom.CusRelativeLayout>

類中,我們通過findViewById獲取根部局對象即可,然后就可以開始調(diào)用布局里面保留的方法、對象

 @Override
    protected void findViewById() {
        rel_parent = mFindViewById(R.id.rel_parent);
        rel_parent.mTvTitle.setText(R.string.special_history_list_title);
        rel_parent.mFailView.setBackgroundResource(R.color.transparent);
        rel_parent.mListView.setPullRefreshEnable(false);
        rel_parent.mListView.setmEnableAutoLoad(true);
    }

最后,總結(jié)一下,這些組件組合在一起,是為了減少輪子的重復(fù)制造,減少代碼的冗余,并且統(tǒng)一代碼規(guī)范,保持kiss原則

"Keep It Simple And Stupid"

“讓它簡單些,連笨蛋都看得懂”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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