簡化你的列表Adapter

BindingCollectionAdapter

最近看到了這個基于databing的開源庫,簡單翻譯了一下锌雀。。迅诬。
GitHub地址

一 依賴安裝

compile 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter:2.2.0'
compile 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter-recyclerview:2.2.0'

gradle 版本需要在2.3.0以上

二 使用

2.1 單視圖

你需要提供items(數(shù)據(jù)list)和ItemBinding 去綁定數(shù)據(jù)腋逆,應使用ObserableList去自動更新View,當然侈贷,如果你不需要該功能也可以使用其他類型的List惩歉。
示例ViewModel:

public class ViewModel {
  public final ObservableList<String> items = new ObservableArrayList<>();
  public final ItemBinding<String> itemBinding = ItemBinding.of(BR.item, R.layout.item);
}

然后布局綁定viewModel的items和itemBinding,如果使用RecyclerView需要綁定一個layoutManager(看示例)

<!-- 主布局 layout.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
      <import type="com.example.R" />
      <import type="me.tatarka.bindingcollectionadapter2.LayoutManagers" />
      <variable name="viewModel" type="com.example.ViewModel"/>
    </data>

    <ListView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:items="@{viewModel.items}"
      app:itemBinding="@{viewModel.itemBinding}"/>

    <android.support.v7.widget.RecyclerView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layoutManager="@{LayoutManagers.linear()}"
      app:items="@{viewModel.items}"
      app:itemBinding="@{viewModel.itemBinding}"/>

    <android.support.v4.view.ViewPager
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:items="@{viewModel.items}"
      app:itemBinding="@{viewModel.itemBinding}"/>

    <Spinner
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:items="@{viewModel.items}"
      app:itemBinding="@{viewModel.itemBinding}"
      app:itemDropDownLayout="@{R.layout.item_dropdown}"/>
</layout>

集合中的item將會通過ItemBinding綁定到子布局中

<!-- 子布局 item.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
      <variable name="item" type="String"/>
    </data>

    <TextView
      android:id="@+id/text"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="@{item}"/>
</layout>

2.2 多視圖

你可以重寫onItemBind實現(xiàn)多視圖布局俏蛮,仍使用app:itemBinding綁定數(shù)據(jù)撑蚌。

public final OnItemBind<String> onItemBind = new OnItemBind<String>() {
  @Override
  public void onItemBind(ItemBinding itemBinding, int position, String item) {
    itemBinding.set(BR.item, position == 0 ? R.layout.item_header : R.layout.item);
  }
};

如果使用的是ListView,必須使用app:itemTypeCount="@{2}來指定視圖類型數(shù)量。
注意:如果你不做任何復雜的數(shù)據(jù)搏屑,onItemBind仍會被多次調(diào)用争涌,如果你不需要綁定數(shù)據(jù),應當使用ItemBinding.VAR_NONE 作為variable的id

2.3 綁定其他變量

可以使用itemBinding.bindExtra(BR.extra, value)來為列表的子布局添加額外的變量辣恋,示例為布局額外綁定一個點擊事件

public interface OnItemClickListener {
    void onItemClick(String item);
}

OnItemClickListener listener = ...;
ItemBinding<Item> itemBinding = ItemBinding.<Item>of(BR.item, R.layout.item)
    .bindExtra(BR.listener, listener);
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
      <variable name="item" type="String"/>
      <variable name="listener" type="OnItemClickListener"/>
    </data>

    <TextView
      android:id="@+id/text"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:onClick="@{() -> listener.onItemClick(item)}"
      android:text="@{item}"/>
</layout>

2.4 額外的Adapter配置

2.4.1 ListView

通過回調(diào)為每一個子布局添加id

adapter.setItemIds(new BindingListViewAdapter.ItemIds<T>() {
  @Override
  public long getItemId(int position, T item) {
    return // Calculate item id.
  }
});

或者在布局中通過app:itemIds="@{itemIds}"來綁定亮垫。通過設置這個會使hasStableIds 返回true解幼,從而加大內(nèi)存消耗,
可以通過回調(diào)來決定是否啟用

adapter.setItemEnabled(new BindingListViewAdapter.ItemEnabled<T>() {
  @Override
  public boolean isEnabled(int position, T item) {
    return // Calculate if item is enabled.
  }
});

或者通過app:itemEnabled="@{itemEnabled}"在布局文件中綁定

2.4.2 ViewPager

通過回調(diào)為子頁面添加標題

adapter.setPageTitles(new PageTitles<T>() {
  @Override
  public CharSequence getPageTitle(int position, T item) {
    return "Page Title";
  }
});

或者通過 app:pageTitles="@{pageTitles}"為ViewPage綁定標題

2.4.3 RecyclerView

自定義view holders

adapter.setViewHolderFactory(new ViewHolderFactory() {
  @Override
  public RecyclerView.ViewHolder createViewHolder(ViewDataBinding binding) {
    return new MyCustomViewHolder(binding.getRoot());
  }
});

或者通過app:viewHolder="@{viewHolderFactory}" 綁定

2.5 直接操作View

如果你需要直接操作View包警,你可以通過自定義Adapter來實現(xiàn)

public class MyRecyclerViewAdapter<T> extends BindingRecyclerViewAdapter<T> {

  @Override
  public ViewDataBinding onCreateBinding(LayoutInflater inflater, @LayoutRes int layoutId, ViewGroup viewGroup) {
    ViewDataBinding binding = super.onCreateBinding(inflater, layoutId, viewGroup);
    Log.d(TAG, "created binding: " + binding);
    return binding;
  }

  @Override
  public void onBindBinding(ViewDataBinding binding, int bindingVariable, @LayoutRes int layoutId, int position, T item) {
    super.onBindBinding(binding, bindingVariable, layoutId, position, item);
    Log.d(TAG, "bound binding: " + binding + " at position: " + position);
  }
}

布局文件中綁定adapter

<android.support.v7.widget.RecyclerView
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layoutManager="@{LayoutManagers.linear()}"
  app:items="@{viewModel.items}"
  app:itemBinding="@{viewModel.itemBinding}"
  app:adapter="@{viewModel.adapter}"/>

2.6 OnItemBind 助手

這兒有一些OnItemBind的常見的實現(xiàn)

itemBind = new OnItemBindClass<>()
  .map(String.class, BR.name, R.layout.item_name)
  .map(Footer.class, ItemBinding.VAR_NONE, R.layout.item_footer)
  .map(Item.class, new OnItemBind<Item>() {
                       @Override
                       public void onItemBind(ItemBinding itemBinding, int position, Item item) {
                         itemBinding.clearExtras()
                                    .set(BR.item, position == 0 ? R.layout.item_header : R.layout.item)
                                    .bindExtra(BR.extra, (list.size() - 1) == position);
                       }
                     })
  .map(Object.class, ItemBinding.VAR_NONE, R.layout.item_other);

OnItemBindModel 是子布局的binding

itemBind = new OnItemBindModel<Model>();

public class Model implements ItemBindingModel {
  @Override
  public void onItemBind(ItemBinding itemBinding) {
    itemBinding.set(BR.name, R.layout.item_name);
  }
}

2.7 MergeObservableList

用于融合兩個列表

ObservableList<String> data = new ObservableArrayList<>();
MergeObservableList<String> list = new MergeObservableList<>()
  .insertItem("Header")
  .insertList(data)
  .insertItem("Footer");

data.addAll(Arrays.asList("One", "Two"));
// list => ["Header", "One", "Two", "Footer"]
data.remove("One");
// list => ["Header", "Two", "Footer"]

2.8 DiffObservableList

用于列表的更新

DiffObservableList<Item> list = new DiffObservableList(new DiffObservableList.Callback<Item>() {
    @Override
    public boolean areItemsTheSame(Item oldItem, Item newItem) {
        return oldItem.id.equals(newItem.id);
    }

    @Override
    public boolean areContentsTheSame(Item oldItem, Item newItem) {
        return oldItem.value.equals(newItem.value);
    }
});

list.update(Arrays.asList(new Item("1", "a"), new Item("2", "b1")));
list.update(Arrays.asList(new Item("2", "b2"), new Item("3", "c"), new Item("4", "d"));

線程切換

DiffObservableList<Item> list = new DiffObservableList(...);

// On background thread:
DiffUtil.DiffResult diffResult = list.calculateDiff(newItems);

// On main thread:
list.update(newItems, diffResult);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市底靠,隨后出現(xiàn)的幾起案子害晦,更是在濱河造成了極大的恐慌,老刑警劉巖暑中,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壹瘟,死亡現(xiàn)場離奇詭異,居然都是意外死亡鳄逾,警方通過查閱死者的電腦和手機稻轨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雕凹,“玉大人殴俱,你說我怎么就攤上這事∶兜郑” “怎么了线欲?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長汽摹。 經(jīng)常有香客問我李丰,道長,這世上最難降的妖魔是什么逼泣? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任趴泌,我火速辦了婚禮,結(jié)果婚禮上拉庶,老公的妹妹穿的比我還像新娘嗜憔。我一直安慰自己,他們只是感情好砍的,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布痹筛。 她就那樣靜靜地躺著,像睡著了一般廓鞠。 火紅的嫁衣襯著肌膚如雪帚稠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天床佳,我揣著相機與錄音滋早,去河邊找鬼。 笑死砌们,一個胖子當著我的面吹牛杆麸,可吹牛的內(nèi)容都是我干的搁进。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼昔头,長吁一口氣:“原來是場噩夢啊……” “哼饼问!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起揭斧,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤莱革,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后讹开,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盅视,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年旦万,在試婚紗的時候發(fā)現(xiàn)自己被綠了闹击。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡成艘,死狀恐怖赏半,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情淆两,我是刑警寧澤除破,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站琼腔,受9級特大地震影響瑰枫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丹莲,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一光坝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧甥材,春花似錦盯另、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叠萍,卻和暖如春芝发,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苛谷。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工辅鲸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腹殿。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓独悴,卻偏偏與公主長得像例书,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刻炒,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

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