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 */ 14 package android.support.v17.leanback.app; 15 16 import java.util.ArrayList; 17 18 import android.animation.TimeAnimator; 19 import android.animation.TimeAnimator.TimeListener; 20 import android.os.Bundle; 21 import android.support.v17.leanback.R; 22 import android.support.v17.leanback.widget.ItemBridgeAdapter; 23 import android.support.v17.leanback.widget.OnItemViewClickedListener; 24 import android.support.v17.leanback.widget.OnItemViewSelectedListener; 25 import android.support.v17.leanback.widget.RowPresenter.ViewHolder; 26 import android.support.v17.leanback.widget.ScaleFrameLayout; 27 import android.support.v17.leanback.widget.VerticalGridView; 28 import android.support.v17.leanback.widget.HorizontalGridView; 29 import android.support.v17.leanback.widget.OnItemSelectedListener; 30 import android.support.v17.leanback.widget.OnItemClickedListener; 31 import android.support.v17.leanback.widget.RowPresenter; 32 import android.support.v17.leanback.widget.ListRowPresenter; 33 import android.support.v17.leanback.widget.Presenter; 34 import android.support.v7.widget.RecyclerView; 35 import android.util.Log; 36 import android.view.LayoutInflater; 37 import android.view.View; 38 import android.view.ViewGroup; 39 import android.view.ViewTreeObserver; 40 import android.view.animation.DecelerateInterpolator; 41 import android.view.animation.Interpolator; 42 43 /** 44 * An ordered set of rows of leanback widgets. 45 */ 46 public class RowsFragment extends BaseRowFragment { 47 48 /** 49 * Internal helper class that manages row select animation and apply a default 50 * dim to each row. 51 */ 52 final class RowViewHolderExtra implements TimeListener { 53 final RowPresenter mRowPresenter; 54 final Presenter.ViewHolder mRowViewHolder; 55 56 final TimeAnimator mSelectAnimator = new TimeAnimator(); 57 58 int mSelectAnimatorDurationInUse; 59 Interpolator mSelectAnimatorInterpolatorInUse; 60 float mSelectLevelAnimStart; 61 float mSelectLevelAnimDelta; 62 RowViewHolderExtra(ItemBridgeAdapter.ViewHolder ibvh)63 RowViewHolderExtra(ItemBridgeAdapter.ViewHolder ibvh) { 64 mRowPresenter = (RowPresenter) ibvh.getPresenter(); 65 mRowViewHolder = ibvh.getViewHolder(); 66 mSelectAnimator.setTimeListener(this); 67 } 68 69 @Override onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime)70 public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 71 if (mSelectAnimator.isRunning()) { 72 updateSelect(totalTime, deltaTime); 73 } 74 } 75 updateSelect(long totalTime, long deltaTime)76 void updateSelect(long totalTime, long deltaTime) { 77 float fraction; 78 if (totalTime >= mSelectAnimatorDurationInUse) { 79 fraction = 1; 80 mSelectAnimator.end(); 81 } else { 82 fraction = (float) (totalTime / (double) mSelectAnimatorDurationInUse); 83 } 84 if (mSelectAnimatorInterpolatorInUse != null) { 85 fraction = mSelectAnimatorInterpolatorInUse.getInterpolation(fraction); 86 } 87 float level = mSelectLevelAnimStart + fraction * mSelectLevelAnimDelta; 88 mRowPresenter.setSelectLevel(mRowViewHolder, level); 89 } 90 animateSelect(boolean select, boolean immediate)91 void animateSelect(boolean select, boolean immediate) { 92 endSelectAnimation(); 93 final float end = select ? 1 : 0; 94 if (immediate) { 95 mRowPresenter.setSelectLevel(mRowViewHolder, end); 96 } else if (mRowPresenter.getSelectLevel(mRowViewHolder) != end) { 97 mSelectAnimatorDurationInUse = mSelectAnimatorDuration; 98 mSelectAnimatorInterpolatorInUse = mSelectAnimatorInterpolator; 99 mSelectLevelAnimStart = mRowPresenter.getSelectLevel(mRowViewHolder); 100 mSelectLevelAnimDelta = end - mSelectLevelAnimStart; 101 mSelectAnimator.start(); 102 } 103 } 104 endAnimations()105 void endAnimations() { 106 endSelectAnimation(); 107 } 108 endSelectAnimation()109 void endSelectAnimation() { 110 mSelectAnimator.end(); 111 } 112 113 } 114 115 private static final String TAG = "RowsFragment"; 116 private static final boolean DEBUG = false; 117 118 private ItemBridgeAdapter.ViewHolder mSelectedViewHolder; 119 private boolean mExpand = true; 120 private boolean mViewsCreated; 121 private float mRowScaleFactor; 122 private int mAlignedTop; 123 private boolean mRowScaleEnabled; 124 private ScaleFrameLayout mScaleFrameLayout; 125 private boolean mInTransition; 126 private boolean mAfterEntranceTransition = true; 127 128 private OnItemSelectedListener mOnItemSelectedListener; 129 private OnItemViewSelectedListener mOnItemViewSelectedListener; 130 private OnItemClickedListener mOnItemClickedListener; 131 private OnItemViewClickedListener mOnItemViewClickedListener; 132 133 // Select animation and interpolator are not intended to be 134 // exposed at this moment. They might be synced with vertical scroll 135 // animation later. 136 int mSelectAnimatorDuration; 137 Interpolator mSelectAnimatorInterpolator = new DecelerateInterpolator(2); 138 139 private RecyclerView.RecycledViewPool mRecycledViewPool; 140 private ArrayList<Presenter> mPresenterMapper; 141 142 private ItemBridgeAdapter.AdapterListener mExternalAdapterListener; 143 144 @Override findGridViewFromRoot(View view)145 protected VerticalGridView findGridViewFromRoot(View view) { 146 return (VerticalGridView) view.findViewById(R.id.container_list); 147 } 148 149 /** 150 * Sets an item clicked listener on the fragment. 151 * OnItemClickedListener will override {@link View.OnClickListener} that 152 * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}. 153 * So in general, developer should choose one of the listeners but not both. 154 * @deprecated Use {@link #setOnItemViewClickedListener(OnItemViewClickedListener)} 155 */ setOnItemClickedListener(OnItemClickedListener listener)156 public void setOnItemClickedListener(OnItemClickedListener listener) { 157 mOnItemClickedListener = listener; 158 if (mViewsCreated) { 159 throw new IllegalStateException( 160 "Item clicked listener must be set before views are created"); 161 } 162 } 163 164 /** 165 * Returns the item clicked listener. 166 * @deprecated Use {@link #getOnItemClickedListener()} 167 */ getOnItemClickedListener()168 public OnItemClickedListener getOnItemClickedListener() { 169 return mOnItemClickedListener; 170 } 171 172 /** 173 * Sets an item clicked listener on the fragment. 174 * OnItemViewClickedListener will override {@link View.OnClickListener} that 175 * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}. 176 * So in general, developer should choose one of the listeners but not both. 177 */ setOnItemViewClickedListener(OnItemViewClickedListener listener)178 public void setOnItemViewClickedListener(OnItemViewClickedListener listener) { 179 mOnItemViewClickedListener = listener; 180 if (mViewsCreated) { 181 throw new IllegalStateException( 182 "Item clicked listener must be set before views are created"); 183 } 184 } 185 186 /** 187 * Returns the item clicked listener. 188 */ getOnItemViewClickedListener()189 public OnItemViewClickedListener getOnItemViewClickedListener() { 190 return mOnItemViewClickedListener; 191 } 192 193 /** 194 * Set the visibility of titles/hovercard of browse rows. 195 */ setExpand(boolean expand)196 public void setExpand(boolean expand) { 197 mExpand = expand; 198 VerticalGridView listView = getVerticalGridView(); 199 if (listView != null) { 200 updateRowScaling(); 201 final int count = listView.getChildCount(); 202 if (DEBUG) Log.v(TAG, "setExpand " + expand + " count " + count); 203 for (int i = 0; i < count; i++) { 204 View view = listView.getChildAt(i); 205 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) listView.getChildViewHolder(view); 206 setRowViewExpanded(vh, mExpand); 207 } 208 } 209 } 210 211 /** 212 * Sets an item selection listener. 213 * @deprecated Use {@link #setOnItemViewSelectedListener(OnItemViewSelectedListener)} 214 */ setOnItemSelectedListener(OnItemSelectedListener listener)215 public void setOnItemSelectedListener(OnItemSelectedListener listener) { 216 mOnItemSelectedListener = listener; 217 VerticalGridView listView = getVerticalGridView(); 218 if (listView != null) { 219 final int count = listView.getChildCount(); 220 for (int i = 0; i < count; i++) { 221 View view = listView.getChildAt(i); 222 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) 223 listView.getChildViewHolder(view); 224 setOnItemSelectedListener(vh, mOnItemSelectedListener); 225 } 226 } 227 } 228 229 /** 230 * Sets an item selection listener. 231 */ setOnItemViewSelectedListener(OnItemViewSelectedListener listener)232 public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) { 233 mOnItemViewSelectedListener = listener; 234 VerticalGridView listView = getVerticalGridView(); 235 if (listView != null) { 236 final int count = listView.getChildCount(); 237 for (int i = 0; i < count; i++) { 238 View view = listView.getChildAt(i); 239 ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) 240 listView.getChildViewHolder(view); 241 setOnItemViewSelectedListener(vh, mOnItemViewSelectedListener); 242 } 243 } 244 } 245 246 /** 247 * Returns an item selection listener. 248 */ getOnItemViewSelectedListener()249 public OnItemViewSelectedListener getOnItemViewSelectedListener() { 250 return mOnItemViewSelectedListener; 251 } 252 253 /** 254 * Enables scaling of rows. 255 * 256 * @param enable true to enable row scaling 257 */ enableRowScaling(boolean enable)258 public void enableRowScaling(boolean enable) { 259 mRowScaleEnabled = enable; 260 } 261 262 @Override onRowSelected(ViewGroup parent, View view, int position, long id)263 void onRowSelected(ViewGroup parent, View view, int position, long id) { 264 VerticalGridView listView = getVerticalGridView(); 265 if (listView == null) { 266 return; 267 } 268 ItemBridgeAdapter.ViewHolder vh = (view == null) ? null : 269 (ItemBridgeAdapter.ViewHolder) listView.getChildViewHolder(view); 270 271 if (mSelectedViewHolder != vh) { 272 if (DEBUG) Log.v(TAG, "new row selected position " + position + " view " + view); 273 274 if (mSelectedViewHolder != null) { 275 setRowViewSelected(mSelectedViewHolder, false, false); 276 } 277 mSelectedViewHolder = vh; 278 if (mSelectedViewHolder != null) { 279 setRowViewSelected(mSelectedViewHolder, true, false); 280 } 281 } 282 } 283 284 @Override getLayoutResourceId()285 int getLayoutResourceId() { 286 return R.layout.lb_rows_fragment; 287 } 288 289 @Override onCreate(Bundle savedInstanceState)290 public void onCreate(Bundle savedInstanceState) { 291 super.onCreate(savedInstanceState); 292 mSelectAnimatorDuration = getResources().getInteger( 293 R.integer.lb_browse_rows_anim_duration); 294 mRowScaleFactor = getResources().getFraction( 295 R.fraction.lb_browse_rows_scale, 1, 1); 296 } 297 298 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)299 public View onCreateView(LayoutInflater inflater, ViewGroup container, 300 Bundle savedInstanceState) { 301 View view = super.onCreateView(inflater, container, savedInstanceState); 302 mScaleFrameLayout = (ScaleFrameLayout) view.findViewById(R.id.scale_frame); 303 return view; 304 } 305 306 @Override onViewCreated(View view, Bundle savedInstanceState)307 public void onViewCreated(View view, Bundle savedInstanceState) { 308 if (DEBUG) Log.v(TAG, "onViewCreated"); 309 super.onViewCreated(view, savedInstanceState); 310 // Align the top edge of child with id row_content. 311 // Need set this for directly using RowsFragment. 312 getVerticalGridView().setItemAlignmentViewId(R.id.row_content); 313 getVerticalGridView().setSaveChildrenPolicy(VerticalGridView.SAVE_LIMITED_CHILD); 314 315 mRecycledViewPool = null; 316 mPresenterMapper = null; 317 } 318 319 @Override onDestroyView()320 public void onDestroyView() { 321 mViewsCreated = false; 322 super.onDestroyView(); 323 } 324 325 @Override setItemAlignment()326 void setItemAlignment() { 327 super.setItemAlignment(); 328 if (getVerticalGridView() != null) { 329 getVerticalGridView().setItemAlignmentOffsetWithPadding(true); 330 } 331 } 332 setExternalAdapterListener(ItemBridgeAdapter.AdapterListener listener)333 void setExternalAdapterListener(ItemBridgeAdapter.AdapterListener listener) { 334 mExternalAdapterListener = listener; 335 } 336 337 /** 338 * Get the view that will change scale. 339 */ getScaleView()340 View getScaleView() { 341 return getVerticalGridView(); 342 } 343 344 /** 345 * Set pivots to scale rows fragment. 346 */ setScalePivots(float pivotX, float pivotY)347 void setScalePivots(float pivotX, float pivotY) { 348 // set pivot on ScaleFrameLayout, it will be propagated to its child VerticalGridView 349 // where we actually change scale. 350 mScaleFrameLayout.setPivotX(pivotX); 351 mScaleFrameLayout.setPivotY(pivotY); 352 } 353 setRowViewExpanded(ItemBridgeAdapter.ViewHolder vh, boolean expanded)354 private static void setRowViewExpanded(ItemBridgeAdapter.ViewHolder vh, boolean expanded) { 355 ((RowPresenter) vh.getPresenter()).setRowViewExpanded(vh.getViewHolder(), expanded); 356 } 357 setRowViewSelected(ItemBridgeAdapter.ViewHolder vh, boolean selected, boolean immediate)358 private static void setRowViewSelected(ItemBridgeAdapter.ViewHolder vh, boolean selected, 359 boolean immediate) { 360 RowViewHolderExtra extra = (RowViewHolderExtra) vh.getExtraObject(); 361 extra.animateSelect(selected, immediate); 362 ((RowPresenter) vh.getPresenter()).setRowViewSelected(vh.getViewHolder(), selected); 363 } 364 setOnItemSelectedListener(ItemBridgeAdapter.ViewHolder vh, OnItemSelectedListener listener)365 private static void setOnItemSelectedListener(ItemBridgeAdapter.ViewHolder vh, 366 OnItemSelectedListener listener) { 367 ((RowPresenter) vh.getPresenter()).setOnItemSelectedListener(listener); 368 } 369 setOnItemViewSelectedListener(ItemBridgeAdapter.ViewHolder vh, OnItemViewSelectedListener listener)370 private static void setOnItemViewSelectedListener(ItemBridgeAdapter.ViewHolder vh, 371 OnItemViewSelectedListener listener) { 372 ((RowPresenter) vh.getPresenter()).setOnItemViewSelectedListener(listener); 373 } 374 375 private final ItemBridgeAdapter.AdapterListener mBridgeAdapterListener = 376 new ItemBridgeAdapter.AdapterListener() { 377 @Override 378 public void onAddPresenter(Presenter presenter, int type) { 379 ((RowPresenter) presenter).setOnItemClickedListener(mOnItemClickedListener); 380 ((RowPresenter) presenter).setOnItemViewClickedListener(mOnItemViewClickedListener); 381 if (mExternalAdapterListener != null) { 382 mExternalAdapterListener.onAddPresenter(presenter, type); 383 } 384 } 385 @Override 386 public void onCreate(ItemBridgeAdapter.ViewHolder vh) { 387 VerticalGridView listView = getVerticalGridView(); 388 if (listView != null) { 389 // set clip children false for slide animation 390 listView.setClipChildren(false); 391 } 392 setupSharedViewPool(vh); 393 mViewsCreated = true; 394 vh.setExtraObject(new RowViewHolderExtra(vh)); 395 // selected state is initialized to false, then driven by grid view onChildSelected 396 // events. When there is rebind, grid view fires onChildSelected event properly. 397 // So we don't need do anything special later in onBind or onAttachedToWindow. 398 setRowViewSelected(vh, false, true); 399 if (mExternalAdapterListener != null) { 400 mExternalAdapterListener.onCreate(vh); 401 } 402 } 403 @Override 404 public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) { 405 if (DEBUG) Log.v(TAG, "onAttachToWindow"); 406 // All views share the same mExpand value. When we attach a view to grid view, 407 // we should make sure it pick up the latest mExpand value we set early on other 408 // attached views. For no-structure-change update, the view is rebound to new data, 409 // but again it should use the unchanged mExpand value, so we don't need do any 410 // thing in onBind. 411 setRowViewExpanded(vh, mExpand); 412 setOnItemSelectedListener(vh, mOnItemSelectedListener); 413 setOnItemViewSelectedListener(vh, mOnItemViewSelectedListener); 414 RowPresenter rowPresenter = (RowPresenter) vh.getPresenter(); 415 RowPresenter.ViewHolder rowVh = rowPresenter.getRowViewHolder(vh.getViewHolder()); 416 rowPresenter.setEntranceTransitionState(rowVh, mAfterEntranceTransition); 417 if (mExternalAdapterListener != null) { 418 mExternalAdapterListener.onAttachedToWindow(vh); 419 } 420 } 421 @Override 422 public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) { 423 if (mSelectedViewHolder == vh) { 424 setRowViewSelected(mSelectedViewHolder, false, true); 425 mSelectedViewHolder = null; 426 } 427 if (mExternalAdapterListener != null) { 428 mExternalAdapterListener.onDetachedFromWindow(vh); 429 } 430 } 431 @Override 432 public void onBind(ItemBridgeAdapter.ViewHolder vh) { 433 if (mExternalAdapterListener != null) { 434 mExternalAdapterListener.onBind(vh); 435 } 436 } 437 @Override 438 public void onUnbind(ItemBridgeAdapter.ViewHolder vh) { 439 RowViewHolderExtra extra = (RowViewHolderExtra) vh.getExtraObject(); 440 extra.endAnimations(); 441 if (mExternalAdapterListener != null) { 442 mExternalAdapterListener.onUnbind(vh); 443 } 444 } 445 }; 446 setupSharedViewPool(ItemBridgeAdapter.ViewHolder bridgeVh)447 private void setupSharedViewPool(ItemBridgeAdapter.ViewHolder bridgeVh) { 448 RowPresenter rowPresenter = (RowPresenter) bridgeVh.getPresenter(); 449 RowPresenter.ViewHolder rowVh = rowPresenter.getRowViewHolder(bridgeVh.getViewHolder()); 450 451 if (rowVh instanceof ListRowPresenter.ViewHolder) { 452 HorizontalGridView view = ((ListRowPresenter.ViewHolder) rowVh).getGridView(); 453 // Recycled view pool is shared between all list rows 454 if (mRecycledViewPool == null) { 455 mRecycledViewPool = view.getRecycledViewPool(); 456 } else { 457 view.setRecycledViewPool(mRecycledViewPool); 458 } 459 460 ItemBridgeAdapter bridgeAdapter = 461 ((ListRowPresenter.ViewHolder) rowVh).getBridgeAdapter(); 462 if (mPresenterMapper == null) { 463 mPresenterMapper = bridgeAdapter.getPresenterMapper(); 464 } else { 465 bridgeAdapter.setPresenterMapper(mPresenterMapper); 466 } 467 } 468 } 469 470 @Override updateAdapter()471 void updateAdapter() { 472 super.updateAdapter(); 473 mSelectedViewHolder = null; 474 mViewsCreated = false; 475 476 ItemBridgeAdapter adapter = getBridgeAdapter(); 477 if (adapter != null) { 478 adapter.setAdapterListener(mBridgeAdapterListener); 479 } 480 } 481 482 @Override onTransitionStart()483 void onTransitionStart() { 484 super.onTransitionStart(); 485 mInTransition = true; 486 freezeRows(true); 487 } 488 489 class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener { 490 491 final View mVerticalView; 492 final Runnable mCallback; 493 int mState; 494 495 final static int STATE_INIT = 0; 496 final static int STATE_FIRST_DRAW = 1; 497 final static int STATE_SECOND_DRAW = 2; 498 ExpandPreLayout(Runnable callback)499 ExpandPreLayout(Runnable callback) { 500 mVerticalView = getVerticalGridView(); 501 mCallback = callback; 502 } 503 execute()504 void execute() { 505 mVerticalView.getViewTreeObserver().addOnPreDrawListener(this); 506 setExpand(false); 507 mState = STATE_INIT; 508 } 509 510 @Override onPreDraw()511 public boolean onPreDraw() { 512 if (mState == STATE_INIT) { 513 setExpand(true); 514 mState = STATE_FIRST_DRAW; 515 } else if (mState == STATE_FIRST_DRAW) { 516 mCallback.run(); 517 mVerticalView.getViewTreeObserver().removeOnPreDrawListener(this); 518 mState = STATE_SECOND_DRAW; 519 } 520 return false; 521 } 522 } 523 onExpandTransitionStart(boolean expand, final Runnable callback)524 void onExpandTransitionStart(boolean expand, final Runnable callback) { 525 onTransitionStart(); 526 if (expand) { 527 callback.run(); 528 return; 529 } 530 // Run a "pre" layout when we go non-expand, in order to get the initial 531 // positions of added rows. 532 new ExpandPreLayout(callback).execute(); 533 } 534 needsScale()535 private boolean needsScale() { 536 return mRowScaleEnabled && !mExpand; 537 } 538 updateRowScaling()539 private void updateRowScaling() { 540 final float scaleFactor = needsScale() ? mRowScaleFactor : 1f; 541 mScaleFrameLayout.setLayoutScaleY(scaleFactor); 542 getScaleView().setScaleY(scaleFactor); 543 getScaleView().setScaleX(scaleFactor); 544 updateWindowAlignOffset(); 545 } 546 updateWindowAlignOffset()547 private void updateWindowAlignOffset() { 548 int alignOffset = mAlignedTop; 549 if (needsScale()) { 550 alignOffset = (int) (alignOffset / mRowScaleFactor + 0.5f); 551 } 552 getVerticalGridView().setWindowAlignmentOffset(alignOffset); 553 } 554 555 @Override setWindowAlignmentFromTop(int alignedTop)556 void setWindowAlignmentFromTop(int alignedTop) { 557 mAlignedTop = alignedTop; 558 final VerticalGridView gridView = getVerticalGridView(); 559 if (gridView != null) { 560 updateWindowAlignOffset(); 561 // align to a fixed position from top 562 gridView.setWindowAlignmentOffsetPercent( 563 VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); 564 gridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE); 565 } 566 } 567 568 @Override onTransitionEnd()569 void onTransitionEnd() { 570 super.onTransitionEnd(); 571 mInTransition = false; 572 freezeRows(false); 573 } 574 freezeRows(boolean freeze)575 private void freezeRows(boolean freeze) { 576 VerticalGridView verticalView = getVerticalGridView(); 577 if (verticalView != null) { 578 final int count = verticalView.getChildCount(); 579 for (int i = 0; i < count; i++) { 580 ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) 581 verticalView.getChildViewHolder(verticalView.getChildAt(i)); 582 RowPresenter rowPresenter = (RowPresenter) ibvh.getPresenter(); 583 RowPresenter.ViewHolder vh = rowPresenter.getRowViewHolder(ibvh.getViewHolder()); 584 rowPresenter.freeze(vh, freeze); 585 } 586 } 587 } 588 589 /** 590 * For rows that willing to participate entrance transition, this function 591 * hide views if afterTransition is true, show views if afterTransition is false. 592 */ setEntranceTransitionState(boolean afterTransition)593 void setEntranceTransitionState(boolean afterTransition) { 594 mAfterEntranceTransition = afterTransition; 595 VerticalGridView verticalView = getVerticalGridView(); 596 if (verticalView != null) { 597 final int count = verticalView.getChildCount(); 598 for (int i = 0; i < count; i++) { 599 ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) 600 verticalView.getChildViewHolder(verticalView.getChildAt(i)); 601 RowPresenter rowPresenter = (RowPresenter) ibvh.getPresenter(); 602 RowPresenter.ViewHolder vh = rowPresenter.getRowViewHolder(ibvh.getViewHolder()); 603 rowPresenter.setEntranceTransitionState(vh, mAfterEntranceTransition); 604 } 605 } 606 } 607 } 608