RowsFragment.java revision 1c33346ba79177e64fe33da70ee73547d7bb15f7
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.app; 15 16import android.animation.TimeAnimator; 17import android.animation.TimeAnimator.TimeListener; 18import android.graphics.Canvas; 19import android.os.Bundle; 20import android.support.v17.leanback.R; 21import android.support.v17.leanback.graphics.ColorOverlayDimmer; 22import android.support.v17.leanback.widget.ItemBridgeAdapter; 23import android.support.v17.leanback.widget.VerticalGridView; 24import android.support.v17.leanback.widget.OnItemSelectedListener; 25import android.support.v17.leanback.widget.OnItemClickedListener; 26import android.support.v17.leanback.widget.RowPresenter; 27import android.support.v17.leanback.widget.Presenter; 28import android.support.v17.leanback.widget.RowPresenter.ViewHolder; 29import android.support.v7.widget.RecyclerView; 30import android.util.Log; 31import android.view.View; 32import android.view.ViewGroup; 33import android.view.animation.DecelerateInterpolator; 34import android.view.animation.Interpolator; 35 36/** 37 * An ordered set of rows of leanback widgets. 38 */ 39public class RowsFragment extends BaseRowFragment { 40 41 /** 42 * Internal helper class that manages row select animation and apply a default 43 * dim to each row. 44 */ 45 final class RowViewHolderExtra implements TimeListener { 46 final RowPresenter mRowPresenter; 47 final RowPresenter.ViewHolder mRowViewHolder; 48 49 final TimeAnimator mSelectAnimator = new TimeAnimator(); 50 final ColorOverlayDimmer mColorDimmer; 51 int mSelectAnimatorDurationInUse; 52 Interpolator mSelectAnimatorInterpolatorInUse; 53 float mSelectLevelAnimStart; 54 float mSelectLevelAnimDelta; 55 56 RowViewHolderExtra(ItemBridgeAdapter.ViewHolder ibvh) { 57 mRowPresenter = (RowPresenter) ibvh.getPresenter(); 58 mRowViewHolder = (ViewHolder) ibvh.getViewHolder(); 59 mSelectAnimator.setTimeListener(this); 60 if (mRowPresenter.getSelectEffectEnabled() 61 && mRowPresenter.isUsingDefaultSelectEffect()) { 62 mColorDimmer = ColorOverlayDimmer.createDefault(ibvh.itemView.getContext()); 63 } else { 64 mColorDimmer = null; 65 } 66 } 67 68 @Override 69 public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 70 float fraction; 71 if (totalTime >= mSelectAnimatorDurationInUse) { 72 fraction = 1; 73 mSelectAnimator.end(); 74 } else { 75 fraction = (float) (totalTime / (double) mSelectAnimatorDurationInUse); 76 } 77 if (mSelectAnimatorInterpolatorInUse != null) { 78 fraction = mSelectAnimatorInterpolatorInUse.getInterpolation(fraction); 79 } 80 float level = mSelectLevelAnimStart + fraction * mSelectLevelAnimDelta; 81 if (mColorDimmer != null) { 82 mColorDimmer.setActiveLevel(level); 83 } 84 mRowPresenter.setSelectLevel(mRowViewHolder, level); 85 } 86 87 void animateSelect(boolean select, boolean immediate) { 88 endAnimation(); 89 final float end = select ? 1 : 0; 90 if (immediate) { 91 mRowPresenter.setSelectLevel(mRowViewHolder, end); 92 if (mColorDimmer != null) { 93 mColorDimmer.setActiveLevel(end); 94 } 95 } else if (mRowPresenter.getSelectLevel(mRowViewHolder) != end) { 96 mSelectAnimatorDurationInUse = mSelectAnimatorDuration; 97 mSelectAnimatorInterpolatorInUse = mSelectAnimatorInterpolator; 98 mSelectLevelAnimStart = mRowPresenter.getSelectLevel(mRowViewHolder); 99 mSelectLevelAnimDelta = end - mSelectLevelAnimStart; 100 mSelectAnimator.start(); 101 } 102 } 103 104 void endAnimation() { 105 mSelectAnimator.end(); 106 } 107 108 void drawDimForSelection(Canvas c) { 109 if (mColorDimmer != null) { 110 mColorDimmer.drawColorOverlay(c, mRowViewHolder.view, false); 111 } 112 } 113 } 114 115 private static final String TAG = "RowsFragment"; 116 private static final boolean DEBUG = false; 117 118 private BackgroundParams mBackgroundParams; 119 private ItemBridgeAdapter.ViewHolder mSelectedViewHolder; 120 private boolean mExpand = true; 121 private boolean mViewsCreated; 122 123 private OnItemSelectedListener mOnItemSelectedListener; 124 private OnItemClickedListener mOnItemClickedListener; 125 126 // Select animation and interpolator are not intended to exposed at this moment. 127 // They might be synced with vertical scroll animation later. 128 int mSelectAnimatorDuration; 129 Interpolator mSelectAnimatorInterpolator = new DecelerateInterpolator(2); 130 131 /** 132 * Set background parameters. 133 * @deprecated Use BackgroundManager instead 134 */ 135 @Deprecated 136 public void setBackgroundParams(BackgroundParams params) { 137 mBackgroundParams = params; 138 } 139 140 /** 141 * Returns the background parameters. 142 * @deprecated Use BackgroundManager instead 143 */ 144 @Deprecated 145 public BackgroundParams getBackgroundParams() { 146 return mBackgroundParams; 147 } 148 149 /** 150 * Sets an item clicked listener. 151 */ 152 public void setOnItemClickedListener(OnItemClickedListener listener) { 153 mOnItemClickedListener = listener; 154 if (mViewsCreated) { 155 throw new IllegalStateException( 156 "Item clicked listener must be set before views are created"); 157 } 158 } 159 160 /** 161 * Returns the item clicked listener. 162 */ 163 public OnItemClickedListener getOnItemClickedListener() { 164 return mOnItemClickedListener; 165 } 166 167 /** 168 * Set the visibility of titles/hovercard of browse rows. 169 */ 170 public void setExpand(boolean expand) { 171 final int count = getVerticalGridView().getChildCount(); 172 if (DEBUG) Log.v(TAG, "setExpand " + expand + " count " + count); 173 mExpand = expand; 174 for (int i = 0; i < count; i++) { 175 View view = getVerticalGridView().getChildAt(i); 176 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().getChildViewHolder(view); 177 setRowViewExpanded(vh, mExpand); 178 } 179 } 180 181 /** 182 * Sets an item selection listener. 183 */ 184 public void setOnItemSelectedListener(OnItemSelectedListener listener) { 185 mOnItemSelectedListener = listener; 186 VerticalGridView listView = getVerticalGridView(); 187 if (listView != null) { 188 final int count = listView.getChildCount(); 189 for (int i = 0; i < count; i++) { 190 View view = listView.getChildAt(i); 191 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) 192 listView.getChildViewHolder(view); 193 setOnItemSelectedListener(vh, mOnItemSelectedListener); 194 } 195 } 196 } 197 198 @Override 199 protected void onRowSelected(ViewGroup parent, View view, int position, long id) { 200 ItemBridgeAdapter.ViewHolder vh = (view == null) ? null : 201 (ItemBridgeAdapter.ViewHolder) getVerticalGridView().getChildViewHolder(view); 202 203 if (mSelectedViewHolder != vh) { 204 if (DEBUG) Log.v(TAG, "new row selected position " + position + " view " + view); 205 206 if (mSelectedViewHolder != null) { 207 setRowViewSelected(mSelectedViewHolder, false, false); 208 } 209 mSelectedViewHolder = vh; 210 if (mSelectedViewHolder != null) { 211 setRowViewSelected(mSelectedViewHolder, true, false); 212 } 213 } 214 } 215 216 @Override 217 protected int getLayoutResourceId() { 218 return R.layout.lb_rows_fragment; 219 } 220 221 @Override 222 public void onCreate(Bundle savedInstanceState) { 223 super.onCreate(savedInstanceState); 224 mSelectAnimatorDuration = getResources().getInteger(R.integer.lb_browse_rows_anim_duration); 225 } 226 227 @Override 228 public void onViewCreated(View view, Bundle savedInstanceState) { 229 if (DEBUG) Log.v(TAG, "onViewCreated"); 230 super.onViewCreated(view, savedInstanceState); 231 getVerticalGridView().setItemAlignmentViewId(R.id.row_list); 232 getVerticalGridView().addItemDecoration(mItemDecoration); 233 } 234 235 private RecyclerView.ItemDecoration mItemDecoration = new RecyclerView.ItemDecoration() { 236 @Override 237 public void onDrawOver(Canvas c, RecyclerView parent) { 238 final int count = parent.getChildCount(); 239 for (int i = 0; i < count; i++) { 240 ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) 241 parent.getViewHolderForChildAt(i); 242 RowViewHolderExtra extra = (RowViewHolderExtra) ibvh.getExtraObject(); 243 extra.drawDimForSelection(c); 244 } 245 } 246 }; 247 248 private static void setRowViewExpanded(ItemBridgeAdapter.ViewHolder vh, boolean expanded) { 249 ((RowPresenter) vh.getPresenter()).setRowViewExpanded( 250 (RowPresenter.ViewHolder) vh.getViewHolder(), expanded); 251 } 252 253 private static void setRowViewSelected(ItemBridgeAdapter.ViewHolder vh, boolean selected, boolean immediate) { 254 RowViewHolderExtra extra = (RowViewHolderExtra) vh.getExtraObject(); 255 extra.animateSelect(selected, immediate); 256 ((RowPresenter) vh.getPresenter()).setRowViewSelected( 257 (RowPresenter.ViewHolder) vh.getViewHolder(), selected); 258 } 259 260 private static void setOnItemSelectedListener(ItemBridgeAdapter.ViewHolder vh, 261 OnItemSelectedListener listener) { 262 ((RowPresenter) vh.getPresenter()).setOnItemSelectedListener(listener); 263 } 264 265 private final ItemBridgeAdapter.AdapterListener mBridgeAdapterListener = new ItemBridgeAdapter.AdapterListener() { 266 @Override 267 public void onAddPresenter(Presenter presenter) { 268 ((RowPresenter) presenter).setOnItemClickedListener(mOnItemClickedListener); 269 } 270 @Override 271 public void onCreate(ItemBridgeAdapter.ViewHolder vh) { 272 mViewsCreated = true; 273 vh.setExtraObject(new RowViewHolderExtra(vh)); 274 } 275 @Override 276 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) { 277 if (DEBUG) Log.v(TAG, "onAttachToWindow"); 278 setRowViewExpanded(vh, mExpand); 279 setOnItemSelectedListener(vh, mOnItemSelectedListener); 280 } 281 @Override 282 public void onBind(ItemBridgeAdapter.ViewHolder vh) { 283 setRowViewSelected(vh, false, true); 284 } 285 @Override 286 public void onUnbind(ItemBridgeAdapter.ViewHolder vh) { 287 RowViewHolderExtra extra = (RowViewHolderExtra) vh.getExtraObject(); 288 extra.endAnimation(); 289 } 290 }; 291 292 @Override 293 protected void updateAdapter() { 294 super.updateAdapter(); 295 mSelectedViewHolder = null; 296 mViewsCreated = false; 297 298 ItemBridgeAdapter adapter = getBridgeAdapter(); 299 if (adapter != null) { 300 adapter.setAdapterListener(mBridgeAdapterListener); 301 } 302 } 303} 304