VerticalGridPresenter.java revision 3cbe5c34f9710da1ab935b45f568995b12219ca2
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 onCreate(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.getViewHolder().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 onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) { 213 viewHolder.itemView.setActivated(true); 214 } 215 }); 216 } 217 218 @Override 219 public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) { 220 if (DEBUG) Log.v(TAG, "onBindViewHolder " + item); 221 ViewHolder vh = (ViewHolder) viewHolder; 222 vh.mItemBridgeAdapter.setAdapter((ObjectAdapter) item); 223 vh.getGridView().setAdapter(vh.mItemBridgeAdapter); 224 } 225 226 @Override 227 public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { 228 if (DEBUG) Log.v(TAG, "onUnbindViewHolder"); 229 ViewHolder vh = (ViewHolder) viewHolder; 230 vh.mItemBridgeAdapter.setAdapter(null); 231 vh.getGridView().setAdapter(null); 232 } 233 234 /** 235 * Sets the item selected listener. 236 * Since this is a grid the row parameter is always null. 237 */ 238 public final void setOnItemSelectedListener(OnItemSelectedListener listener) { 239 mOnItemSelectedListener = listener; 240 } 241 242 /** 243 * Returns the item selected listener. 244 */ 245 public final OnItemSelectedListener getOnItemSelectedListener() { 246 return mOnItemSelectedListener; 247 } 248 249 /** 250 * Sets the item selected listener. 251 * Since this is a grid the row parameter is always null. 252 */ 253 public final void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) { 254 mOnItemViewSelectedListener = listener; 255 } 256 257 /** 258 * Returns the item selected listener. 259 */ 260 public final OnItemViewSelectedListener getOnItemViewSelectedListener() { 261 return mOnItemViewSelectedListener; 262 } 263 264 /** 265 * Sets the item clicked listener. 266 * OnItemClickedListener will override {@link View.OnClickListener} that 267 * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}. 268 * So in general, developer should choose one of the listeners but not both. 269 */ 270 public final void setOnItemClickedListener(OnItemClickedListener listener) { 271 mOnItemClickedListener = listener; 272 } 273 274 /** 275 * Sets the item clicked listener. 276 * OnItemViewClickedListener will override {@link View.OnClickListener} that 277 * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}. 278 * So in general, developer should choose one of the listeners but not both. 279 */ 280 public final void setOnItemViewClickedListener(OnItemViewClickedListener listener) { 281 mOnItemViewClickedListener = listener; 282 } 283 284 /** 285 * Returns the item clicked listener. 286 */ 287 public final OnItemClickedListener getOnItemClickedListener() { 288 return mOnItemClickedListener; 289 } 290 291 /** 292 * Returns the item clicked listener. 293 */ 294 public final OnItemViewClickedListener getOnItemViewClickedListener() { 295 return mOnItemViewClickedListener; 296 } 297 298 private void selectChildView(ViewHolder vh, View view) { 299 if (getOnItemSelectedListener() != null) { 300 ItemBridgeAdapter.ViewHolder ibh = (view == null) ? null : 301 (ItemBridgeAdapter.ViewHolder) vh.getGridView().getChildViewHolder(view); 302 if (ibh == null) { 303 getOnItemSelectedListener().onItemSelected(null, null); 304 } else { 305 getOnItemSelectedListener().onItemSelected(ibh.mItem, null); 306 } 307 } 308 if (getOnItemViewSelectedListener() != null) { 309 ItemBridgeAdapter.ViewHolder ibh = (view == null) ? null : 310 (ItemBridgeAdapter.ViewHolder) vh.getGridView().getChildViewHolder(view); 311 if (ibh == null) { 312 getOnItemViewSelectedListener().onItemSelected(null, null, null, null); 313 } else { 314 getOnItemViewSelectedListener().onItemSelected(ibh.mHolder, ibh.mItem, null, null); 315 } 316 } 317 } 318} 319