ListRowPresenter.java revision 254b417129de2a8c5612826a152f8a26c8f1d0e8
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.content.res.TypedArray; 18import android.os.Build; 19import android.support.v17.leanback.R; 20import android.support.v17.leanback.system.Settings; 21import android.util.Log; 22import android.view.KeyEvent; 23import android.view.View; 24import android.view.ViewGroup; 25import android.view.ViewGroup.LayoutParams; 26 27import java.util.HashMap; 28 29/** 30 * ListRowPresenter renders {@link ListRow} using a 31 * {@link HorizontalGridView} hosted in a {@link ListRowView}. 32 * 33 * <h3>Hover card</h3> 34 * Optionally, {@link #setHoverCardPresenterSelector(PresenterSelector)} can be used to 35 * display a view for the currently focused list item below the rendered 36 * list. This view is known as a hover card. 37 * 38 * <h3>Selection animation</h3> 39 * ListRowPresenter disables {@link RowPresenter}'s default dimming effect and draws 40 * a dim overlay on each view individually. A subclass may override and disable 41 * {@link #isUsingDefaultListSelectEffect()} and write its own dim effect in 42 * {@link #onSelectLevelChanged(RowPresenter.ViewHolder)}. 43 * 44 * <h3>Shadow</h3> 45 * ListRowPresenter applies a default shadow to each child view. Call 46 * {@link #setShadowEnabled(boolean)} to disable shadows. A subclass may override and return 47 * false in {@link #isUsingDefaultShadow()} and replace with its own shadow implementation. 48 */ 49public class ListRowPresenter extends RowPresenter { 50 51 private static final String TAG = "ListRowPresenter"; 52 private static final boolean DEBUG = false; 53 54 private static final int DEFAULT_RECYCLED_POOL_SIZE = 24; 55 56 /** 57 * ViewHolder for the ListRowPresenter. 58 */ 59 public static class ViewHolder extends RowPresenter.ViewHolder { 60 final ListRowPresenter mListRowPresenter; 61 final HorizontalGridView mGridView; 62 ItemBridgeAdapter mItemBridgeAdapter; 63 final HorizontalHoverCardSwitcher mHoverCardViewSwitcher = new HorizontalHoverCardSwitcher(); 64 final int mPaddingTop; 65 final int mPaddingBottom; 66 final int mPaddingLeft; 67 final int mPaddingRight; 68 69 public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) { 70 super(rootView); 71 mGridView = gridView; 72 mListRowPresenter = p; 73 mPaddingTop = mGridView.getPaddingTop(); 74 mPaddingBottom = mGridView.getPaddingBottom(); 75 mPaddingLeft = mGridView.getPaddingLeft(); 76 mPaddingRight = mGridView.getPaddingRight(); 77 } 78 79 public final ListRowPresenter getListRowPresenter() { 80 return mListRowPresenter; 81 } 82 83 public final HorizontalGridView getGridView() { 84 return mGridView; 85 } 86 87 public final ItemBridgeAdapter getBridgeAdapter() { 88 return mItemBridgeAdapter; 89 } 90 } 91 92 class ListRowPresenterItemBridgeAdapter extends ItemBridgeAdapter { 93 ListRowPresenter.ViewHolder mRowViewHolder; 94 95 ListRowPresenterItemBridgeAdapter(ListRowPresenter.ViewHolder rowViewHolder) { 96 mRowViewHolder = rowViewHolder; 97 } 98 99 @Override 100 protected void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) { 101 if (mShadowOverlayHelper != null) { 102 mShadowOverlayHelper.onViewCreated(viewHolder.itemView); 103 } 104 } 105 106 @Override 107 public void onBind(final ItemBridgeAdapter.ViewHolder viewHolder) { 108 // Only when having an OnItemClickListner, we will attach the OnClickListener. 109 if (mRowViewHolder.getOnItemViewClickedListener() != null) { 110 viewHolder.mHolder.view.setOnClickListener(new View.OnClickListener() { 111 @Override 112 public void onClick(View v) { 113 ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder) 114 mRowViewHolder.mGridView.getChildViewHolder(viewHolder.itemView); 115 if (mRowViewHolder.getOnItemViewClickedListener() != null) { 116 mRowViewHolder.getOnItemViewClickedListener().onItemClicked(viewHolder.mHolder, 117 ibh.mItem, mRowViewHolder, (ListRow) mRowViewHolder.mRow); 118 } 119 } 120 }); 121 } 122 } 123 124 @Override 125 public void onUnbind(ItemBridgeAdapter.ViewHolder viewHolder) { 126 if (mRowViewHolder.getOnItemViewClickedListener() != null) { 127 viewHolder.mHolder.view.setOnClickListener(null); 128 } 129 } 130 131 @Override 132 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) { 133 if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) { 134 int dimmedColor = mRowViewHolder.mColorDimmer.getPaint().getColor(); 135 mShadowOverlayHelper.setOverlayColor(viewHolder.itemView, dimmedColor); 136 } 137 mRowViewHolder.syncActivatedStatus(viewHolder.itemView); 138 } 139 140 @Override 141 public void onAddPresenter(Presenter presenter, int type) { 142 mRowViewHolder.getGridView().getRecycledViewPool().setMaxRecycledViews( 143 type, getRecycledPoolSize(presenter)); 144 } 145 } 146 147 private int mRowHeight; 148 private int mExpandedRowHeight; 149 private PresenterSelector mHoverCardPresenterSelector; 150 private int mFocusZoomFactor; 151 private boolean mUseFocusDimmer; 152 private boolean mShadowEnabled = true; 153 private int mBrowseRowsFadingEdgeLength = -1; 154 private boolean mRoundedCornersEnabled = true; 155 private HashMap<Presenter, Integer> mRecycledPoolSize = new HashMap<Presenter, Integer>(); 156 private ShadowOverlayHelper mShadowOverlayHelper; 157 158 private static int sSelectedRowTopPadding; 159 private static int sExpandedSelectedRowTopPadding; 160 private static int sExpandedRowNoHovercardBottomPadding; 161 162 /** 163 * Constructs a ListRowPresenter with defaults. 164 * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming and 165 * disabled dimming on focus. 166 */ 167 public ListRowPresenter() { 168 this(FocusHighlight.ZOOM_FACTOR_MEDIUM); 169 } 170 171 /** 172 * Constructs a ListRowPresenter with the given parameters. 173 * 174 * @param focusZoomFactor Controls the zoom factor used when an item view is focused. One of 175 * {@link FocusHighlight#ZOOM_FACTOR_NONE}, 176 * {@link FocusHighlight#ZOOM_FACTOR_SMALL}, 177 * {@link FocusHighlight#ZOOM_FACTOR_XSMALL}, 178 * {@link FocusHighlight#ZOOM_FACTOR_MEDIUM}, 179 * {@link FocusHighlight#ZOOM_FACTOR_LARGE} 180 * Dimming on focus defaults to disabled. 181 */ 182 public ListRowPresenter(int focusZoomFactor) { 183 this(focusZoomFactor, false); 184 } 185 186 /** 187 * Constructs a ListRowPresenter with the given parameters. 188 * 189 * @param focusZoomFactor Controls the zoom factor used when an item view is focused. One of 190 * {@link FocusHighlight#ZOOM_FACTOR_NONE}, 191 * {@link FocusHighlight#ZOOM_FACTOR_SMALL}, 192 * {@link FocusHighlight#ZOOM_FACTOR_XSMALL}, 193 * {@link FocusHighlight#ZOOM_FACTOR_MEDIUM}, 194 * {@link FocusHighlight#ZOOM_FACTOR_LARGE} 195 * @param useFocusDimmer determines if the FocusHighlighter will use the dimmer 196 */ 197 public ListRowPresenter(int focusZoomFactor, boolean useFocusDimmer) { 198 if (!FocusHighlightHelper.isValidZoomIndex(focusZoomFactor)) { 199 throw new IllegalArgumentException("Unhandled zoom factor"); 200 } 201 mFocusZoomFactor = focusZoomFactor; 202 mUseFocusDimmer = useFocusDimmer; 203 } 204 205 /** 206 * Sets the row height for rows created by this Presenter. Rows 207 * created before calling this method will not be updated. 208 * 209 * @param rowHeight Row height in pixels, or WRAP_CONTENT, or 0 210 * to use the default height. 211 */ 212 public void setRowHeight(int rowHeight) { 213 mRowHeight = rowHeight; 214 } 215 216 /** 217 * Returns the row height for list rows created by this Presenter. 218 */ 219 public int getRowHeight() { 220 return mRowHeight; 221 } 222 223 /** 224 * Sets the expanded row height for rows created by this Presenter. 225 * If not set, expanded rows have the same height as unexpanded 226 * rows. 227 * 228 * @param rowHeight The row height in to use when the row is expanded, 229 * in pixels, or WRAP_CONTENT, or 0 to use the default. 230 */ 231 public void setExpandedRowHeight(int rowHeight) { 232 mExpandedRowHeight = rowHeight; 233 } 234 235 /** 236 * Returns the expanded row height for rows created by this Presenter. 237 */ 238 public int getExpandedRowHeight() { 239 return mExpandedRowHeight != 0 ? mExpandedRowHeight : mRowHeight; 240 } 241 242 /** 243 * Returns the zoom factor used for focus highlighting. 244 */ 245 public final int getFocusZoomFactor() { 246 return mFocusZoomFactor; 247 } 248 249 /** 250 * Returns the zoom factor used for focus highlighting. 251 * @deprecated use {@link #getFocusZoomFactor} instead. 252 */ 253 @Deprecated 254 public final int getZoomFactor() { 255 return mFocusZoomFactor; 256 } 257 258 /** 259 * Returns true if the focus dimmer is used for focus highlighting; false otherwise. 260 */ 261 public final boolean isFocusDimmerUsed() { 262 return mUseFocusDimmer; 263 } 264 265 @Override 266 protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) { 267 super.initializeRowViewHolder(holder); 268 final ViewHolder rowViewHolder = (ViewHolder) holder; 269 Context context = holder.view.getContext(); 270 if (mShadowOverlayHelper == null) { 271 mShadowOverlayHelper = new ShadowOverlayHelper(context, needsDefaultListSelectEffect(), 272 needsDefaultShadow(), areChildRoundedCornersEnabled(), isUsingZOrder(context)); 273 } 274 rowViewHolder.mItemBridgeAdapter = new ListRowPresenterItemBridgeAdapter(rowViewHolder); 275 // set wrapper if needed 276 rowViewHolder.mItemBridgeAdapter.setWrapper(mShadowOverlayHelper.getWrapper()); 277 mShadowOverlayHelper.prepareParentForShadow(rowViewHolder.mGridView); 278 279 FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter, 280 mFocusZoomFactor, mUseFocusDimmer); 281 rowViewHolder.mGridView.setFocusDrawingOrderEnabled(mShadowOverlayHelper.getShadowType() 282 == ShadowOverlayHelper.SHADOW_STATIC); 283 rowViewHolder.mGridView.setOnChildSelectedListener( 284 new OnChildSelectedListener() { 285 @Override 286 public void onChildSelected(ViewGroup parent, View view, int position, long id) { 287 selectChildView(rowViewHolder, view, true); 288 } 289 }); 290 rowViewHolder.mGridView.setOnUnhandledKeyListener( 291 new BaseGridView.OnUnhandledKeyListener() { 292 @Override 293 public boolean onUnhandledKey(KeyEvent event) { 294 if (rowViewHolder.getOnKeyListener() != null && 295 rowViewHolder.getOnKeyListener().onKey( 296 rowViewHolder.view, event.getKeyCode(), event)) { 297 return true; 298 } 299 return false; 300 } 301 }); 302 } 303 304 final boolean needsDefaultListSelectEffect() { 305 return isUsingDefaultListSelectEffect() && getSelectEffectEnabled(); 306 } 307 308 /** 309 * Sets the recycled pool size for the given presenter. 310 */ 311 public void setRecycledPoolSize(Presenter presenter, int size) { 312 mRecycledPoolSize.put(presenter, size); 313 } 314 315 /** 316 * Returns the recycled pool size for the given presenter. 317 */ 318 public int getRecycledPoolSize(Presenter presenter) { 319 return mRecycledPoolSize.containsKey(presenter) ? mRecycledPoolSize.get(presenter) : 320 DEFAULT_RECYCLED_POOL_SIZE; 321 } 322 323 /** 324 * Sets the {@link PresenterSelector} used for showing a select object in a hover card. 325 */ 326 public final void setHoverCardPresenterSelector(PresenterSelector selector) { 327 mHoverCardPresenterSelector = selector; 328 } 329 330 /** 331 * Returns the {@link PresenterSelector} used for showing a select object in a hover card. 332 */ 333 public final PresenterSelector getHoverCardPresenterSelector() { 334 return mHoverCardPresenterSelector; 335 } 336 337 /* 338 * Perform operations when a child of horizontal grid view is selected. 339 */ 340 private void selectChildView(ViewHolder rowViewHolder, View view, boolean fireEvent) { 341 if (view != null) { 342 if (rowViewHolder.mExpanded && rowViewHolder.mSelected) { 343 ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder) 344 rowViewHolder.mGridView.getChildViewHolder(view); 345 346 if (mHoverCardPresenterSelector != null) { 347 rowViewHolder.mHoverCardViewSwitcher.select( 348 rowViewHolder.mGridView, view, ibh.mItem); 349 } 350 if (fireEvent && rowViewHolder.getOnItemViewSelectedListener() != null) { 351 rowViewHolder.getOnItemViewSelectedListener().onItemSelected( 352 ibh.mHolder, ibh.mItem, rowViewHolder, rowViewHolder.mRow); 353 } 354 } 355 } else { 356 if (mHoverCardPresenterSelector != null) { 357 rowViewHolder.mHoverCardViewSwitcher.unselect(); 358 } 359 if (fireEvent && rowViewHolder.getOnItemViewSelectedListener() != null) { 360 rowViewHolder.getOnItemViewSelectedListener().onItemSelected( 361 null, null, rowViewHolder, rowViewHolder.mRow); 362 } 363 } 364 } 365 366 private static void initStatics(Context context) { 367 if (sSelectedRowTopPadding == 0) { 368 sSelectedRowTopPadding = context.getResources().getDimensionPixelSize( 369 R.dimen.lb_browse_selected_row_top_padding); 370 sExpandedSelectedRowTopPadding = context.getResources().getDimensionPixelSize( 371 R.dimen.lb_browse_expanded_selected_row_top_padding); 372 sExpandedRowNoHovercardBottomPadding = context.getResources().getDimensionPixelSize( 373 R.dimen.lb_browse_expanded_row_no_hovercard_bottom_padding); 374 } 375 } 376 377 private int getSpaceUnderBaseline(ListRowPresenter.ViewHolder vh) { 378 RowHeaderPresenter.ViewHolder headerViewHolder = vh.getHeaderViewHolder(); 379 if (headerViewHolder != null) { 380 if (getHeaderPresenter() != null) { 381 return getHeaderPresenter().getSpaceUnderBaseline(headerViewHolder); 382 } 383 return headerViewHolder.view.getPaddingBottom(); 384 } 385 return 0; 386 } 387 388 private void setVerticalPadding(ListRowPresenter.ViewHolder vh) { 389 int paddingTop, paddingBottom; 390 // Note: sufficient bottom padding needed for card shadows. 391 if (vh.isExpanded()) { 392 int headerSpaceUnderBaseline = getSpaceUnderBaseline(vh); 393 if (DEBUG) Log.v(TAG, "headerSpaceUnderBaseline " + headerSpaceUnderBaseline); 394 paddingTop = (vh.isSelected() ? sExpandedSelectedRowTopPadding : vh.mPaddingTop) - 395 headerSpaceUnderBaseline; 396 paddingBottom = mHoverCardPresenterSelector == null ? 397 sExpandedRowNoHovercardBottomPadding : vh.mPaddingBottom; 398 } else if (vh.isSelected()) { 399 paddingTop = sSelectedRowTopPadding - vh.mPaddingBottom; 400 paddingBottom = sSelectedRowTopPadding; 401 } else { 402 paddingTop = 0; 403 paddingBottom = vh.mPaddingBottom; 404 } 405 vh.getGridView().setPadding(vh.mPaddingLeft, paddingTop, vh.mPaddingRight, 406 paddingBottom); 407 } 408 409 @Override 410 protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { 411 initStatics(parent.getContext()); 412 ListRowView rowView = new ListRowView(parent.getContext()); 413 setupFadingEffect(rowView); 414 if (mRowHeight != 0) { 415 rowView.getGridView().setRowHeight(mRowHeight); 416 } 417 return new ViewHolder(rowView, rowView.getGridView(), this); 418 } 419 420 /** 421 * Dispatch item selected event using current selected item in the {@link HorizontalGridView}. 422 * The method should only be called from onRowViewSelected(). 423 */ 424 @Override 425 protected void dispatchItemSelectedListener(RowPresenter.ViewHolder holder, boolean selected) { 426 ViewHolder vh = (ViewHolder)holder; 427 ItemBridgeAdapter.ViewHolder itemViewHolder = (ItemBridgeAdapter.ViewHolder) 428 vh.mGridView.findViewHolderForPosition(vh.mGridView.getSelectedPosition()); 429 if (itemViewHolder == null) { 430 super.dispatchItemSelectedListener(holder, selected); 431 return; 432 } 433 434 if (selected) { 435 if (holder.getOnItemViewSelectedListener() != null) { 436 holder.getOnItemViewSelectedListener().onItemSelected( 437 itemViewHolder.getViewHolder(), itemViewHolder.mItem, vh, vh.getRow()); 438 } 439 } 440 } 441 442 @Override 443 protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) { 444 super.onRowViewSelected(holder, selected); 445 ViewHolder vh = (ViewHolder) holder; 446 setVerticalPadding(vh); 447 updateFooterViewSwitcher(vh); 448 } 449 450 /* 451 * Show or hide hover card when row selection or expanded state is changed. 452 */ 453 private void updateFooterViewSwitcher(ViewHolder vh) { 454 if (vh.mExpanded && vh.mSelected) { 455 if (mHoverCardPresenterSelector != null) { 456 vh.mHoverCardViewSwitcher.init((ViewGroup) vh.view, 457 mHoverCardPresenterSelector); 458 } 459 ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder) 460 vh.mGridView.findViewHolderForPosition( 461 vh.mGridView.getSelectedPosition()); 462 selectChildView(vh, ibh == null ? null : ibh.itemView, false); 463 } else { 464 if (mHoverCardPresenterSelector != null) { 465 vh.mHoverCardViewSwitcher.unselect(); 466 } 467 } 468 } 469 470 private void setupFadingEffect(ListRowView rowView) { 471 // content is completely faded at 1/2 padding of left, fading length is 1/2 of padding. 472 HorizontalGridView gridView = rowView.getGridView(); 473 if (mBrowseRowsFadingEdgeLength < 0) { 474 TypedArray ta = gridView.getContext() 475 .obtainStyledAttributes(R.styleable.LeanbackTheme); 476 mBrowseRowsFadingEdgeLength = (int) ta.getDimension( 477 R.styleable.LeanbackTheme_browseRowsFadingEdgeLength, 0); 478 ta.recycle(); 479 } 480 gridView.setFadingLeftEdgeLength(mBrowseRowsFadingEdgeLength); 481 } 482 483 @Override 484 protected void onRowViewExpanded(RowPresenter.ViewHolder holder, boolean expanded) { 485 super.onRowViewExpanded(holder, expanded); 486 ViewHolder vh = (ViewHolder) holder; 487 if (getRowHeight() != getExpandedRowHeight()) { 488 int newHeight = expanded ? getExpandedRowHeight() : getRowHeight(); 489 vh.getGridView().setRowHeight(newHeight); 490 } 491 setVerticalPadding(vh); 492 updateFooterViewSwitcher(vh); 493 } 494 495 @Override 496 protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) { 497 super.onBindRowViewHolder(holder, item); 498 ViewHolder vh = (ViewHolder) holder; 499 ListRow rowItem = (ListRow) item; 500 vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter()); 501 vh.mGridView.setAdapter(vh.mItemBridgeAdapter); 502 } 503 504 @Override 505 protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) { 506 ViewHolder vh = (ViewHolder) holder; 507 vh.mGridView.setAdapter(null); 508 vh.mItemBridgeAdapter.clear(); 509 super.onUnbindRowViewHolder(holder); 510 } 511 512 /** 513 * ListRowPresenter overrides the default select effect of {@link RowPresenter} 514 * and return false. 515 */ 516 @Override 517 public final boolean isUsingDefaultSelectEffect() { 518 return false; 519 } 520 521 /** 522 * Returns true so that default select effect is applied to each individual 523 * child of {@link HorizontalGridView}. Subclass may return false to disable 524 * the default implementation. 525 * @see #onSelectLevelChanged(RowPresenter.ViewHolder) 526 */ 527 public boolean isUsingDefaultListSelectEffect() { 528 return true; 529 } 530 531 /** 532 * Returns true if SDK >= 18, where default shadow 533 * is applied to each individual child of {@link HorizontalGridView}. 534 * Subclass may return false to disable. 535 */ 536 public boolean isUsingDefaultShadow() { 537 return ShadowOverlayHelper.supportsShadow(); 538 } 539 540 /** 541 * Returns true if SDK >= L, where Z shadow is enabled so that Z order is enabled 542 * on each child of horizontal list. If subclass returns false in isUsingDefaultShadow() 543 * and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false. 544 */ 545 public boolean isUsingZOrder(Context context) { 546 return !Settings.getInstance(context).preferStaticShadows(); 547 } 548 549 /** 550 * Enables or disables child shadow. 551 * This is not only for enable/disable default shadow implementation but also subclass must 552 * respect this flag. 553 */ 554 public final void setShadowEnabled(boolean enabled) { 555 mShadowEnabled = enabled; 556 } 557 558 /** 559 * Returns true if child shadow is enabled. 560 * This is not only for enable/disable default shadow implementation but also subclass must 561 * respect this flag. 562 */ 563 public final boolean getShadowEnabled() { 564 return mShadowEnabled; 565 } 566 567 /** 568 * Enables or disabled rounded corners on children of this row. 569 * Supported on Android SDK >= L. 570 */ 571 public final void enableChildRoundedCorners(boolean enable) { 572 mRoundedCornersEnabled = enable; 573 } 574 575 /** 576 * Returns true if rounded corners are enabled for children of this row. 577 */ 578 public final boolean areChildRoundedCornersEnabled() { 579 return mRoundedCornersEnabled; 580 } 581 582 final boolean needsDefaultShadow() { 583 return isUsingDefaultShadow() && getShadowEnabled(); 584 } 585 586 @Override 587 public boolean canDrawOutOfBounds() { 588 return needsDefaultShadow(); 589 } 590 591 /** 592 * Applies select level to header and draw a default color dim over each child 593 * of {@link HorizontalGridView}. 594 * <p> 595 * Subclass may override this method. A subclass 596 * needs to call super.onSelectLevelChanged() for applying header select level 597 * and optionally applying a default select level to each child view of 598 * {@link HorizontalGridView} if {@link #isUsingDefaultListSelectEffect()} 599 * is true. Subclass may override {@link #isUsingDefaultListSelectEffect()} to return 600 * false and deal with the individual item select level by itself. 601 * </p> 602 */ 603 @Override 604 protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) { 605 super.onSelectLevelChanged(holder); 606 if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) { 607 ViewHolder vh = (ViewHolder) holder; 608 int dimmedColor = vh.mColorDimmer.getPaint().getColor(); 609 for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) { 610 mShadowOverlayHelper.setOverlayColor(vh.mGridView.getChildAt(i), dimmedColor); 611 } 612 if (vh.mGridView.getFadingLeftEdge()) { 613 vh.mGridView.invalidate(); 614 } 615 } 616 } 617 618 @Override 619 public void freeze(RowPresenter.ViewHolder holder, boolean freeze) { 620 ViewHolder vh = (ViewHolder) holder; 621 vh.mGridView.setScrollEnabled(!freeze); 622 } 623 624 @Override 625 public void setEntranceTransitionState(RowPresenter.ViewHolder holder, 626 boolean afterEntrance) { 627 super.setEntranceTransitionState(holder, afterEntrance); 628 ((ViewHolder) holder).mGridView.setChildrenVisibility( 629 afterEntrance? View.VISIBLE : View.INVISIBLE); 630 } 631} 632