用RecyclerView實現(xiàn)Form表單 靈活可復用 給你一個新思路-MultiItem進階

前言

本文是MultiItem系列的進階文章社牲,講解如何利用RecyclerView實現(xiàn)Form表單陶夜,在日常開發(fā)中多數(shù)人還是使用普通布局方式實現(xiàn)二跋,這種方案比較直觀也很簡單,但是如果表單業(yè)務較多巾兆,并且易變,很多弊端就會顯現(xiàn)虎囚,不過這正是使用RecyclerView實現(xiàn)的優(yōu)勢所在角塑,可以自定義一套通用的輸入類型的ItemInput組件,既靈活又可復用淘讥。MultiItem特點:

  • 直接使用業(yè)務中的實體類為RecyclerView Adapter設置數(shù)據(jù)源圃伶,不需要做任何封裝
  • RecyclerView Adapter零編碼,解放了復雜的Adapter
  • 支持DataBinding蒲列,讓你清爽的編寫列表代碼
  • 支持Form表單錄入窒朋,懶加載易復用,支持DataBinding蝗岖、隱藏域侥猩、輸入內(nèi)容驗證及是否變化

源碼地址

Github地址:https://github.com/free46000/MultiItem,請大家多多關注抵赢。

系列文章

效果截圖

Form表單效果
Form表單效果

Form表單提交
Form表單提交

用法

使用方法

首先初始化InputItemAdapter欺劳,然后添加實現(xiàn)ItemInput接口的數(shù)據(jù)源,相關代碼:
注:類庫中已提供了一些實現(xiàn)接口的基類如:BaseItemInput DataBindItemInput铅鲤,使用時直接繼承基類就可以划提,

protected void initViews() {
    //初始化adapter
    adapter = new InputItemAdapter();
    List<Object> list = new ArrayList<>();
    
    //姓名和性別錄入Item,一個錄入item對應多個提交的值{"name":"","sex":""}
    list.add(new ItemNameAndSex());
    
    //普通的EditText錄入Item
    list.add(new ItemEdit("height").setName("身高:"));
    list.add(new ItemEdit("weight").setName("體重:"));
    list.add(new ItemEdit("age").setName("年齡:"));
    list.add(new ItemEdit("default").setName("國家:").setDefValue("中國"));
    
    //利用DataBinding的錄入Item
    list.add(new ItemInfoDataBind("info").setName("介紹:"));
    
    //添加user id對應的隱藏域的Item(用戶不可見)
    adapter.addHiddenItem("id", "隱藏域中攜帶id");
    adapter.setDataItems(list);
    
    recyclerView.setAdapter(adapter);
}

接下來展示提交表單的相關代碼邢享,提交時可以自動組裝數(shù)據(jù)鹏往,另外還提供了一些有用的api,詳見代碼注釋:

public void submit() {
    //通過adapter.isValueChange()判斷表單內(nèi)容是否改變
    //通過adapter.isValueValid()判斷表單內(nèi)容是否有效
    //通過adapter.getInputJson()直接獲取表單錄入Json骇塘,還有獲取錄入Map的方法
    String tipTxt = "表單內(nèi)容" + (adapter.isValueChange() ? " 已經(jīng) " : " 沒有 ") +
            "被用戶改變伊履!\n表單  " + (adapter.isValueValid() ? " 已經(jīng) " : " 沒有 ") +
            "通過驗證!\n自動組裝的表單內(nèi)容為:\n";
    
    //表單內(nèi)容json字符串款违,也可以通過Gson或FastJson等對字符串反序列化成實體對象
    String valueTxt = adapter.getInputJson().toString(4);
    new AlertDialog.Builder(this).setTitle("提交").setMessage(tipTxt + valueTxt)
            .setPositiveButton(R.string.confirm, null).show();
}

ItemInput普通錄入ItemEdit

我們先來看看普通的錄入ItemEdit的編寫方式唐瀑,它繼承了BaseItemInput基類,下面貼出一些關鍵的需要覆寫的方法奠货,作用詳見注釋:

public class ItemEdit extends BaseItemInput<ItemEdit> {
    /**
     * @param key 錄入對應key
     */
    public ItemEdit(String key) {
        super(key);
    }
    
    @Override
    public String getValue() {
        //返回錄入的值介褥,和{@link #getKey()}一起組裝為Map  如果為null則不組裝
        return editText == null ? defValue : editText.getText().toString();
    }
    
    @Override
    public boolean isValueValid() {
        //錄入的值不為空則有效;其它無效
        return !TextUtils.isEmpty(getValue());
    }
    
    @Override
    protected void initInputView(BaseViewHolder holder) {
        //初始化Input視圖,由于Input視圖不可以復用柔滔,所以直接在初始化視圖時設置好相關內(nèi)容即可
        TextView nameText = getView(holder.itemView, R.id.text);
        nameText.setText(name);
    
        editText = getView(holder.itemView, R.id.editText);
        editText.setHint(hint);
        editText.setText(defValue);
    }
    
    ...
}

ItemInput一對多錄入ItemNameAndSex

上面我們已經(jīng)看了普通錄入的實現(xiàn)溢陪,一對多錄入的方式需要在上面的基礎上,增加一些定制化的實現(xiàn)睛廊,所以和普通錄入重復的代碼就不貼出來了形真,只貼出一些關鍵的需要覆寫的方法,作用詳見注釋:

public class ItemNameAndSex extends BaseItemInput<ItemNameAndSex> {
    //本例中需要返回兩組key-value所以去覆寫getValueMap()
     @Override
    public Object getValue() {
        //在本方法中返回兩個值的組合超全,作用是為判斷表單的值是否被改變提供依據(jù)
        if (nameEdit == null) {
            return null;
        }
        return nameEdit.getText().toString() + sexRadio.getCheckedRadioButtonId();
    }

    @Override
    public boolean isValueValid() {
        //如果名字輸入框錄入的值不為空則有效咆霜;其它無效
        return nameEdit != null && !TextUtils.isEmpty(nameEdit.getText().toString());
    }

    @Override
    public Map<String, Object> getValueMap() {
        if (nameEdit == null) {
            return null;
        }

        //此處自己組裝Map{name:name,sex:sex}并返回,這樣可以達到一個Item返回兩組值的效果
        Map<String, Object> valueMap = new HashMap<>(2);
        valueMap.put("name", nameEdit.getText().toString());
        int sexStrResId = sexRadio.getCheckedRadioButtonId() == R.id.man ? R.string.man : R.string.woman;
        valueMap.put("sex", nameEdit.getContext().getString(sexStrResId));

        return valueMap;
    }
    
    ...
}    

ItemInput 數(shù)據(jù)綁定錄入ItemInfoDataBind

接下來我們看看數(shù)據(jù)綁定方式嘶朱,貼出關鍵代碼:

public class ItemInfoDataBind extends DataBindItemInput<ItemInfoDataBind> {
    
     @Override
    protected void initInputView(ViewDataBinding dataBinding) {
        //把自身實例對象通過ViewDataBinding綁定到視圖中
        dataBinding.setVariable(BR.itemData, this);
    }    
    ...
}

通過以上代碼我們不難發(fā)現(xiàn)數(shù)據(jù)綁定技術對代碼的改善蛾坯,java代碼中已經(jīng)沒有了和View層相關的邏輯代碼,直接在xml布局中就可以完成疏遏,下面貼出xml布局的關鍵代碼:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="itemData"
            type="com.freelib.multiitem.demo.input.ItemInfoDataBind"/>
    </data>

    <LinearLayout ...>
    
        <TextView
            ...
            android:text="@{itemData.name}"/>

        <EditText
            ...
            //@={}為雙向綁定用法脉课,即EditText的變化會實時更新到itemData.info屬性上
            android:text="@={itemData.info}"/>
            
    </LinearLayout>

</layout>

數(shù)據(jù)綁定的xml布局和普通寫法也沒什么差別,所以在這里再次安利下财异,大家要多多使用DataBinding,提高開發(fā)效率倘零,降低耦合度。

詳解

復用詳解

拿我們上面貼出代碼的ItemEdit來說戳寸,在正常情況下所有EditText相關的錄入項都可以使用本類即可呈驶,這樣就做到了復用。所以我們在項目中封裝一些公用組件的錄入Item后疫鹊,即使碰到大量到表單業(yè)務袖瞻,變化再多都不需要擔心,只是在InputItemAdapter添加刪除一些組件Item或者把原有組件Item的順序調(diào)整一下即可订晌,在這個過程中都不需要去碰到xml布局文件虏辫,在邏輯上也會比較清晰。

流程解析

這次實現(xiàn)相當于在原有功能的基礎上封裝了一些新的api锈拨,所以并沒有太多可以講解的地方,所以花了一個流程圖供大家參考:

Form表單流程
Form表單流程

總結

前言中也說利用RecyclerView實現(xiàn)Form表單了并不是一種主流的實現(xiàn)方式羹唠,當然會存在一些不足之處奕枢,但是比較適用于大量表單業(yè)務的客戶端中,希望大家多多交流佩微!
最后擴展一下大家的思路缝彬,其實我們可以約定好表單格式數(shù)據(jù),通過服務端下發(fā)哺眯,在客戶端做到動態(tài)表單錄入

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谷浅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌一疯,老刑警劉巖撼玄,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異墩邀,居然都是意外死亡掌猛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門眉睹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荔茬,“玉大人,你說我怎么就攤上這事竹海∧轿担” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵斋配,是天一觀的道長坊萝。 經(jīng)常有香客問我,道長许起,這世上最難降的妖魔是什么十偶? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮园细,結果婚禮上惦积,老公的妹妹穿的比我還像新娘。我一直安慰自己猛频,他們只是感情好狮崩,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹿寻,像睡著了一般睦柴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毡熏,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天坦敌,我揣著相機與錄音,去河邊找鬼痢法。 笑死狱窘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的财搁。 我是一名探鬼主播蘸炸,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尖奔!你這毒婦竟也來了搭儒?” 一聲冷哼從身側響起穷当,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎淹禾,沒想到半個月后馁菜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡稀拐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年火邓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片德撬。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡铲咨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜓洪,到底是詐尸還是另有隱情纤勒,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布隆檀,位于F島的核電站摇天,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏恐仑。R本人自食惡果不足惜泉坐,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裳仆。 院中可真熱鬧腕让,春花似錦、人聲如沸歧斟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽静袖。三九已至觉鼻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間队橙,已是汗流浹背坠陈。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留喘帚,地道東北人畅姊。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像吹由,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朱嘴,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

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