VerticalGridPresenter.java revision 53a46b5723708bbb223084ebf3a4fbf6ea4616ae
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 */ 14package android.support.v17.leanback.widget; 15 16import android.support.v17.leanback.R; 17import android.view.LayoutInflater; 18import android.view.View; 19import android.view.ViewGroup; 20import android.view.ViewGroup.LayoutParams; 21import android.util.Log; 22 23/** 24 * A presenter that renders objects in a vertical grid. 25 * 26 */ 27public class VerticalGridPresenter extends Presenter { 28 private static final String TAG = "GridPresenter"; 29 private static final boolean DEBUG = false; 30 31 public static class ViewHolder extends Presenter.ViewHolder { 32 final ItemBridgeAdapter mItemBridgeAdapter = new ItemBridgeAdapter(); 33 final VerticalGridView mGridView; 34 boolean mInitialized; 35 36 public ViewHolder(VerticalGridView view) { 37 super(view); 38 mGridView = view; 39 } 40 41 public VerticalGridView getGridView() { 42 return mGridView; 43 } 44 } 45 46 private int mNumColumns = -1; 47 private int mZoomFactor; 48 private boolean mShadowEnabled = true; 49 private OnItemClickedListener mOnItemClickedListener; 50 private OnItemSelectedListener mOnItemSelectedListener; 51 private OnItemViewSelectedListener mOnItemViewSelectedListener; 52 private OnItemViewClickedListener mOnItemViewClickedListener; 53 54 public VerticalGridPresenter() { 55 this(FocusHighlight.ZOOM_FACTOR_MEDIUM); 56 } 57 58 public VerticalGridPresenter(int zoomFactor) { 59 mZoomFactor = zoomFactor; 60 } 61 62 /** 63 * Sets the number of columns in the vertical grid. 64 */ 65 public void setNumberOfColumns(int numColumns) { 66 if (numColumns < 0) { 67 throw new IllegalArgumentException("Invalid number of columns"); 68 } 69 if (mNumColumns != numColumns) { 70 mNumColumns = numColumns; 71 } 72 } 73 74 /** 75 * Returns the number of columns in the vertical grid. 76 */ 77 public int getNumberOfColumns() { 78 return mNumColumns; 79 } 80 81 /** 82 * Enable or disable child shadow. 83 * This is not only for enable/disable default shadow implementation but also subclass must 84 * respect this flag. 85 */ 86 public final void setShadowEnabled(boolean enabled) { 87 mShadowEnabled = enabled; 88 } 89 90 /** 91 * Returns true if child shadow is enabled. 92 * This is not only for enable/disable default shadow implementation but also subclass must 93 * respect this flag. 94 */ 95 public final boolean getShadowEnabled() { 96 return mShadowEnabled; 97 } 98 99 /** 100 * Returns true if opticalBounds is supported (SDK >= 18) so that default shadow 101 * is applied to each individual child of {@link VerticalGridView}. 102 * Subclass may return false to disable. 103 */ 104 public boolean isUsingDefaultShadow() { 105 return ShadowOverlayContainer.supportsShadow(); 106 } 107 108 /** 109 * Returns true if SDK >= L, where Z shadow is enabled so that Z order is enabled 110 * on each child of vertical grid. If subclass returns false in isUsingDefaultShadow() 111 * and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false. 112 */ 113 public boolean isUsingZOrder() { 114 return ShadowHelper.getInstance().usesZShadow(); 115 } 116 117 final boolean needsDefaultShadow() { 118 return isUsingDefaultShadow() && getShadowEnabled(); 119 } 120 121 @Override 122 public final ViewHolder onCreateViewHolder(ViewGroup parent) { 123 ViewHolder vh = createGridViewHolder(parent); 124 vh.mInitialized = false; 125 initializeGridViewHolder(vh); 126 if (!vh.mInitialized) { 127 throw new RuntimeException("super.initializeGridViewHolder() must be called"); 128 } 129 return vh; 130 } 131 132 /** 133 * Subclass may override this to inflate a different layout. 134 */ 135 protected ViewHolder createGridViewHolder(ViewGroup parent) { 136 View root = LayoutInflater.from(parent.getContext()).inflate( 137 R.layout.lb_vertical_grid, parent, false); 138 return new ViewHolder((VerticalGridView) root.findViewById(R.id.browse_grid)); 139 } 140 141 private ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() { 142 @Override 143 public View createWrapper(View root) { 144 ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext()); 145 wrapper.setLayoutParams( 146 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 147 wrapper.initialize(needsDefaultShadow(), false); 148 return wrapper; 149 } 150 @Override 151 public void wrap(View wrapper, View wrapped) { 152 ((ShadowOverlayContainer) wrapper).wrap(wrapped); 153 } 154 }; 155 156 /** 157 * Called after a {@link VerticalGridPresenter.ViewHolder} is created. 158 * Subclasses may override this method and start by calling 159 * super.initializeGridViewHolder(ViewHolder). 160 * 161 * @param vh The ViewHolder to initialize for the vertical grid. 162 */ 163 protected void initializeGridViewHolder(ViewHolder vh) { 164 if (mNumColumns == -1) { 165 throw new IllegalStateException("Number of columns must be set"); 166 } 167 if (DEBUG) Log.v(TAG, "mNumColumns " + mNumColumns); 168 vh.getGridView().setNumColumns(mNumColumns); 169 vh.mInitialized = true; 170 171 if (needsDefaultShadow()) { 172 vh.mItemBridgeAdapter.setWrapper(mWrapper); 173 ShadowOverlayContainer.prepareParentForShadow(vh.getGridView()); 174 ((ViewGroup) vh.view).setClipChildren(false); 175 } 176 vh.getGridView().setFocusDrawingOrderEnabled(!isUsingZOrder()); 177 FocusHighlightHelper.setupBrowseItemFocusHighlight(vh.mItemBridgeAdapter, mZoomFactor); 178 179 final ViewHolder gridViewHolder = vh; 180 vh.getGridView().setOnChildSelectedListener(new OnChildSelectedListener() { 181 @Override 182 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 183 selectChildView(gridViewHolder, view); 184 } 185 }); 186 187 vh.mItemBridgeAdapter.setAdapterListener(new ItemBridgeAdapter.AdapterListener() { 188 @Override 189 public void onBind(final ItemBridgeAdapter.ViewHolder itemViewHolder) { 190 // Only when having an OnItemClickListner, we attach the OnClickListener. 191 if (getOnItemClickedListener() != null || getOnItemViewClickedListener() != null) { 192 final View itemView = itemViewHolder.mHolder.view; 193 itemView.setOnClickListener(new View.OnClickListener() { 194 @Override 195 public void onClick(View view) { 196 if (getOnItemClickedListener() != null) { 197 // Row is always null 198 getOnItemClickedListener().onItemClicked(itemViewHolder.mItem, 199 null); 200 } 201 if (getOnItemViewClickedListener() != null) { 202 // Row is always null 203 getOnItemViewClickedListener().onItemClicked( 204 itemViewHolder.mHolder, itemViewHolder.mItem, null, null); 205 } 206 } 207 }); 208 } 209 } 210 211 @Override 212 public void onUnbind(ItemBridgeAdapter.ViewHolder viewHolder) { 213 if (getOnItemClickedListener() != null || getOnItemViewClickedListener() != null) { 214 viewHolder.mHolder.view.setOnClickListener(null); 215 } 216 } 217 218 @Override 219 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) { 220 viewHolder.itemView.setActivated(true); 221 } 222 }); 223 } 224 225 @Override 226 public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) { 227 if (DEBUG) Log.v(TAG, "onBindViewHolder " + item); 228 ViewHolder vh = (ViewHolder) viewHolder; 229 vh.mItemBridgeAdapter.setAdapter((ObjectAdapter) item); 230 vh.getGridView().setAdapter(vh.mItemBridgeAdapter); 231 } 232 233 @Override 234 public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { 235 if (DEBUG) Log.v(TAG, "onUnbindViewHolder"); 236 ViewHolder vh = (ViewHolder) viewHolder; 237 vh.mItemBridgeAdapter.setAdapter(null); 238 vh.getGridView().setAdapter(null); 239 } 240 241 /** 242 * Sets the item selected listener. 243 * Since this is a grid the row parameter is always null. 244 * @deprecated Use {@link #setOnItemViewSelectedListener(OnItemViewSelectedListener)} 245 */ 246 public final void setOnItemSelectedListener(OnItemSelectedListener listener) { 247 mOnItemSelectedListener = listener; 248 } 249 250 /** 251 * Returns the item selected listener. 252 * @deprecated Use {@link #getOnItemViewSelectedListener()} 253 */ 254 public final OnItemSelectedListener getOnItemSelectedListener() { 255 return mOnItemSelectedListener; 256 } 257 258 /** 259 * Sets the item selected listener. 260 * Since this is a grid the row parameter is always null. 261 */ 262 public final void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) { 263 mOnItemViewSelectedListener = listener; 264 } 265 266 /** 267 * Returns the item selected listener. 268 */ 269 public final OnItemViewSelectedListener getOnItemViewSelectedListener() { 270 return mOnItemViewSelectedListener; 271 } 272 273 /** 274 * Sets the item clicked listener. 275 * OnItemClickedListener will override {@link View.OnClickListener} that 276 * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}. 277 * So in general, developer should choose one of the listeners but not both. 278 * @deprecated Use {@link #setOnItemViewClickedListener(OnItemViewClickedListener)} 279 */ 280 public final void setOnItemClickedListener(OnItemClickedListener listener) { 281 mOnItemClickedListener = listener; 282 } 283 284 /** 285 * Sets the item clicked listener. 286 * OnItemViewClickedListener will override {@link View.OnClickListener} that 287 * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}. 288 * So in general, developer should choose one of the listeners but not both. 289 */ 290 public final void setOnItemViewClickedListener(OnItemViewClickedListener listener) { 291 mOnItemViewClickedListener = listener; 292 } 293 294 /** 295 * Returns the item clicked listener. 296 * @deprecated Use {@link #getOnItemViewClickedListener()} 297 */ 298 public final OnItemClickedListener getOnItemClickedListener() { 299 return mOnItemClickedListener; 300 } 301 302 /** 303 * Returns the item clicked listener. 304 */ 305 public final OnItemViewClickedListener getOnItemViewClickedListener() { 306 return mOnItemViewClickedListener; 307 } 308 309 private void selectChildView(ViewHolder vh, View view) { 310 if (getOnItemSelectedListener() != null) { 311 ItemBridgeAdapter.ViewHolder ibh = (view == null) ? null : 312 (ItemBridgeAdapter.ViewHolder) vh.getGridView().getChildViewHolder(view); 313 if (ibh == null) { 314 getOnItemSelectedListener().onItemSelected(null, null); 315 } else { 316 getOnItemSelectedListener().onItemSelected(ibh.mItem, null); 317 } 318 } 319 if (getOnItemViewSelectedListener() != null) { 320 ItemBridgeAdapter.ViewHolder ibh = (view == null) ? null : 321 (ItemBridgeAdapter.ViewHolder) vh.getGridView().getChildViewHolder(view); 322 if (ibh == null) { 323 getOnItemViewSelectedListener().onItemSelected(null, null, null, null); 324 } else { 325 getOnItemViewSelectedListener().onItemSelected(ibh.mHolder, ibh.mItem, null, null); 326 } 327 } 328 } 329} 330