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