最近在對公司的項目進(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"
“讓它簡單些,連笨蛋都看得懂”