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);