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