/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package android.support.v17.leanback.widget; import android.view.View; import android.view.ViewGroup; /** * A Presenter is used to generate {@link View}s and bind Objects to them on * demand. It is closely related to concept of an {@link * android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, but is * not position-based. * *

* A trivial Presenter that takes a string and renders it into a {@link * android.widget.TextView TextView}: * *

 * public class StringTextViewPresenter extends Presenter {
 *     // This class does not need a custom ViewHolder, since it does not use
 *     // a complex layout.
 *
 *     {@literal @}Override
 *     public ViewHolder onCreateViewHolder(ViewGroup parent) {
 *         return new ViewHolder(new TextView(parent.getContext()));
 *     }
 *
 *     {@literal @}Override
 *     public void onBindViewHolder(ViewHolder viewHolder, Object item) {
 *         String str = (String) item;
 *         TextView textView = (TextView) viewHolder.mView;
 *
 *         textView.setText(item);
 *     }
 *
 *     {@literal @}Override
 *     public void onUnbindViewHolder(ViewHolder viewHolder) {
 *         // Nothing to unbind for TextView, but if this viewHolder had
 *         // allocated bitmaps, they can be released here.
 *     }
 * }
 * 
*/ public abstract class Presenter { /** * ViewHolder can be subclassed and used to cache any view accessors needed * to improve binding performance (for example, results of findViewById) * without needing to subclass a View. */ public static class ViewHolder { public final View view; public ViewHolder(View view) { this.view = view; } } /** * Creates a new {@link View}. */ public abstract ViewHolder onCreateViewHolder(ViewGroup parent); /** * Binds a {@link View} to an item. */ public abstract void onBindViewHolder(ViewHolder viewHolder, Object item); /** * Unbinds a {@link View} from an item. Any expensive references may be * released here, and any fields that are not bound for every item should be * cleared here. */ public abstract void onUnbindViewHolder(ViewHolder viewHolder); /** * Called when a view created by this presenter has been attached to a window. * *

This can be used as a reasonable signal that the view is about to be seen * by the user. If the adapter previously freed any resources in * {@link #onViewDetachedFromWindow(ViewHolder)} * those resources should be restored here.

* * @param holder Holder of the view being attached */ public void onViewAttachedToWindow(ViewHolder holder) { } /** * Called when a view created by this presenter has been detached from its window. * *

Becoming detached from the window is not necessarily a permanent condition; * the consumer of an presenter's views may choose to cache views offscreen while they * are not visible, attaching and detaching them as appropriate.

* * Any view property animations should be cancelled here or the view may fail * to be recycled. * * @param holder Holder of the view being detached */ public void onViewDetachedFromWindow(ViewHolder holder) { // If there are view property animations running then RecyclerView won't recycle. cancelAnimationsRecursive(holder.view); } /** * Utility method for removing all running animations on a view. */ protected static void cancelAnimationsRecursive(View view) { if (view != null && view.hasTransientState()) { view.animate().cancel(); if (view instanceof ViewGroup) { final int count = ((ViewGroup) view).getChildCount(); for (int i = 0; view.hasTransientState() && i < count; i++) { cancelAnimationsRecursive(((ViewGroup) view).getChildAt(i)); } } } } /** * Called to set a click listener for the given view holder. * * The default implementation sets the click listener on the root view in the view holder. * If the root view isn't focusable this method should be overridden to set the listener * on the appropriate focusable child view(s). * * @param holder The view holder containing the view(s) on which the listener should be set. * @param listener The click listener to be set. */ public void setOnClickListener(ViewHolder holder, View.OnClickListener listener) { holder.view.setOnClickListener(listener); } }