Skip to content

Instantly share code, notes, and snippets.

@williamwebb
Last active January 20, 2023 13:05
Show Gist options
  • Save williamwebb/eeefd80b8177b3d67fc4 to your computer and use it in GitHub Desktop.
Save williamwebb/eeefd80b8177b3d67fc4 to your computer and use it in GitHub Desktop.
RecyclerView & Adapter init in XML
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BindingAdapter">
<attr name="binding_layout" format="reference"/>
<attr name="binding_variable" format="string"/>
<attr name="binding_data" format="string"/>
</declare-styleable>
</resources>
package io.jug6ernaut.fln2.views;
import android.content.Context;
import android.databinding.BindingAdapter;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.support.annotation.AnyRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Created by williamwebb on 11/15/15.
* <p>
* RecycleView Adapter class for use with DataBinding.
*/
public class DataBindingAdapter<DataModel, ViewBinder extends ViewDataBinding> extends RecyclerView.Adapter<DataBindingAdapter.DataBindingViewHolder<DataModel, ViewBinder>> {
private OnViewBindCallback<ViewBinder> onViewBindCallback;
private final List<DataModel> data = new ArrayList<>();
private final int layoutId;
private final int variableId;
/**
* Constructor.
*
* @param data data to populate the Adapter with
* @param layoutId layout used by the adapter
* @param variableId variable id used to set DataBinding. Ex: BR.data
*/
public DataBindingAdapter(@NonNull List<DataModel> data, @LayoutRes int layoutId, @AnyRes int variableId) {
this.data.addAll(data);
this.layoutId = layoutId;
this.variableId = variableId;
}
/**
* Constructor.
*
* @param layoutId layout used by the adapter
* @param variableId variable id used to set DataBinding. Ex: BR.data
*/
public DataBindingAdapter(@LayoutRes int layoutId, @AnyRes int variableId) {
this(Collections.emptyList(),layoutId,variableId);
}
@Override
public DataBindingViewHolder<DataModel, ViewBinder> onCreateViewHolder(ViewGroup parent, int viewType) {
return DataBindingViewHolder.from(parent, layoutId, variableId);
}
public void setData(List<DataModel> data) {
this.data.clear();
this.data.addAll(data);
}
@Override
public void onBindViewHolder(DataBindingViewHolder<DataModel, ViewBinder> holder, int position) {
holder.bind(data.get(position));
if (onViewBindCallback != null) onViewBindCallback.onViewBind(holder.dataBinding);
}
@Override
public int getItemCount() {
return data.size();
}
/**
* Callback used to customize onBind
*
* @param callback
*/
public DataBindingAdapter setOnBindViewCallback(OnViewBindCallback<ViewBinder> callback) {
this.onViewBindCallback = callback;
return this;
}
public interface OnViewBindCallback<BinderType extends ViewDataBinding> {
void onViewBind(BinderType type);
}
static class DataBindingViewHolder<DataModel, ViewBinder extends ViewDataBinding> extends ViewHolder {
private final ViewBinder dataBinding;
private final int variableId;
static <DataModel, ViewBinder extends ViewDataBinding> DataBindingViewHolder<DataModel, ViewBinder> from(ViewGroup parent, int layoutId, int variableId) {
View v = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new DataBindingViewHolder<>(v, variableId);
}
DataBindingViewHolder(View itemView, int variableId) {
super(itemView);
this.variableId = variableId;
dataBinding = DataBindingUtil.bind(itemView);
}
void bind(DataModel data) {
dataBinding.setVariable(variableId, data);
dataBinding.executePendingBindings();
}
}
@SuppressWarnings("unchecked") @BindingAdapter({"binding_data", "binding_layout", "binding_variable"})
public static void loadImage(RecyclerView view, List binding_data, int layoutId, String bindingVariableId) {
DataBindingAdapter adapter = createBindingAdapter(view.getContext(),layoutId,bindingVariableId);
adapter.setData(binding_data);
view.setAdapter(adapter);
view.getAdapter().notifyDataSetChanged();
}
private static DataBindingAdapter createBindingAdapter(Context context, int bindingLayout, String bindingVariable) {
try {
Class BR_CLASS = Class.forName(context.getPackageName() + ".BR");
Field BR = BR_CLASS.getField(bindingVariable);
int bindingVariableId = BR.getInt(null);
return new DataBindingAdapter(bindingLayout, bindingVariableId);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
// Lint test to verify variableId is a variableId, possibly that it exist in layoutId
// public class EnumDetector extends Detector implements JavaScanner {
// …
// }
}
Example Usage all in XML!
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:databinding="http://schemas.android.com/apk/res-auto"
>
<data>
<variable
name="model"
type="io.jug6ernaut.fln2.ui.main.MainActivity.Model"/>
</data>
<android.support.v7.widget.RecyclerView
android:id="@+id/app_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:layoutManager="android.support.v7.widget.GridLayoutManager"
app:reverseLayout="false"
app:spanCount="4"
app:stackFromEnd="false"
databinding:binding_data="@{model.data}"
databinding:binding_layout="@{@layout/app_layout_grid}"
databinding:binding_variable='@{"data"}'/>
</layout>
Then regular DataBinding
ContentMainBinding binding = ContentMainBinding.bind(view);
binding.setModel(model);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment