Android通用UI封裝----“我的”頁面Item

問題

程序員最討厭的事情是什么? 不是代碼多到寫不完丛晌,而是重復(fù)的代碼要寫無數(shù)遍仅炊。身為程序員的我們,肯定經(jīng)常被這個問題所困擾澎蛛。就比如Android APP中抚垄,“我的”頁面中的每一個Item,就像下圖這樣的這樣的谋逻,


“我的”頁面常見布局

還有像這種資料錄入頁面的:

資料錄入頁面

像這種頁面布局是極其常見的呆馁,幾乎在每個APP中都有那么一兩個這樣的頁面。這種頁面讓Android開發(fā)人員很是頭疼毁兆,開發(fā)難度倒是不難浙滤,就是重復(fù)代碼太多,沒有挑戰(zhàn)性气堕。用一句不好聽的話來說就是“代碼又臭又長”纺腊。所以呢,我就對此做了一個封裝茎芭,達(dá)到一行代碼就是一行item揖膜。

使用效果

先來看一下使用效果,看看封裝后骗爆,使用起來有多簡單次氨。

代碼
對應(yīng)的效果

上面的代碼對有一定Android開發(fā)經(jīng)驗(yàn)的你應(yīng)該不難理解,起始就是new一個Item對象摘投,設(shè)置其屬性(具體下面解釋)煮寡,設(shè)置監(jiān)聽事件(具體下面解釋),添加到LinnearLayout容器中犀呼。

封裝步驟

1.布局

布局不難幸撕,也就是把通常寫的item布局抽取出來。主要包括這么幾個部分:上分割線外臂、下分割線坐儿、左Icon、中間文字(偏左那個)、中間輸入框貌矿、右邊文字炭菌、右邊Icon(默認(rèn)右箭頭)。
直接上代碼逛漫,根據(jù)代碼里的注釋黑低,很好理解。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <!--item的上分割線-->
    <View
        android:id="@+id/divider_top"
        android:layout_width="fill_parent"
        android:layout_height="1px"
        android:background="#efefef" />

    <!--item內(nèi)容部分的容器-->
    <LinearLayout
        android:id="@+id/ll_root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:paddingTop="10dp">

        <!--item左邊的Icon-->
        <ImageView
            android:id="@+id/iv_left_icon"
            android:layout_width="20dp"
            android:layout_height="20dp" />

        <!--item中間部分的文字-->
        <TextView
            android:id="@+id/tv_text_content"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="12dp"
            android:layout_weight="1"
            android:textSize="14sp" />

        <!--item 中間部分的輸入框(有則顯示五則隱藏酌毡,默認(rèn)隱藏)-->
        <EditText
            android:id="@+id/edit_content"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:background="@color/transparent"
            android:lines="1"
            android:maxLines="1"
            android:textSize="14sp" />

        <!--item右邊的文字-->
        <TextView
            android:id="@+id/tv_right_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp" />

        <!--item右邊的Icon 默認(rèn)是向右的箭頭-->
        <ImageView
            android:id="@+id/iv_right_icon"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:paddingLeft="10dp"
            android:src="@mipmap/homepage_right_arrow" />
    </LinearLayout>

    <!--item的下分割線-->
    <View
        android:id="@+id/divider_bottom"
        android:layout_width="fill_parent"
        android:layout_height="1px"
        android:background="#efefef" />

</LinearLayout>

2.MyOneLineView.class的封裝

  • 布局的引入
    Xml布局寫好之后我們還需要一個Java類克握,取名為MyOneLineView.class
    該類繼承LinearLayout或RelativeLayout,使其成為一個容器枷踏。
    然后菩暗,通過LayoutInflater將我們前面寫好的布局進(jìn)入MyOneLineView容器中。
public class MyOneLineView extends LinearLayout {
    //各各控件
    private View dividerTop, dividerBottom;
    private LinearLayout llRoot;
    private ImageView ivLeftIcon;
    private TextView tvTextContent;
    private EditText editContent;
    private TextView tvRightText;
    private ImageView ivRightIcon;

    public MyOneLineView(Context context) {  //該構(gòu)造函數(shù)使其旭蠕,可以在Java代碼中創(chuàng)建
        super(context);
    }
 
    public MyOneLineView(Context context, AttributeSet attrs) {//該構(gòu)造函數(shù)使其可以在XML布局中使用
        super(context, attrs);
    }

    /**
     * 初始化各個控件
     */
    public MyOneLineView init() {
    //引入之前的xml布局
    LayoutInflater.from(getContext()).inflate(R.layout.layout_my_one_line, this, true);
        llRoot = (LinearLayout) findViewById(R.id.ll_root);
        dividerTop = findViewById(R.id.divider_top);
        dividerBottom = findViewById(R.id.divider_bottom);
        ivLeftIcon = (ImageView) findViewById(R.id.iv_left_icon);
        tvTextContent = (TextView) findViewById(R.id.tv_text_content);
        editContent = (EditText) findViewById(R.id.edit_content);
        tvRightText = (TextView) findViewById(R.id.tv_right_text);
        ivRightIcon = (ImageView) findViewById(R.id.iv_right_icon);
        return this;
    }
}

這樣MyOneLineView.class每new一下就代表這一個Item停团。只不過他的樣式還只是默認(rèn)狀態(tài)。下面我們就對它的樣式操作進(jìn)行封裝掏熬。

  • 分割線封裝

前面布局中也介紹了客蹋,每個Item都有上下兩條分割線,默認(rèn)上分割線隱藏孽江,下分割線顯示讶坯,寬度充滿全屏,高度1dp岗屏,顏色是灰色辆琅。
我們封裝幾個方法用于對分割線樣式的改變:

 /**
     * 設(shè)置上下分割線的顯示情況
     *
     * @return
     */
    public MyOneLineView showDivider(Boolean showDividerTop, Boolean showDivderBottom) {
        if (showDividerTop) {
            dividerTop.setVisibility(VISIBLE);
        } else {
            dividerTop.setVisibility(GONE);
        }
        if (showDivderBottom) {
            dividerBottom.setVisibility(VISIBLE);
        } else {
            dividerBottom.setVisibility(GONE);
        }
        return this;
    }

    /**
     * 設(shè)置上分割線的顏色
     *
     * @return
     */
    public MyOneLineView setDividerTopColor(int dividerTopColorRes) {
        dividerTop.setBackgroundColor(getResources().getColor(dividerTopColorRes));
        return this;
    }

    /**
     * 設(shè)置上分割線的高度
     *
     * @return
     */
    public MyOneLineView setDividerTopHigiht(int dividerTopHigihtDp) {
        ViewGroup.LayoutParams layoutParams = dividerTop.getLayoutParams();
        layoutParams.height = DensityUtils.dp2px(getContext(), dividerTopHigihtDp);
        dividerTop.setLayoutParams(layoutParams);
        return this;
    }

  • 每個child的封裝

同上面對分割線樣式的封裝,我們就可以對每個child的樣式提供方法这刷,需要怎樣改變child的樣式就封裝對應(yīng)的方法即可婉烟。直接看代碼:


    /**
     * 設(shè)置root的paddingTop 與 PaddingBottom 從而控制整體的行高
     * paddingLeft 與 paddingRight 保持默認(rèn) 20dp
     */
    public MyOneLineView setRootPaddingTopBottom(int paddintTop, int paddintBottom) {
        llRoot.setPadding(DensityUtils.dp2px(getContext(), 20),
                DensityUtils.dp2px(getContext(), paddintTop),
                DensityUtils.dp2px(getContext(), 20),
                DensityUtils.dp2px(getContext(), paddintBottom));
        return this;
    }

    /**
     * 設(shè)置root的paddingLeft 與 PaddingRight 從而控制整體的行高
     * <p>
     * paddingTop 與 paddingBottom 保持默認(rèn) 15dp
     */
    public MyOneLineView setRootPaddingLeftRight(int paddintTop, int paddintRight) {
        llRoot.setPadding(DensityUtils.dp2px(getContext(), paddintTop),
                DensityUtils.dp2px(getContext(), 15),
                DensityUtils.dp2px(getContext(), paddintRight),
                DensityUtils.dp2px(getContext(), 15));
        return this;
    }

    /**
     * 設(shè)置左邊Icon
     *
     * @param iconRes
     */
    public MyOneLineView setLeftIcon(int iconRes) {
        ivLeftIcon.setImageResource(iconRes);
        return this;
    }

    /**
     * 設(shè)置左邊Icon顯示與否
     *
     * @param showLeftIcon
     */
    public MyOneLineView showLeftIcon(boolean showLeftIcon) {
        if (showLeftIcon) {
            ivLeftIcon.setVisibility(VISIBLE);
        } else {
            ivLeftIcon.setVisibility(GONE);
        }
        return this;
    }

    /**
     * 設(shè)置右邊Icon 以及Icon的寬高
     */
    public MyOneLineView setLeftIconSize(int widthDp, int heightDp) {
        ViewGroup.LayoutParams layoutParams = ivLeftIcon.getLayoutParams();
        layoutParams.width = DensityUtils.dp2px(getContext(), widthDp);
        layoutParams.height = DensityUtils.dp2px(getContext(), heightDp);
        ivLeftIcon.setLayoutParams(layoutParams);
        return this;
    }


    /**
     * 設(shè)置中間的文字內(nèi)容
     *
     * @param textContent
     * @return
     */
    public MyOneLineView setTextContent(String textContent) {
        tvTextContent.setText(textContent);
        return this;
    }

    /**
     * 設(shè)置中間的文字顏色
     *
     * @return
     */
    public MyOneLineView setTextContentColor(int colorRes) {
        tvTextContent.setTextColor(getResources().getColor(colorRes));
        return this;
    }

    /**
     * 設(shè)置中間的文字大小
     *
     * @return
     */
    public MyOneLineView setTextContentSize(int textSizeSp) {
        tvTextContent.setTextSize(textSizeSp);
        return this;
    }

這一部分代碼都比較類似,所以就貼出部分代碼來暇屋。
細(xì)心的同學(xué)會發(fā)現(xiàn)似袁,大部分的方法都是返回了this.這樣做的原因就是想實(shí)現(xiàn)鏈?zhǔn)浇Y(jié)構(gòu),鏈?zhǔn)浇Y(jié)構(gòu)也是最近比較流行的咐刨。

代碼中有這樣的代碼:
DensityUtils.dp2px(getContext(), widthDp)昙衅;
DensityUtils也是一個封裝的工具類,用于dp sp 與px 的轉(zhuǎn)換定鸟,用興趣的同學(xué)可以看這篇文章Android單位轉(zhuǎn)換----常用單位轉(zhuǎn)換工具類

  • 點(diǎn)擊事件的封裝

樣式有了而涉,接下來就應(yīng)該考慮點(diǎn)擊事件了,這一類item通常有兩個點(diǎn)擊事件联予,一整行的點(diǎn)擊事件啼县、右箭頭的點(diǎn)擊事件材原。因此這里封裝了兩個ClickListener

public class MyOneLineView extends LinearLayout {
....
    /**
     * 整個一行被點(diǎn)擊
     */
    public static interface OnRootClickListener {
        void onRootClick(View view);
    }
    /**
     * 右邊箭頭的點(diǎn)擊事件
     */
    public static interface OnArrowClickListener {
        void onArrowClick(View view);
    }
    public MyOneLineView setOnRootClickListener(final OnRootClickListener onRootClickListener, final int tag) {
        llRoot.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                llRoot.setTag(tag);
                onRootClickListener.onRootClick(llRoot);
            }
        });
        return this;
    }
    public MyOneLineView setOnArrowClickListener(final OnArrowClickListener onArrowClickListener, final int tag) {

        ivRightIcon.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ivRightIcon.setTag(tag);
                onArrowClickListener.onArrowClick(ivRightIcon);
            }
        });
        return this;
    }
....
}

小伙伴們可能會問,這里為什么要傳入tag季眷。不用急余蟹,請看下面的使用代碼:


public class MineFragment extends SimpleFragment implements MyOneLineView.OnRootClickListener{
    ......
    initView(){
        //添加我的下載
        llRoot.addView(new MyOneLineView(getContext())
                .initMine(R.mipmap.mine_download, "我的下載", "", true)
                .setOnRootClickListener(this, 1));
        //添加我的收藏
        llRoot.addView(new MyOneLineView(getContext())
                .initMine(R.mipmap.mine_collection, "我的收藏", "", true)
                .setOnRootClickListener(this, 2));
    }


    @Override
    public void onRootClick(View view) {
        switch ((int) view.getTag()) {
            case 1:
                startActivity(new Intent(getContext(), MyDownloadActivity.class));
                break;
            case 2:
                startActivity(new Intent(getContext(), MyCollectionActivity.class));
                break;
    }

    ......
}

看了這段代碼,大家應(yīng)該直到為什么要設(shè)置tag了吧子刮。原因就是希望共用onRootClick方法客叉。有同學(xué)會問,為什么不用id呢话告?那是因?yàn)椋恳粋€item用的是同一個xml布局卵慰,也就是用的同一個id沙郭,所以這里不能像以往一樣用id。

  • 常用場景init()

到這里MyOnLineView已經(jīng)封裝好了裳朋,但是為了方便病线,我們可以為使用頻率很高的一些情況提供快速的創(chuàng)建方法,就想“我的”頁面的item鲤嫡。大家可以更具自己項(xiàng)目不同來做調(diào)整送挑。

 /**
     * 默認(rèn)情況下的樣子  icon + 文字 + 右箭頭 + 下分割線
     *
     * @param iconRes     icon圖片
     * @param textContent 文字內(nèi)容
     */
    public MyOneLineView init(int iconRes, String textContent) {
        init();
        showDivider(false, true);
        setLeftIcon(iconRes);
        setTextContent(textContent);
        showEdit(false);
        setRightText("");
        showArrow(true);
        return this;
    }

    /**
     * 我的頁面每一行  icon + 文字 + 右箭頭(顯示/不顯示) + 右箭頭左邊的文字(顯示/不顯示)+ 下分割線
     *
     * @param iconRes     icon圖片
     * @param textContent 文字內(nèi)容
     */
    public MyOneLineView initMine(int iconRes, String textContent, String textRight, boolean showArrow) {
        init(iconRes, textContent);
        setRightText(textRight);
        showArrow(showArrow);
        return this;
    }


    /**
     * icon + 文字 + edit + 下分割線
     *
     * @return
     */
    public MyOneLineView initItemWidthEdit(int iconRes, String textContent, String editHint) {
        init(iconRes, textContent);
        showEdit(true);
        setEditHint(editHint);
        showArrow(false);
        return this;
    }

總結(jié)

文章到此結(jié)束,希望這篇文章對大家有所幫助暖眼,提高開發(fā)效率惕耕。
完整代碼:https://github.com/chaohengxing/MyOneLineView.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市诫肠,隨后出現(xiàn)的幾起案子司澎,更是在濱河造成了極大的恐慌,老刑警劉巖栋豫,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挤安,死亡現(xiàn)場離奇詭異,居然都是意外死亡丧鸯,警方通過查閱死者的電腦和手機(jī)蛤铜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丛肢,“玉大人围肥,你說我怎么就攤上這事》湓酰” “怎么了虐先?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長派敷。 經(jīng)常有香客問我蛹批,道長撰洗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任腐芍,我火速辦了婚禮差导,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猪勇。我一直安慰自己设褐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布泣刹。 她就那樣靜靜地躺著助析,像睡著了一般。 火紅的嫁衣襯著肌膚如雪椅您。 梳的紋絲不亂的頭發(fā)上外冀,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音掀泳,去河邊找鬼雪隧。 笑死,一個胖子當(dāng)著我的面吹牛员舵,可吹牛的內(nèi)容都是我干的脑沿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼马僻,長吁一口氣:“原來是場噩夢啊……” “哼庄拇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起韭邓,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤丛忆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后仍秤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熄诡,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年诗力,在試婚紗的時候發(fā)現(xiàn)自己被綠了凰浮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡苇本,死狀恐怖袜茧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓣窄,我是刑警寧澤笛厦,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站俺夕,受9級特大地震影響裳凸,放射性物質(zhì)發(fā)生泄漏贱鄙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一姨谷、第九天 我趴在偏房一處隱蔽的房頂上張望逗宁。 院中可真熱鬧,春花似錦梦湘、人聲如沸瞎颗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哼拔。三九已至,卻和暖如春瓣颅,著一層夾襖步出監(jiān)牢的瞬間倦逐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工弄捕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人导帝。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓守谓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親您单。 傳聞我的和親對象是個殘疾皇子斋荞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

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