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