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