package me.tatarka.bindingcollectionadapter2; import android.databinding.ViewDataBinding; import android.support.annotation.LayoutRes; import android.util.SparseArray; /** * Provides the necessary information to bind an item in a collection to a view. This includes the * variable id and the layout as well as any extra bindings you may want to provide. * * @param <T> The item type. */ public final class ItemBinding<T> { /** * Use this constant as the variable id to not bind the item in the collection to the layout if * no data is need, like a static footer or loading indicator. */ public static final int VAR_NONE = 0; private static final int VAR_INVALID = -1; /** * Constructs an instance with the given variable id and layout. */ public static <T> ItemBinding<T> of(int variableId, @LayoutRes int layoutRes) { return new ItemBinding<T>(null).set(variableId, layoutRes); } /** * Constructs an instance with the given callback. It will be called for each item in the * collection to set the binding info. * * @see OnItemBind */ public static <T> ItemBinding<T> of(OnItemBind<T> onItemBind) { if (onItemBind == null) { throw new NullPointerException("onItemBind == null"); } return new ItemBinding<>(onItemBind); } private final OnItemBind<T> onItemBind; private int variableId; @LayoutRes private int layoutRes; private SparseArray<Object> extraBindings; private ItemBinding(OnItemBind<T> onItemBind) { this.onItemBind = onItemBind; } /** * Set the variable id and layout. This is normally called in {@link * OnItemBind#onItemBind(ItemBinding, int, Object)}. */ public final ItemBinding<T> set(int variableId, @LayoutRes int layoutRes) { this.variableId = variableId; this.layoutRes = layoutRes; return this; } /** * Set the variable id. This is normally called in {@link OnItemBind#onItemBind(ItemBinding, * int, Object)}. */ public final ItemBinding<T> variableId(int variableId) { this.variableId = variableId; return this; } /** * Set the layout. This is normally called in {@link OnItemBind#onItemBind(ItemBinding, int, * Object)}. */ public final ItemBinding<T> layoutRes(@LayoutRes int layoutRes) { this.layoutRes = layoutRes; return this; } /** * Bind an extra variable to the view with the given variable id. The same instance will be * provided to all views the binding is bound to. */ public final ItemBinding<T> bindExtra(int variableId, Object value) { if (extraBindings == null) { extraBindings = new SparseArray<>(1); } extraBindings.put(variableId, value); return this; } /** * Returns the current variable id of this binding. */ public final int variableId() { return variableId; } /** * Returns the current layout fo this binding. */ @LayoutRes public final int layoutRes() { return layoutRes; } /** * Returns the current extra binding for the given variable id or null if one isn't present. */ public final Object extraBinding(int variableId) { if (extraBindings == null) { return null; } return extraBindings.get(variableId); } /** * Updates the state of the binding for the given item and position. This is called internally * by the binding collection adapters. */ public void onItemBind(int position, T item) { if (onItemBind != null) { variableId = VAR_INVALID; layoutRes = 0; onItemBind.onItemBind(this, position, item); if (variableId == VAR_INVALID) { throw new IllegalStateException("variableId not set in onItemBind()"); } if (layoutRes == 0) { throw new IllegalStateException("layoutRes not set in onItemBind()"); } } } /** * Binds the item and extra bindings to the given binding. Returns true if anything was bound * and false otherwise. This is called internally by the binding collection adapters. * * @throws IllegalStateException if the variable id isn't present in the layout. */ public boolean bind(ViewDataBinding binding, T item) { if (variableId == VAR_NONE) { return false; } boolean result = binding.setVariable(variableId, item); if (!result) { Utils.throwMissingVariable(binding, variableId, layoutRes); } if (extraBindings != null) { for (int i = 0, size = extraBindings.size(); i < size; i++) { int variableId = extraBindings.keyAt(i); Object value = extraBindings.valueAt(i); if (variableId != VAR_NONE) { binding.setVariable(variableId, value); } } } return true; } }