ListRowPresenter.java revision a4560456facaa3dd341a7ab2f372f655d46f7ee6
147520b68e50572a9775a662410c5aff8300c8784Craig Stout/* 247520b68e50572a9775a662410c5aff8300c8784Craig Stout * Copyright (C) 2014 The Android Open Source Project 347520b68e50572a9775a662410c5aff8300c8784Craig Stout * 447520b68e50572a9775a662410c5aff8300c8784Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 547520b68e50572a9775a662410c5aff8300c8784Craig Stout * in compliance with the License. You may obtain a copy of the License at 647520b68e50572a9775a662410c5aff8300c8784Craig Stout * 747520b68e50572a9775a662410c5aff8300c8784Craig Stout * http://www.apache.org/licenses/LICENSE-2.0 847520b68e50572a9775a662410c5aff8300c8784Craig Stout * 947520b68e50572a9775a662410c5aff8300c8784Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License 1047520b68e50572a9775a662410c5aff8300c8784Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 1147520b68e50572a9775a662410c5aff8300c8784Craig Stout * or implied. See the License for the specific language governing permissions and limitations under 1247520b68e50572a9775a662410c5aff8300c8784Craig Stout * the License. 1347520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 1447520b68e50572a9775a662410c5aff8300c8784Craig Stoutpackage android.support.v17.leanback.widget; 1547520b68e50572a9775a662410c5aff8300c8784Craig Stout 1647520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport java.util.ArrayList; 1747520b68e50572a9775a662410c5aff8300c8784Craig Stout 18892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.content.Context; 199240e796bc63422c28f2707840bd99c48573279bDake Guimport android.content.res.TypedArray; 20cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.graphics.Canvas; 21892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.support.v17.leanback.R; 22cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v17.leanback.graphics.ColorOverlayDimmer; 2347520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.support.v17.leanback.widget.Presenter.ViewHolder; 24cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Guimport android.support.v7.widget.RecyclerView; 25892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.util.AttributeSet; 2647520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View; 2747520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup; 28892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.view.ViewGroup.LayoutParams; 29892181367d658f347d00ea5e091aa31f086b2a20Dake Guimport android.widget.FrameLayout; 3047520b68e50572a9775a662410c5aff8300c8784Craig Stout 3147520b68e50572a9775a662410c5aff8300c8784Craig Stout/** 327aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter renders {@link ListRow} using a 33cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link HorizontalGridView} hosted in a {@link ListRowView}. 347aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * 357aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Hover card</h3> 3647520b68e50572a9775a662410c5aff8300c8784Craig Stout * Optionally, {@link #setHoverCardPresenterSelector(PresenterSelector)} can be used to 3747520b68e50572a9775a662410c5aff8300c8784Craig Stout * display a view for the currently focused list item below the rendered 3847520b68e50572a9775a662410c5aff8300c8784Craig Stout * list. This view is known as a hover card. 397aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * 407aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * <h3>Selection animation</h3> 417aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * ListRowPresenter disables {@link RowPresenter}'s default dimming effect and draw 427aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * a dim overlay on top of each individual child items. Subclass may override and disable 437aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #isUsingDefaultListSelectEffect()} and write its own dim effect in 447aaa6c6ef8807cc4ea4c4642716d6e30056bc4ebDake Gu * {@link #onSelectLevelChanged(RowPresenter.ViewHolder)}. 45dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * 46dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * <h3>Shadow</h3> 47dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * ListRowPresenter applies a default shadow to child of each view. Call 48dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * {@link #setShadowEnabled(boolean)} to disable shadow. Subclass may override and return 49dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * false in {@link #isUsingDefaultShadow()} and replace with its own shadow implementation. 5047520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 5147520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class ListRowPresenter extends RowPresenter { 5247520b68e50572a9775a662410c5aff8300c8784Craig Stout 5347520b68e50572a9775a662410c5aff8300c8784Craig Stout private static final String TAG = "ListRowPresenter"; 5447520b68e50572a9775a662410c5aff8300c8784Craig Stout private static final boolean DEBUG = false; 5547520b68e50572a9775a662410c5aff8300c8784Craig Stout 5647520b68e50572a9775a662410c5aff8300c8784Craig Stout public static class ViewHolder extends RowPresenter.ViewHolder { 5747520b68e50572a9775a662410c5aff8300c8784Craig Stout final ListRowPresenter mListRowPresenter; 5847520b68e50572a9775a662410c5aff8300c8784Craig Stout final HorizontalGridView mGridView; 5947520b68e50572a9775a662410c5aff8300c8784Craig Stout final ItemBridgeAdapter mItemBridgeAdapter = new ItemBridgeAdapter(); 6047520b68e50572a9775a662410c5aff8300c8784Craig Stout final HorizontalHoverCardSwitcher mHoverCardViewSwitcher = new HorizontalHoverCardSwitcher(); 61cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu final ColorOverlayDimmer mColorDimmer; 6247520b68e50572a9775a662410c5aff8300c8784Craig Stout 6347520b68e50572a9775a662410c5aff8300c8784Craig Stout public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) { 6447520b68e50572a9775a662410c5aff8300c8784Craig Stout super(rootView); 6547520b68e50572a9775a662410c5aff8300c8784Craig Stout mGridView = gridView; 6647520b68e50572a9775a662410c5aff8300c8784Craig Stout mListRowPresenter = p; 67cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu mColorDimmer = ColorOverlayDimmer.createDefault(rootView.getContext()); 6847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 6947520b68e50572a9775a662410c5aff8300c8784Craig Stout 7047520b68e50572a9775a662410c5aff8300c8784Craig Stout public final ListRowPresenter getListRowPresenter() { 7147520b68e50572a9775a662410c5aff8300c8784Craig Stout return mListRowPresenter; 7247520b68e50572a9775a662410c5aff8300c8784Craig Stout } 7347520b68e50572a9775a662410c5aff8300c8784Craig Stout 7447520b68e50572a9775a662410c5aff8300c8784Craig Stout public final HorizontalGridView getGridView() { 7547520b68e50572a9775a662410c5aff8300c8784Craig Stout return mGridView; 7647520b68e50572a9775a662410c5aff8300c8784Craig Stout } 7747520b68e50572a9775a662410c5aff8300c8784Craig Stout } 7847520b68e50572a9775a662410c5aff8300c8784Craig Stout 79a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn private int mRowHeight; 80a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn private int mExpandedRowHeight; 8147520b68e50572a9775a662410c5aff8300c8784Craig Stout private PresenterSelector mHoverCardPresenterSelector; 82b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout private int mZoomFactor; 83892181367d658f347d00ea5e091aa31f086b2a20Dake Gu private boolean mShadowEnabled = true; 849240e796bc63422c28f2707840bd99c48573279bDake Gu private int mBrowseRowsFadingEdgeLength = -1; 85b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout 86b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout /** 87b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout * Constructs a ListRowPresenter with defaults. 88739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming. 89b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout */ 90b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout public ListRowPresenter() { 91739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout this(FocusHighlight.ZOOM_FACTOR_MEDIUM); 92b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout } 93b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout 94b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout /** 95b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout * Constructs a ListRowPresenter with the given parameters. 96b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout * 97b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout * @param zoomFactor Controls the zoom factor used when an item view is focused. One of 98739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_NONE}, 99739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_SMALL}, 100739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_MEDIUM}, 101739e3805bf2785e6773aede5e2e1643f537305f9Craig Stout * {@link FocusHighlight#ZOOM_FACTOR_LARGE} 102b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout */ 103b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout public ListRowPresenter(int zoomFactor) { 104b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout mZoomFactor = zoomFactor; 105b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout } 106b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout 107b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout /** 108a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Sets the row height in pixels for rows created by this Presenter. Rows 109a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * created before calling this method will not be updated. 110a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * 111a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * @param rowHeight The row height in pixels to use for rows created by this 112a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Presenter, or 0 to use the default height. 113a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn */ 114a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn public void setRowHeight(int rowHeight) { 115a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn mRowHeight = rowHeight; 116a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn } 117a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn 118a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn /** 119a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Returns the row height in pixels for rows created by this Presenter. 120a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn */ 121a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn public int getRowHeight() { 122a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn return mRowHeight; 123a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn } 124a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn 125a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn /** 126a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Sets the expanded row height in pixels for rows created by this 127a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Presenter. If not set, expanded rows have the same height as unexpanded 128a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * rows. 129a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * 130a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * @param rowHeight The row height in pixels to use for expanded rows 131a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * created by this Presenter, or 0 to use the default height. 132a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn */ 133a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn public void setExpandedRowHeight(int rowHeight) { 134a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn mExpandedRowHeight = rowHeight; 135a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn } 136a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn 137a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn /** 138a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Returns the expanded row height in pixels for rows created by this 139a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn * Presenter. 140a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn */ 141a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn public int getExpandedRowHeight() { 142a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn return mExpandedRowHeight > 0 ? mExpandedRowHeight : mRowHeight; 143a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn } 144a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn 145a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn /** 146b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout * Returns the zoom factor used for focus highlighting. 147b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout */ 148b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout public final int getZoomFactor() { 149b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout return mZoomFactor; 150b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout } 15147520b68e50572a9775a662410c5aff8300c8784Craig Stout 152892181367d658f347d00ea5e091aa31f086b2a20Dake Gu private ItemBridgeAdapter.Wrapper mCardWrapper = new ItemBridgeAdapter.Wrapper() { 153892181367d658f347d00ea5e091aa31f086b2a20Dake Gu @Override 154892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public View createWrapper(View root) { 155dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext()); 156892181367d658f347d00ea5e091aa31f086b2a20Dake Gu wrapper.setLayoutParams( 157892181367d658f347d00ea5e091aa31f086b2a20Dake Gu new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 158cb13a318e577e14461eb008071dddf762847de42Dake Gu wrapper.initialize(needsDefaultShadow(), needsDefaultListSelectEffect()); 159892181367d658f347d00ea5e091aa31f086b2a20Dake Gu return wrapper; 160892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 161892181367d658f347d00ea5e091aa31f086b2a20Dake Gu @Override 162892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public void wrap(View wrapper, View wrapped) { 163dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu ((ShadowOverlayContainer) wrapper).wrap(wrapped); 164892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 165892181367d658f347d00ea5e091aa31f086b2a20Dake Gu }; 166892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 16747520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 16847520b68e50572a9775a662410c5aff8300c8784Craig Stout protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) { 16947520b68e50572a9775a662410c5aff8300c8784Craig Stout super.initializeRowViewHolder(holder); 17047520b68e50572a9775a662410c5aff8300c8784Craig Stout final ViewHolder rowViewHolder = (ViewHolder) holder; 171c4b1a043ab39a881b2a05d50e93c35e6f6ebfffbDake Gu if (needsDefaultListSelectEffect() || needsDefaultShadow()) { 172892181367d658f347d00ea5e091aa31f086b2a20Dake Gu rowViewHolder.mItemBridgeAdapter.setWrapper(mCardWrapper); 173892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 174cb13a318e577e14461eb008071dddf762847de42Dake Gu if (needsDefaultListSelectEffect()) { 175dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu ShadowOverlayContainer.prepareParentForShadow(rowViewHolder.mGridView); 176892181367d658f347d00ea5e091aa31f086b2a20Dake Gu ((ViewGroup) rowViewHolder.view).setClipChildren(false); 177cb13a318e577e14461eb008071dddf762847de42Dake Gu if (rowViewHolder.mContainerViewHolder != null) { 178cb13a318e577e14461eb008071dddf762847de42Dake Gu ((ViewGroup) rowViewHolder.mContainerViewHolder.view).setClipChildren(false); 179cb13a318e577e14461eb008071dddf762847de42Dake Gu } 180cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 181b9e89a1544f8cf582f191184fb9b2a4f24e1fa5bCraig Stout FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter, mZoomFactor); 18247520b68e50572a9775a662410c5aff8300c8784Craig Stout rowViewHolder.mGridView.setOnChildSelectedListener( 18347520b68e50572a9775a662410c5aff8300c8784Craig Stout new OnChildSelectedListener() { 18447520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 18547520b68e50572a9775a662410c5aff8300c8784Craig Stout public void onChildSelected(ViewGroup parent, View view, int position, long id) { 18647520b68e50572a9775a662410c5aff8300c8784Craig Stout selectChildView(rowViewHolder, view); 18747520b68e50572a9775a662410c5aff8300c8784Craig Stout } 18847520b68e50572a9775a662410c5aff8300c8784Craig Stout }); 189892181367d658f347d00ea5e091aa31f086b2a20Dake Gu rowViewHolder.mItemBridgeAdapter.setAdapterListener( 190892181367d658f347d00ea5e091aa31f086b2a20Dake Gu new ItemBridgeAdapter.AdapterListener() { 191892181367d658f347d00ea5e091aa31f086b2a20Dake Gu @Override 192892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public void onCreate(final ItemBridgeAdapter.ViewHolder viewHolder) { 193892181367d658f347d00ea5e091aa31f086b2a20Dake Gu // Only when having an OnItemClickListner, we will attach the OnClickListener. 194892181367d658f347d00ea5e091aa31f086b2a20Dake Gu if (getOnItemClickedListener() != null) { 19547520b68e50572a9775a662410c5aff8300c8784Craig Stout viewHolder.mHolder.view.setOnClickListener(new View.OnClickListener() { 19647520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 19747520b68e50572a9775a662410c5aff8300c8784Craig Stout public void onClick(View v) { 19847520b68e50572a9775a662410c5aff8300c8784Craig Stout ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder) 199892181367d658f347d00ea5e091aa31f086b2a20Dake Gu rowViewHolder.mGridView.getChildViewHolder(viewHolder.itemView); 20047520b68e50572a9775a662410c5aff8300c8784Craig Stout if (getOnItemClickedListener() != null) { 20147520b68e50572a9775a662410c5aff8300c8784Craig Stout getOnItemClickedListener().onItemClicked(ibh.mItem, 20247520b68e50572a9775a662410c5aff8300c8784Craig Stout (ListRow) rowViewHolder.mRow); 20347520b68e50572a9775a662410c5aff8300c8784Craig Stout } 20447520b68e50572a9775a662410c5aff8300c8784Craig Stout } 20547520b68e50572a9775a662410c5aff8300c8784Craig Stout }); 20647520b68e50572a9775a662410c5aff8300c8784Craig Stout } 207892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 208892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 209892181367d658f347d00ea5e091aa31f086b2a20Dake Gu @Override 21029246e5ca814f17dcf368eeacd1b44a329592ae0Dake Gu public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) { 211dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu if (viewHolder.itemView instanceof ShadowOverlayContainer) { 212892181367d658f347d00ea5e091aa31f086b2a20Dake Gu int dimmedColor = rowViewHolder.mColorDimmer.getPaint().getColor(); 213dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu ((ShadowOverlayContainer) viewHolder.itemView).setOverlayColor(dimmedColor); 214892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 2154df06cbe8f6dd087fc8f1068faa77923cb297365Tim Kilbourn viewHolder.itemView.setActivated(rowViewHolder.mExpanded); 216892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 217892181367d658f347d00ea5e091aa31f086b2a20Dake Gu }); 21847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 21947520b68e50572a9775a662410c5aff8300c8784Craig Stout 220cb13a318e577e14461eb008071dddf762847de42Dake Gu final boolean needsDefaultListSelectEffect() { 221cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu return isUsingDefaultListSelectEffect() && getSelectEffectEnabled(); 222cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 223cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu 22447520b68e50572a9775a662410c5aff8300c8784Craig Stout /** 22547520b68e50572a9775a662410c5aff8300c8784Craig Stout * Set {@link PresenterSelector} used for showing a select object in a hover card. 22647520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 22747520b68e50572a9775a662410c5aff8300c8784Craig Stout public final void setHoverCardPresenterSelector(PresenterSelector selector) { 22847520b68e50572a9775a662410c5aff8300c8784Craig Stout mHoverCardPresenterSelector = selector; 22947520b68e50572a9775a662410c5aff8300c8784Craig Stout } 23047520b68e50572a9775a662410c5aff8300c8784Craig Stout 23147520b68e50572a9775a662410c5aff8300c8784Craig Stout /** 23247520b68e50572a9775a662410c5aff8300c8784Craig Stout * Get {@link PresenterSelector} used for showing a select object in a hover card. 23347520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 23447520b68e50572a9775a662410c5aff8300c8784Craig Stout public final PresenterSelector getHoverCardPresenterSelector() { 23547520b68e50572a9775a662410c5aff8300c8784Craig Stout return mHoverCardPresenterSelector; 23647520b68e50572a9775a662410c5aff8300c8784Craig Stout } 23747520b68e50572a9775a662410c5aff8300c8784Craig Stout 23847520b68e50572a9775a662410c5aff8300c8784Craig Stout /* 23947520b68e50572a9775a662410c5aff8300c8784Craig Stout * Perform operations when a child of horizontal grid view is selected. 24047520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 24147520b68e50572a9775a662410c5aff8300c8784Craig Stout private void selectChildView(ViewHolder rowViewHolder, View view) { 24247520b68e50572a9775a662410c5aff8300c8784Craig Stout ItemBridgeAdapter.ViewHolder ibh = null; 24347520b68e50572a9775a662410c5aff8300c8784Craig Stout if (view != null) { 24447520b68e50572a9775a662410c5aff8300c8784Craig Stout ibh = (ItemBridgeAdapter.ViewHolder) 24547520b68e50572a9775a662410c5aff8300c8784Craig Stout rowViewHolder.mGridView.getChildViewHolder(view); 24647520b68e50572a9775a662410c5aff8300c8784Craig Stout } 24747520b68e50572a9775a662410c5aff8300c8784Craig Stout if (view == null) { 24847520b68e50572a9775a662410c5aff8300c8784Craig Stout if (mHoverCardPresenterSelector != null) { 24947520b68e50572a9775a662410c5aff8300c8784Craig Stout rowViewHolder.mHoverCardViewSwitcher.unselect(); 25047520b68e50572a9775a662410c5aff8300c8784Craig Stout } 25147520b68e50572a9775a662410c5aff8300c8784Craig Stout if (getOnItemSelectedListener() != null) { 25247520b68e50572a9775a662410c5aff8300c8784Craig Stout getOnItemSelectedListener().onItemSelected(null, rowViewHolder.mRow); 25347520b68e50572a9775a662410c5aff8300c8784Craig Stout } 25447520b68e50572a9775a662410c5aff8300c8784Craig Stout } else if (rowViewHolder.mExpanded && rowViewHolder.mSelected) { 25547520b68e50572a9775a662410c5aff8300c8784Craig Stout if (mHoverCardPresenterSelector != null) { 25647520b68e50572a9775a662410c5aff8300c8784Craig Stout rowViewHolder.mHoverCardViewSwitcher.select(rowViewHolder.mGridView, view, 25747520b68e50572a9775a662410c5aff8300c8784Craig Stout ibh.mItem); 25847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 25947520b68e50572a9775a662410c5aff8300c8784Craig Stout if (getOnItemSelectedListener() != null) { 26047520b68e50572a9775a662410c5aff8300c8784Craig Stout getOnItemSelectedListener().onItemSelected(ibh.mItem, rowViewHolder.mRow); 26147520b68e50572a9775a662410c5aff8300c8784Craig Stout } 26247520b68e50572a9775a662410c5aff8300c8784Craig Stout } 26347520b68e50572a9775a662410c5aff8300c8784Craig Stout } 26447520b68e50572a9775a662410c5aff8300c8784Craig Stout 26547520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 26647520b68e50572a9775a662410c5aff8300c8784Craig Stout protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { 267cb13a318e577e14461eb008071dddf762847de42Dake Gu ListRowView rowView = new ListRowView(parent.getContext()); 2689240e796bc63422c28f2707840bd99c48573279bDake Gu setupFadingEffect(rowView); 269a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn if (mRowHeight > 0) { 270a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn rowView.getGridView().setRowHeight(mRowHeight); 271a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn } 27247520b68e50572a9775a662410c5aff8300c8784Craig Stout return new ViewHolder(rowView, rowView.getGridView(), this); 27347520b68e50572a9775a662410c5aff8300c8784Craig Stout } 27447520b68e50572a9775a662410c5aff8300c8784Craig Stout 27547520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 27647520b68e50572a9775a662410c5aff8300c8784Craig Stout protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) { 27747520b68e50572a9775a662410c5aff8300c8784Craig Stout updateFooterViewSwitcher((ViewHolder) holder); 27847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 27947520b68e50572a9775a662410c5aff8300c8784Craig Stout 28047520b68e50572a9775a662410c5aff8300c8784Craig Stout /* 28147520b68e50572a9775a662410c5aff8300c8784Craig Stout * Show or hide hover card when row selection or expanded state is changed. 28247520b68e50572a9775a662410c5aff8300c8784Craig Stout */ 28347520b68e50572a9775a662410c5aff8300c8784Craig Stout private void updateFooterViewSwitcher(ViewHolder vh) { 28447520b68e50572a9775a662410c5aff8300c8784Craig Stout if (vh.mExpanded && vh.mSelected) { 28547520b68e50572a9775a662410c5aff8300c8784Craig Stout if (mHoverCardPresenterSelector != null) { 28647520b68e50572a9775a662410c5aff8300c8784Craig Stout vh.mHoverCardViewSwitcher.init((ViewGroup) vh.view, 28747520b68e50572a9775a662410c5aff8300c8784Craig Stout mHoverCardPresenterSelector); 28847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 28902e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu ItemBridgeAdapter.ViewHolder ibh = (ItemBridgeAdapter.ViewHolder) 29002e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu vh.mGridView.findViewHolderForPosition( 29102e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu vh.mGridView.getSelectedPosition()); 29202e411c2c69d20aab138f1a162a24ea650eff7a1Dake Gu selectChildView(vh, ibh == null ? null : ibh.itemView); 29347520b68e50572a9775a662410c5aff8300c8784Craig Stout } else { 29447520b68e50572a9775a662410c5aff8300c8784Craig Stout if (mHoverCardPresenterSelector != null) { 29547520b68e50572a9775a662410c5aff8300c8784Craig Stout vh.mHoverCardViewSwitcher.clear(); 29647520b68e50572a9775a662410c5aff8300c8784Craig Stout } 29747520b68e50572a9775a662410c5aff8300c8784Craig Stout } 29847520b68e50572a9775a662410c5aff8300c8784Craig Stout } 29947520b68e50572a9775a662410c5aff8300c8784Craig Stout 3009240e796bc63422c28f2707840bd99c48573279bDake Gu private void setupFadingEffect(ListRowView rowView) { 3019240e796bc63422c28f2707840bd99c48573279bDake Gu // content is completely faded at 1/2 padding of left, fading length is 1/2 of padding. 3029240e796bc63422c28f2707840bd99c48573279bDake Gu HorizontalGridView gridView = rowView.getGridView(); 3039240e796bc63422c28f2707840bd99c48573279bDake Gu if (mBrowseRowsFadingEdgeLength < 0) { 3049240e796bc63422c28f2707840bd99c48573279bDake Gu TypedArray ta = gridView.getContext() 3059240e796bc63422c28f2707840bd99c48573279bDake Gu .obtainStyledAttributes(R.styleable.LeanbackTheme); 3069240e796bc63422c28f2707840bd99c48573279bDake Gu mBrowseRowsFadingEdgeLength = (int) ta.getDimension( 3079240e796bc63422c28f2707840bd99c48573279bDake Gu R.styleable.LeanbackTheme_browseRowsFadingEdgeLength, 0); 3089240e796bc63422c28f2707840bd99c48573279bDake Gu ta.recycle(); 30947520b68e50572a9775a662410c5aff8300c8784Craig Stout } 3109240e796bc63422c28f2707840bd99c48573279bDake Gu gridView.setFadingLeftEdgeLength(mBrowseRowsFadingEdgeLength); 31147520b68e50572a9775a662410c5aff8300c8784Craig Stout } 31247520b68e50572a9775a662410c5aff8300c8784Craig Stout 31347520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 31447520b68e50572a9775a662410c5aff8300c8784Craig Stout protected void onRowViewExpanded(RowPresenter.ViewHolder holder, boolean expanded) { 31547520b68e50572a9775a662410c5aff8300c8784Craig Stout super.onRowViewExpanded(holder, expanded); 31647520b68e50572a9775a662410c5aff8300c8784Craig Stout ViewHolder vh = (ViewHolder) holder; 317a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn if (getRowHeight() != getExpandedRowHeight()) { 318a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn int newHeight = expanded ? getExpandedRowHeight() : getRowHeight(); 319a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn vh.getGridView().setRowHeight(newHeight); 320a4560456facaa3dd341a7ab2f372f655d46f7ee6Tim Kilbourn } 3219240e796bc63422c28f2707840bd99c48573279bDake Gu vh.getGridView().setFadingLeftEdge(!expanded); 32247520b68e50572a9775a662410c5aff8300c8784Craig Stout updateFooterViewSwitcher(vh); 32347520b68e50572a9775a662410c5aff8300c8784Craig Stout } 32447520b68e50572a9775a662410c5aff8300c8784Craig Stout 32547520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 326cb13a318e577e14461eb008071dddf762847de42Dake Gu protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) { 327cb13a318e577e14461eb008071dddf762847de42Dake Gu super.onBindRowViewHolder(holder, item); 328cb13a318e577e14461eb008071dddf762847de42Dake Gu ViewHolder vh = (ViewHolder) holder; 32947520b68e50572a9775a662410c5aff8300c8784Craig Stout ListRow rowItem = (ListRow) item; 33047520b68e50572a9775a662410c5aff8300c8784Craig Stout vh.mItemBridgeAdapter.clear(); 33147520b68e50572a9775a662410c5aff8300c8784Craig Stout vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter()); 33247520b68e50572a9775a662410c5aff8300c8784Craig Stout vh.mGridView.setAdapter(vh.mItemBridgeAdapter); 33347520b68e50572a9775a662410c5aff8300c8784Craig Stout } 33447520b68e50572a9775a662410c5aff8300c8784Craig Stout 33547520b68e50572a9775a662410c5aff8300c8784Craig Stout @Override 336cb13a318e577e14461eb008071dddf762847de42Dake Gu protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) { 337cb13a318e577e14461eb008071dddf762847de42Dake Gu ((ViewHolder) holder).mGridView.setAdapter(null); 338cb13a318e577e14461eb008071dddf762847de42Dake Gu super.onUnbindRowViewHolder(holder); 33947520b68e50572a9775a662410c5aff8300c8784Craig Stout } 34047520b68e50572a9775a662410c5aff8300c8784Craig Stout 341cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu /** 342cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * ListRowPresenter overrides the default select effect of {@link RowPresenter} 343cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * and return false. 344cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu */ 345cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu @Override 346cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu public final boolean isUsingDefaultSelectEffect() { 347cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu return false; 348cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 349cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu 350cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu /** 351cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * Returns true so that default select effect is applied to each individual 352cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * child of {@link HorizontalGridView}. Subclass may return false to disable 353cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * the default implementation. 354cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * @see #onSelectLevelChanged(RowPresenter.ViewHolder) 355cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu */ 356cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu public boolean isUsingDefaultListSelectEffect() { 357cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu return true; 358cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 359cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu 360cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu /** 361dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu * Returns true if SDK >= 18, where default shadow 362892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * is applied to each individual child of {@link HorizontalGridView}. 363892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * Subclass may return false to disable. 364892181367d658f347d00ea5e091aa31f086b2a20Dake Gu */ 365892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public boolean isUsingDefaultShadow() { 366dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu return ShadowOverlayContainer.supportsShadow(); 367892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 368892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 369892181367d658f347d00ea5e091aa31f086b2a20Dake Gu /** 370892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * Enable or disable child shadow. 371892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * This is not only for enable/disable default shadow implementation but also subclass must 372892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * respect this flag. 373892181367d658f347d00ea5e091aa31f086b2a20Dake Gu */ 374892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public final void setShadowEnabled(boolean enabled) { 375892181367d658f347d00ea5e091aa31f086b2a20Dake Gu mShadowEnabled = enabled; 376892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 377892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 378892181367d658f347d00ea5e091aa31f086b2a20Dake Gu /** 379892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * Returns true if child shadow is enabled. 380892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * This is not only for enable/disable default shadow implementation but also subclass must 381892181367d658f347d00ea5e091aa31f086b2a20Dake Gu * respect this flag. 382892181367d658f347d00ea5e091aa31f086b2a20Dake Gu */ 383892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public final boolean getShadowEnabled() { 384892181367d658f347d00ea5e091aa31f086b2a20Dake Gu return mShadowEnabled; 385892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 386892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 387892181367d658f347d00ea5e091aa31f086b2a20Dake Gu final boolean needsDefaultShadow() { 388892181367d658f347d00ea5e091aa31f086b2a20Dake Gu return isUsingDefaultShadow() && getShadowEnabled(); 389892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 390892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 391892181367d658f347d00ea5e091aa31f086b2a20Dake Gu @Override 392892181367d658f347d00ea5e091aa31f086b2a20Dake Gu public boolean canDrawOutOfBounds() { 393892181367d658f347d00ea5e091aa31f086b2a20Dake Gu return needsDefaultShadow(); 394892181367d658f347d00ea5e091aa31f086b2a20Dake Gu } 395892181367d658f347d00ea5e091aa31f086b2a20Dake Gu 396892181367d658f347d00ea5e091aa31f086b2a20Dake Gu /** 397cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * Applies select level to header and draw a default color dim over each child 398cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * of {@link HorizontalGridView}. 399cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * <p> 400cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * Subclass may override this method. A subclass 401cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * needs to call super.onSelectLevelChanged() for applying header select level 402cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * and optionally applying a default select level to each child view of 403cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * {@link HorizontalGridView} if {@link #isUsingDefaultListSelectEffect()} 404cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * is true. Subclass may override {@link #isUsingDefaultListSelectEffect()} to return 405cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * false and deal with the individual item select level by itself. 406cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu * </p> 407cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu */ 408cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu @Override 409cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) { 410cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu super.onSelectLevelChanged(holder); 411cb13a318e577e14461eb008071dddf762847de42Dake Gu if (needsDefaultListSelectEffect()) { 412cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu ViewHolder vh = (ViewHolder) holder; 413cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu vh.mColorDimmer.setActiveLevel(holder.mSelectLevel); 414892181367d658f347d00ea5e091aa31f086b2a20Dake Gu int dimmedColor = vh.mColorDimmer.getPaint().getColor(); 415892181367d658f347d00ea5e091aa31f086b2a20Dake Gu for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) { 416dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu ShadowOverlayContainer wrapper = (ShadowOverlayContainer) vh.mGridView.getChildAt(i); 417dfd01bbadc107b6b3b2081ddb0236128c425f380Dake Gu wrapper.setOverlayColor(dimmedColor); 418cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 4199240e796bc63422c28f2707840bd99c48573279bDake Gu if (vh.mGridView.getFadingLeftEdge()) { 4209240e796bc63422c28f2707840bd99c48573279bDake Gu vh.mGridView.invalidate(); 4219240e796bc63422c28f2707840bd99c48573279bDake Gu } 422cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 423cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu } 424cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu 42547520b68e50572a9775a662410c5aff8300c8784Craig Stout} 426