1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 package android.support.v17.leanback.widget; 15 16 import android.view.View; 17 import android.view.ViewGroup; 18 19 /** 20 * A Presenter is used to generate {@link View}s and bind Objects to them on 21 * demand. It is closely related to concept of an {@link 22 * android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, but is 23 * not position-based. 24 * 25 * <p> 26 * A trivial Presenter that takes a string and renders it into a {@link 27 * android.widget.TextView TextView}: 28 * 29 * <pre class="prettyprint"> 30 * public class StringTextViewPresenter extends Presenter { 31 * // This class does not need a custom ViewHolder, since it does not use 32 * // a complex layout. 33 * 34 * {@literal @}Override 35 * public ViewHolder onCreateViewHolder(ViewGroup parent) { 36 * return new ViewHolder(new TextView(parent.getContext())); 37 * } 38 * 39 * {@literal @}Override 40 * public void onBindViewHolder(ViewHolder viewHolder, Object item) { 41 * String str = (String) item; 42 * TextView textView = (TextView) viewHolder.mView; 43 * 44 * textView.setText(item); 45 * } 46 * 47 * {@literal @}Override 48 * public void onUnbindViewHolder(ViewHolder viewHolder) { 49 * // Nothing to unbind for TextView, but if this viewHolder had 50 * // allocated bitmaps, they can be released here. 51 * } 52 * } 53 * </pre> 54 */ 55 public abstract class Presenter { 56 /** 57 * ViewHolder can be subclassed and used to cache any view accessors needed 58 * to improve binding performance (for example, results of findViewById) 59 * without needing to subclass a View. 60 */ 61 public static class ViewHolder { 62 public final View view; 63 ViewHolder(View view)64 public ViewHolder(View view) { 65 this.view = view; 66 } 67 } 68 69 /** 70 * Creates a new {@link View}. 71 */ onCreateViewHolder(ViewGroup parent)72 public abstract ViewHolder onCreateViewHolder(ViewGroup parent); 73 74 /** 75 * Binds a {@link View} to an item. 76 */ onBindViewHolder(ViewHolder viewHolder, Object item)77 public abstract void onBindViewHolder(ViewHolder viewHolder, Object item); 78 79 /** 80 * Unbinds a {@link View} from an item. Any expensive references may be 81 * released here, and any fields that are not bound for every item should be 82 * cleared here. 83 */ onUnbindViewHolder(ViewHolder viewHolder)84 public abstract void onUnbindViewHolder(ViewHolder viewHolder); 85 86 /** 87 * Called when a view created by this presenter has been attached to a window. 88 * 89 * <p>This can be used as a reasonable signal that the view is about to be seen 90 * by the user. If the adapter previously freed any resources in 91 * {@link #onViewDetachedFromWindow(ViewHolder)} 92 * those resources should be restored here.</p> 93 * 94 * @param holder Holder of the view being attached 95 */ onViewAttachedToWindow(ViewHolder holder)96 public void onViewAttachedToWindow(ViewHolder holder) { 97 } 98 99 /** 100 * Called when a view created by this presenter has been detached from its window. 101 * 102 * <p>Becoming detached from the window is not necessarily a permanent condition; 103 * the consumer of an presenter's views may choose to cache views offscreen while they 104 * are not visible, attaching and detaching them as appropriate.</p> 105 * 106 * Any view property animations should be cancelled here or the view may fail 107 * to be recycled. 108 * 109 * @param holder Holder of the view being detached 110 */ onViewDetachedFromWindow(ViewHolder holder)111 public void onViewDetachedFromWindow(ViewHolder holder) { 112 // If there are view property animations running then RecyclerView won't recycle. 113 cancelAnimationsRecursive(holder.view); 114 } 115 116 /** 117 * Utility method for removing all running animations on a view. 118 */ cancelAnimationsRecursive(View view)119 protected static void cancelAnimationsRecursive(View view) { 120 if (view != null && view.hasTransientState()) { 121 view.animate().cancel(); 122 if (view instanceof ViewGroup) { 123 final int count = ((ViewGroup) view).getChildCount(); 124 for (int i = 0; view.hasTransientState() && i < count; i++) { 125 cancelAnimationsRecursive(((ViewGroup) view).getChildAt(i)); 126 } 127 } 128 } 129 } 130 131 /** 132 * Called to set a click listener for the given view holder. 133 * 134 * The default implementation sets the click listener on the root view in the view holder. 135 * If the root view isn't focusable this method should be overridden to set the listener 136 * on the appropriate focusable child view(s). 137 * 138 * @param holder The view holder containing the view(s) on which the listener should be set. 139 * @param listener The click listener to be set. 140 */ setOnClickListener(ViewHolder holder, View.OnClickListener listener)141 public void setOnClickListener(ViewHolder holder, View.OnClickListener listener) { 142 holder.view.setOnClickListener(listener); 143 } 144 } 145