Android DataBinding 需要一些代码来完成这项工作
前面的步骤 1 可以被你所有的项目复用,后面的步骤 2 和 3 都是布局资源文件,就像 WPF 做的一样
步骤1.为所有AbsListView定义一个BindingAdapter类,这个类可以被你的其他项目AbsListView重用
public class AbsListViewBindingAdapter {
@BindingAdapter(value = {"android:items", "android:itemTemplate", "android:dropDownItemTemplate"}, requireAll = false)
public static <T> void setListAdapter(AbsListView view, List<T> items, @LayoutRes int itemTemplateLayout, @LayoutRes int dropDownItemTemplateLayout) {
final ListAdapter oldAdapter = view.getAdapter();
if (oldAdapter instanceof ObservableListAdapter) {
((ObservableListAdapter<T>) oldAdapter).setParams(items, itemTemplateLayout, dropDownItemTemplateLayout);
} else {
view.setAdapter(new ObservableListAdapter<>(view.getContext(), items, itemTemplateLayout, dropDownItemTemplateLayout));
}
}
@BindingAdapter(value = {"android:items", "android:itemTemplate", "android:dropDownItemTemplate"}, requireAll = false)
public static <T> void setListAdapter(AbsListView view, T[] items, @LayoutRes int itemTemplateLayout, @LayoutRes int dropDownItemTemplateLayout) {
setListAdapter(view, items != null ? Arrays.asList(items) : null, itemTemplateLayout, dropDownItemTemplateLayout);
}
@BindingAdapter(value = {"android:items", "android:itemTemplate", "android:dropDownItemTemplate"}, requireAll = false)
public static <T> void setListAdapter(AbsListView view, int[] items, @LayoutRes int itemTemplateLayout, @LayoutRes int dropDownItemTemplateLayout) {
setListAdapter(view, items != null ? IntStream.of(items).boxed().collect(Collectors.toList()) : null, itemTemplateLayout, dropDownItemTemplateLayout);
}
static class ObservableListAdapter<T> extends BaseAdapter {
private List<T> mList;
private int mDropDownResourceId = 0;
private int mResourceId = 0;
private final LayoutInflater mLayoutInflater;
final ObservableList.OnListChangedCallback mListChangedCallback = new ObservableList.OnListChangedCallback() {
@Override
public void onChanged(ObservableList observableList) {
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(ObservableList observableList, int i, int i1) {
notifyDataSetChanged();
}
@Override
public void onItemRangeInserted(ObservableList observableList, int i, int i1) {
notifyDataSetChanged();
}
@Override
public void onItemRangeMoved(ObservableList observableList, int i, int i1, int i2) {
notifyDataSetChanged();
}
@Override
public void onItemRangeRemoved(ObservableList observableList, int i, int i1) {
notifyDataSetChanged();
}
};
public ObservableListAdapter(Context context, List<T> list, @LayoutRes int itemTemplate, @LayoutRes int dropDownItemTemplate) {
mLayoutInflater = LayoutInflater.from(context);
setParams(list, itemTemplate, dropDownItemTemplate);
}
public void setParams(List<T> list, @LayoutRes int itemTemplate, @LayoutRes int dropDownItemTemplate) {
boolean requireNotifyChange = mResourceId != itemTemplate || mDropDownResourceId != dropDownItemTemplate || !Objects.equals(list, mList);
mResourceId = itemTemplate;
mDropDownResourceId = dropDownItemTemplate;
if (!Objects.equals(list, mList)) {
if (mList instanceof ObservableList) {
((ObservableList) mList).removeOnListChangedCallback(mListChangedCallback);
}
mList = list;
if (mList instanceof ObservableList) {
((ObservableList) mList).addOnListChangedCallback(mListChangedCallback);
}
}
if (requireNotifyChange) {
notifyDataSetChanged();
}
}
@Override
public int getCount() {
return (mList != null) ? mList.size() : 0;
}
@Override
public T getItem(int position) {
return mList != null ? mList.get(position) : null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getViewForResource(mResourceId, position, convertView, parent);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getViewForResource(mDropDownResourceId, position, convertView, parent);
}
public View getViewForResource(int resourceId, int position, View convertView, ViewGroup parent) {
final ViewDataBinding binding = (convertView != null)
? DataBindingUtil.getBinding(convertView)
: DataBindingUtil.inflate(mLayoutInflater, resourceId, parent, false);
binding.setVariable(BR.viewModel, getItem(position));
return binding.getRoot();
}
}
}
步骤 2. 像 WPF 一样声明你自己的项目模板,并且你必须声明你的 viewModel 数据类型,因为 Android 总是使用静态类型绑定,但 WPF 使用动态/反射类型绑定,请确保为方便起见,变量 viewModel(= WPF 的 DataContext)在数据部分声明
例如:java.io.File
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="java.io.File" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:text='@{viewModel.directory ? "Folder" : "File"}'
android:textSize="20sp" />
<TextView
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@{viewModel.name}"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{viewModel.length()+ ""}'
android:textSize="20sp" />
</LinearLayout>
</layout>
步骤 3. 将您的项目模板添加到您的 ListView 布局文件中,此示例列出了外部存储目录中的所有文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.os.Environment" />
<variable
name="viewModel"
type="com.mycompany.databindingtest.MainActivity.ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:dropDownItemTemplate="@{@layout/file_list_item_template}"
android:itemTemplate="@{@layout/file_list_item_template}"
android:items="@{Environment.externalStorageDirectory.listFiles()}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
完整源代码:sample3