StaggeredGridLayoutManager.java revision 6b4d950d0d1e26165a1e643a2fd1fe4e283786f1
12d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/* 22d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 32d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 42d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 52d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * you may not use this file except in compliance with the License. 62d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * You may obtain a copy of the License at 72d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 82d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 92d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Unless required by applicable law or agreed to in writing, software 112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * See the License for the specific language governing permissions and 142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * limitations under the License. 152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarpackage android.support.v7.widget; 182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.content.Context; 202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.graphics.PointF; 212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.graphics.Rect; 222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.os.Parcel; 232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.os.Parcelable; 242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.support.v4.view.ViewCompat; 252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.AttributeSet; 262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.Log; 272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.View; 282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.ViewGroup; 292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.ArrayList; 322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.Arrays; 332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.BitSet; 342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START; 372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END; 382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_HEAD; 392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_TAIL; 402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/** 412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * A LayoutManager that lays out children in a staggered grid formation. 422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It supports horizontal & vertical layout as well as an ability to layout children in reverse. 432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps, 452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * StaggeredGridLayoutManager can offset spans independently or move items between spans. You can 462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * control this behavior via {@link #setGapStrategy(int)}. 472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarpublic class StaggeredGridLayoutManager extends RecyclerView.LayoutManager { 492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final String TAG = "StaggeredGridLayoutManager"; 512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final boolean DEBUG = false; 532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5403a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; 5503a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar 5603a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar public static final int VERTICAL = OrientationHelper.VERTICAL; 5703a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar 582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Does not do anything to hide gaps 602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_NONE = 0; 622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Scroll the shorter span slower to avoid gaps in the UI. 652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For example, if LayoutManager ends up with the following layout: 672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BXC 692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DEF 702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Where B has two spans height, if user scrolls down it will keep the positions of 2nd and 3rd 722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * columns, 732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * which will result in: 742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BXC 762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BEF 772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * instead of 792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * B 812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BEF 822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_LAZY = 1; 852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * On scroll, LayoutManager checks for a view that is assigned to wrong span. 882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When such a situation is detected, LayoutManager will wait until scroll is complete and then 892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * move children to their correct spans. 902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For example, if LayoutManager ends up with the following layout due to adapter changes: 922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * AAA 942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * _BC 952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DDD 962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It will animate to the following state: 982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * AAA 1002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BC_ 1012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DDD 1022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 1032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; 1052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final int INVALID_OFFSET = Integer.MIN_VALUE; 1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Number of spans 1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mSpanCount = -1; 1122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span[] mSpans; 1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Primary orientation is the layout's orientation, secondary orientation is the orientation 1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * for spans. Having both makes code much cleaner for calculations. 1182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper mPrimaryOrientation; 1202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper mSecondaryOrientation; 1212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mOrientation; 1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The width or height per span, depending on the orientation. 1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mSizePerSpan; 1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private LayoutState mLayoutState; 1302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mReverseLayout = false; 1322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Aggregated reverse layout value that takes RTL into account. 1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mShouldReverseLayout = false; 1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Temporary variable used during fill method to check which spans needs to be filled. 1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private BitSet mRemainingSpans; 1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When LayoutManager needs to scroll to a position, it sets this variable and requests a 1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * layout which will check this variable and re-layout accordingly. 1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1476e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar int mPendingScrollPosition = RecyclerView.NO_POSITION; 1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is 1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * called. 1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1536e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar int mPendingScrollPositionOffset = INVALID_OFFSET; 1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Keeps the mapping between the adapter positions and spans. This is necessary to provide 1572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * a consistent experience when user scrolls the list. 1582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LazySpanLookup mLazySpanLookup = new LazySpanLookup(); 1602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * how we handle gaps in UI. 1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS; 1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Saved state needs this information to properly layout on restore. 1682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mLastLayoutFromEnd; 1702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * SavedState is not handled until a layout happens. This is where we keep it until next 1732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * layout. 1742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private SavedState mPendingSavedState; 1762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If LayoutManager detects an unwanted gap in the layout, it sets this flag which will trigger 1792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * a runnable after scrolling ends and will re-check. If invalid view state is still present, 1802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * it will request a layout to fix it. 1812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mHasGaps; 1832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Creates a StaggeredGridLayoutManager with given parameters. 1862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 1872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param spanCount If orientation is vertical, spanCount is number of columns. If 1882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * orientation is horizontal, spanCount is number of rows. 1899bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL} 1902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public StaggeredGridLayoutManager(int spanCount, int orientation) { 1922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = orientation; 1932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setSpanCount(spanCount); 1942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 1972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onScrollStateChanged(int state) { 1982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (state == RecyclerView.SCROLL_STATE_IDLE && mHasGaps) { 1992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // re-check for gaps 2002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View gapView = hasGapsToFix(0, getChildCount()); 2012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gapView == null) { 2022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mHasGaps = false; // yay, gap disappeared :) 2032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // We should invalidate positions after the last visible child. No reason to 2042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // re-layout. 2052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int lastVisiblePosition = mShouldReverseLayout ? getFirstChildPosition() 2062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getLastChildPosition(); 2072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.invalidateAfter(lastVisiblePosition + 1); 2082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 2092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.invalidateAfter(getPosition(gapView)); 2100ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar requestSimpleAnimationsInNextLayout(); 2112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); // Trigger a re-layout which will fix the layout assignments. 2122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 2172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the number of spans for the layout. This will invalidate all of the span assignments 2182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * for Views. 2192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 2202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Calling this method will automatically result in a new layout request unless the spanCount 2212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * parameter is equal to current span count. 2222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 2232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param spanCount Number of spans to layout 2242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 2252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setSpanCount(int spanCount) { 2260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 2272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mSpanCount != spanCount) { 2282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // invalidate span info in saved state 2292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateSpanInfo(); 2302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.mSpanCount = spanCount; 231333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition; 2322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanCount != mSpanCount) { 2342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateSpanAssignments(); 2352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanCount = spanCount; 2362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans = new BitSet(mSpanCount); 2372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans = new Span[mSpanCount]; 2382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 2392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i] = new Span(i); 2402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 2422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 2462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep 2472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * scroll position. 2482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 2492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param orientation {@link OrientationHelper#HORIZONTAL} or {@link OrientationHelper#VERTICAL} 2502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 2512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setOrientation(int orientation) { 2522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (orientation != HORIZONTAL && orientation != VERTICAL) { 2532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar throw new IllegalArgumentException("invalid orientation."); 2542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 2562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mOrientation != orientation) { 2572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // override pending state 2582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.mOrientation = orientation; 2592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (orientation == mOrientation) { 2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 2622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = orientation; 2642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation != null && mSecondaryOrientation != null) { 2652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // swap 2662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper tmp = mPrimaryOrientation; 2672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation = mSecondaryOrientation; 2682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation = tmp; 2692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 2712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 2742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets whether LayoutManager should start laying out items from the end of the UI. The order 2752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * items are traversed is not affected by this call. 2762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 2772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * This behaves similar to the layout change for RTL views. When set to true, first item is 2782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * laid out at the end of the ViewGroup, second item is laid out before it etc. 2792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 2802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For horizontal layouts, it depends on the layout direction. 2812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if 2822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link RecyclerView}} is RTL, it will layout from LTR. 2832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 2842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param reverseLayout Whether layout should be in reverse or not 2852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 2862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setReverseLayout(boolean reverseLayout) { 2870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 2882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) { 2892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.mReverseLayout = reverseLayout; 2902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = reverseLayout; 2922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 2932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 2962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the current gap handling strategy for StaggeredGridLayoutManager. 2972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 2982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Staggered grid may have gaps in the layout as items may have different sizes. To avoid gaps, 2992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * StaggeredGridLayoutManager provides 3 options. Check {@link #GAP_HANDLING_NONE}, 3002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}, {@link #GAP_HANDLING_LAZY} for details. 3012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 3022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}. 3032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 3042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return Current gap handling strategy. 3052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setGapStrategy(int) 3062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_NONE 3072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_LAZY 3082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS 3092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getGapStrategy() { 3112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mGapStrategy; 3122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter 3162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * is different than the current strategy, calling this method will trigger a layout request. 3172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 3182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param gapStrategy The new gap handling strategy. Should be {@link #GAP_HANDLING_LAZY} 3192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * , {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or 3202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #GAP_HANDLING_NONE} 3212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #getGapStrategy() 3222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setGapStrategy(int gapStrategy) { 3240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 3252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mGapStrategy != gapStrategy) { 3262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.mGapStrategy = gapStrategy; 3272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gapStrategy == mGapStrategy) { 3292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 3302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gapStrategy != GAP_HANDLING_LAZY && gapStrategy != GAP_HANDLING_NONE && 3322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) { 3332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE " 3342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar + ", GAP_HANDLING_LAZY or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS"); 3352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mGapStrategy = gapStrategy; 3372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 3382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 3410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void assertNotInLayoutOrScroll(String message) { 3420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar if (mPendingSavedState == null) { 3430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.assertNotInLayoutOrScroll(message); 3440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 3450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 3460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 3472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the number of spans laid out by StaggeredGridLayoutManager. 3492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 3502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return Number of spans in the layout 3512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getSpanCount() { 3532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mSpanCount; 3542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items. 3582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 3592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If you need to cancel current assignments, you can call this method which will clear all 3602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * assignments and request a new layout. 3612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void invalidateSpanAssignments() { 3632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.clear(); 3642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 3652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void ensureOrientationHelper() { 3682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation == null) { 3692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation); 3702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation = OrientationHelper 3712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .createOrientationHelper(this, 1 - mOrientation); 3722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState = new LayoutState(); 3732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Calculates the views' layout order. (e.g. from end to start or start to end) 3782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * RTL layout support is applied automatically. So if layout is RTL and 3792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left. 3802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void resolveShouldLayoutReverse() { 3822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // A == B is the same result, but we rather keep it readable 3832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL || !isLayoutRTL()) { 3842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mShouldReverseLayout = mReverseLayout; 3852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 3862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mShouldReverseLayout = !mReverseLayout; 3872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean isLayoutRTL() { 3912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL; 3922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns whether views are laid out in reverse order or not. 3962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 3972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Not that this value is not affected by RecyclerView's layout direction. 3982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 3992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return True if layout is reversed, false otherwise 4002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setReverseLayout(boolean) 4012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean getReverseLayout() { 4032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mReverseLayout; 4042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 4072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 4082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureOrientationHelper(); 4092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Update adapter size. 4102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.mAdapterSize = state.getItemCount(); 4112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int anchorItemPosition; 4122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int anchorOffset; 4132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // This value may change if we are jumping to a position. 4142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean layoutFromEnd; 4152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // If set to true, spans will clear their offsets and they'll be laid out from start 4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // depending on the layout direction. Invalidating span offsets is necessary to be able 4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // to jump to a position. 4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean invalidateSpanOffsets = false; 4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "found saved state: " + mPendingSavedState); 4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setOrientation(mPendingSavedState.mOrientation); 4262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setSpanCount(mPendingSavedState.mSpanCount); 4272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setGapStrategy(mPendingSavedState.mGapStrategy); 4282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setReverseLayout(mPendingSavedState.mReverseLayout); 4292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar resolveShouldLayoutReverse(); 4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState.mAnchorPosition != RecyclerView.NO_POSITION) { 4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = mPendingSavedState.mAnchorPosition; 4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd; 4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutFromEnd = mShouldReverseLayout; 4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState.mHasSpanOffsets) { 4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].clear(); 4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].setLine(mPendingSavedState.mSpanOffsets[i]); 4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState.mSpanLookupSize > 1) { 4442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.mData = mPendingSavedState.mSpanLookup; 4452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 4482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar resolveShouldLayoutReverse(); 4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutFromEnd = mShouldReverseLayout; // get updated value. 4502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Validate scroll position if exists. 4536e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar if (!state.isPreLayout() && mPendingScrollPosition != RecyclerView.NO_POSITION) { 4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Validate it. 4552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) { 4562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = RecyclerView.NO_POSITION; 4572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 4582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4616e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar if (!state.isPreLayout() && mPendingScrollPosition != RecyclerView.NO_POSITION) { 4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState == null 4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar || mPendingSavedState.mAnchorPosition == RecyclerView.NO_POSITION 4642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar || !mPendingSavedState.mHasSpanOffsets) { 4652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // If item is visible, make it fully visible. 4662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final View child = findViewByPosition(mPendingScrollPosition); 4672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (child != null) { 4682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingScrollPositionOffset != INVALID_OFFSET) { 4692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use regular anchor position. 4702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorItemPosition = mShouldReverseLayout ? getLastChildPosition() 4712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getFirstChildPosition(); 4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutFromEnd) { 4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int target = mPrimaryOrientation.getEndAfterPadding() - 4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset; 4752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = target - mPrimaryOrientation.getDecoratedEnd(child); 4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int target = mPrimaryOrientation.getStartAfterPadding() + 4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset; 4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = target - mPrimaryOrientation.getDecoratedStart(child); 4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int startGap = mPrimaryOrientation.getDecoratedStart(child) 4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar - mPrimaryOrientation.getStartAfterPadding(); 4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int endGap = mPrimaryOrientation.getEndAfterPadding() - 4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.getDecoratedEnd(child); 4862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child); 4872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use regular anchor item, just offset the layout. 4882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorItemPosition = mShouldReverseLayout ? getLastChildPosition() 4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getFirstChildPosition(); 4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (childSize > mPrimaryOrientation.getTotalSpace()) { 4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Item does not fit. Fix depending on layout direction. 4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = layoutFromEnd ? mPrimaryOrientation.getEndAfterPadding() 4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (startGap < 0) { 4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = -startGap; 4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (endGap < 0) { 4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = endGap; 4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Nothing to do, just layout normal. 5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorItemPosition = mShouldReverseLayout ? getLastChildPosition() 5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getFirstChildPosition(); 5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = INVALID_OFFSET; 5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Child is not visible. Set anchor coordinate depending on in which direction 5072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // child will be visible. 5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorItemPosition = mPendingScrollPosition; 5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingScrollPositionOffset == INVALID_OFFSET) { 5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int position = calculateScrollDirectionForPosition( 5112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorItemPosition); 5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (position == LAYOUT_START) { 5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = mPrimaryOrientation.getStartAfterPadding(); 5142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutFromEnd = false; 5152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = mPrimaryOrientation.getEndAfterPadding(); 5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutFromEnd = true; 5182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutFromEnd) { 5212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = mPrimaryOrientation.getEndAfterPadding() 5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar - mPendingScrollPositionOffset; 5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = mPrimaryOrientation.getStartAfterPadding() 5252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar + mPendingScrollPositionOffset; 5262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateSpanOffsets = true; 5292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = INVALID_OFFSET; 5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorItemPosition = mPendingScrollPosition; 5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // We don't recycle views out of adapter order. This way, we can rely on the first or 5372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // last child as the anchor position. 538719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar anchorItemPosition = mShouldReverseLayout 539719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar ? findLastReferenceChildPosition(state.getItemCount()) 540719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar : findFirstReferenceChildPosition(state.getItemCount()); 5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar anchorOffset = INVALID_OFFSET; 5422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5430ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar if (getChildCount() > 0 && (mPendingSavedState == null || 5440ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar !mPendingSavedState.mHasSpanOffsets)) { 5450ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar if (invalidateSpanOffsets || mHasGaps) { 5462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 5472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Scroll to position is set, clear. 5482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].clear(); 5492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (anchorOffset != INVALID_OFFSET) { 5502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].setLine(anchorOffset); 5512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 5552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorOffset); 5562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 5582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "cached start-end lines for " + i + ":" + 5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].mCachedStart + ":" + mSpans[i].mCachedEnd); 5612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount; 5662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar detachAndScrapAttachedViews(recycler); 5672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Layout start. 5682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar updateLayoutStateToFillStart(anchorItemPosition, state); 5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (!layoutFromEnd) { 5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; 5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fill(recycler, mLayoutState, state); 5732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Layout end. 5752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar updateLayoutStateToFillEnd(anchorItemPosition, state); 5762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutFromEnd) { 5772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; 5782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fill(recycler, mLayoutState, state); 5802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() > 0) { 5822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout) { 5832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixEndGap(recycler, state, true); 5842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixStartGap(recycler, state, false); 5852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixStartGap(recycler, state, true); 5872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixEndGap(recycler, state, false); 5882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5916e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar if (!state.isPreLayout()) { 5926e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar mPendingScrollPosition = RecyclerView.NO_POSITION; 5936e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 5946e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar } 5952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLastLayoutFromEnd = layoutFromEnd; 5962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState = null; // we don't need this anymore 5972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 6002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Checks if a child is assigned to the non-optimal span. 6012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 6022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param startChildIndex Starts checking after this child, inclusive 6032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param endChildIndex Starts checking until this child, exclusive 6042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return The first View that is assigned to the wrong span. 6052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 6062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View hasGapsToFix(int startChildIndex, int endChildIndex) { 6072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // quick reject 6082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startChildIndex >= endChildIndex) { 6092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return null; 6102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int firstChildIndex, childLimit; 6122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int nextSpanDiff = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1; 6132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 6142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout) { 6152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar firstChildIndex = endChildIndex - 1; 6162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar childLimit = startChildIndex - 1; 6172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 6182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar firstChildIndex = startChildIndex; 6192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar childLimit = endChildIndex; 6202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1; 6222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) { 6232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(i); 6242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int start = mPrimaryOrientation.getDecoratedStart(child); 6252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int end = mPrimaryOrientation.getDecoratedEnd(child); 6262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); 6272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutParams.mFullSpan) { 6282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar continue; // quick reject 6292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int nextSpanIndex = layoutParams.getSpanIndex() + nextSpanDiff; 6312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (nextSpanIndex >= 0 && nextSpanIndex < mSpanCount) { 6322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span nextSpan = mSpans[nextSpanIndex]; 6332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (nextSpan.isEmpty(start, end)) { 6342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return child; 6352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar nextSpanIndex += nextSpanDiff; 6372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // everything looks good 6402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return null; 6412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 6432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 6442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean supportsPredictiveItemAnimations() { 6456e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar return mPendingSavedState == null; 6462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 648333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 649333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the first visible view for each span. 650333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 651333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 652333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 653333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 654333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 655333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 656333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 657333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 658333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 659333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 660333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @return The adapter position of the first visible item in each span. If a span does not have 661333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * any items, {@link RecyclerView#NO_POSITION} is returned for that span. 662333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 663333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 664333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 665333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstCompletelyVisibleItemPositions(int[]) 666333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastVisibleItemPositions(int[]) 667333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 668333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findFirstVisibleItemPositions(int[] into) { 669333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 670333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 671333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 672333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 673333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 674333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 675333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar for (int i = 0; i < mSpanCount; i ++) { 676333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findFirstVisibleItemPosition(); 677333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 678333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 679333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 680333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 681333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 682333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the first completely visible view for each span. 683333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 684333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 685333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 686333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 687333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 688333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 689333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 690333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 691333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 692333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 693333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @return The adapter position of the first fully visible item in each span. If a span does 694333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span. 695333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 696333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 697333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstVisibleItemPositions(int[]) 698333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastCompletelyVisibleItemPositions(int[]) 699333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 700333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findFirstCompletelyVisibleItemPositions(int[] into) { 701333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 702333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 703333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 704333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 705333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 706333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 707333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar for (int i = 0; i < mSpanCount; i ++) { 708333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition(); 709333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 710333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 711333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 712333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 713333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 714333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the last visible view for each span. 715333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 716333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 717333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 718333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 719333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 720333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 721333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 722333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 723333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 724333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 725333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @return The adapter position of the last visible item in each span. If a span does not have 726333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * any items, {@link RecyclerView#NO_POSITION} is returned for that span. 727333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 728333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 729333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 730333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastCompletelyVisibleItemPositions(int[]) 731333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstVisibleItemPositions(int[]) 732333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 733333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findLastVisibleItemPositions(int[] into) { 734333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 735333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 736333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 737333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 738333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 739333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 740333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar for (int i = 0; i < mSpanCount; i ++) { 741333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findLastVisibleItemPosition(); 742333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 743333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 744333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 745333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 746333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 747333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the last completely visible view for each span. 748333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 749333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 750333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 751333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 752333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 753333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 754333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 755333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 756333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 757333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 758333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @return The adapter position of the last fully visible item in each span. If a span does not 759333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * have any items, {@link RecyclerView#NO_POSITION} is returned for that span. 760333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 761333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 762333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 763333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstCompletelyVisibleItemPositions(int[]) 764333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastVisibleItemPositions(int[]) 765333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 766333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findLastCompletelyVisibleItemPositions(int[] into) { 767333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 768333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 769333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 770333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 771333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 772333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 773333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar for (int i = 0; i < mSpanCount; i ++) { 774333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findLastCompletelyVisibleItemPosition(); 775333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 776333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 777333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 778333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 7792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void measureChildWithDecorationsAndMargin(View child, int widthSpec, 7802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int heightSpec) { 7812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); 7822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 7832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + insets.left, 7842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.rightMargin + insets.right); 7852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + insets.top, 7862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.bottomMargin + insets.bottom); 7872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar child.measure(widthSpec, heightSpec); 7882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 7902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int updateSpecWithExtra(int spec, int startInset, int endInset) { 7912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startInset == 0 && endInset == 0) { 7922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return spec; 7932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int mode = View.MeasureSpec.getMode(spec); 7952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) { 7962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return View.MeasureSpec.makeMeasureSpec( 7972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View.MeasureSpec.getSize(spec) - startInset - endInset, mode); 7982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return spec; 8002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 8022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 8032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onRestoreInstanceState(Parcelable state) { 8042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (state instanceof SavedState) { 8052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState = (SavedState) state; 8062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 8072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (DEBUG) { 8082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "invalid saved state class"); 8092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 8122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 8132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public Parcelable onSaveInstanceState() { 8142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 8152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState(mPendingSavedState); 8162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar SavedState state = new SavedState(); 8182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mOrientation = mOrientation; 8192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mReverseLayout = mReverseLayout; 8202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanCount = mSpanCount; 8212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorLayoutFromEnd = mLastLayoutFromEnd; 8222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mGapStrategy = mGapStrategy; 8232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 8242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLazySpanLookup != null && mLazySpanLookup.mData != null) { 8252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookup = mLazySpanLookup.mData; 8262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookupSize = state.mSpanLookup.length; 8272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 8282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookupSize = 0; 8292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 8312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() > 0) { 8322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition() 8332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getFirstChildPosition(); 834333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt(); 8352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mHasSpanOffsets = true; 8362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanOffsets = new int[mSpanCount]; 8372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 8386b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar state.mSpanOffsets[i] = mLastLayoutFromEnd ? mSpans[i].getEndLine(Span.INVALID_LINE) 8396b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar : mSpans[i].getStartLine(Span.INVALID_LINE); 8402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 8422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorPosition = RecyclerView.NO_POSITION; 843333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar state.mVisibleAnchorPosition = RecyclerView.NO_POSITION; 8442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mHasSpanOffsets = false; 8452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 8472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "saved state:\n" + state); 8482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return state; 8502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 852333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 853333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Finds the first fully visible child to be used as an anchor child if span count changes when 854333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * state is restored. 855333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 856333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int findFirstVisibleItemPositionInt() { 857333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int start, end, diff; 858333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (mLastLayoutFromEnd) { 859333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar start = getChildCount() - 1; 860333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar end = -1; 861333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar diff = -1; 862333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else { 863333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar start = 0; 864333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar end = getChildCount(); 865333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar diff = 1; 866333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 867333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); 868333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); 869333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar for (int i = start; i != end; i += diff) { 870333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final View child = getChildAt(i); 871333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (mPrimaryOrientation.getDecoratedStart(child) >= boundsStart 872333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar && mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) { 873333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 874333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 875333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 876333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return RecyclerView.NO_POSITION; 877333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 878333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 8792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state, 8802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean canOffsetChildren) { 8812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); 8822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine; 8832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int fixOffset; 8842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gap > 0) { 8852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixOffset = -scrollBy(-gap, recycler, state); 8862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 8872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; // nothing to fix 8882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gap -= fixOffset; 8902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (canOffsetChildren && gap > 0) { 8912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(gap); 8922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 8942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 8952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state, 8962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean canOffsetChildren) { 8972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding()); 8982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding(); 8992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int fixOffset; 9002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gap > 0) { 9012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixOffset = scrollBy(gap, recycler, state); 9022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 9032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; // nothing to fix 9042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gap -= fixOffset; 9062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (canOffsetChildren && gap > 0) { 9072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(-gap); 9082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateLayoutStateToFillStart(int anchorPosition, RecyclerView.State state) { 9122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = 0; 9132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = anchorPosition; 9142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (isSmoothScrolling()) { 9152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetPos = state.getTargetScrollPosition(); 9162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout == targetPos < anchorPosition) { 9172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 9182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 9192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace(); 9202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 9222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 9232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_START; 9252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL 9262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_HEAD; 9272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateLayoutStateToFillEnd(int anchorPosition, RecyclerView.State state) { 9302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = 0; 9312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = anchorPosition; 9322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (isSmoothScrolling()) { 9332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetPos = state.getTargetScrollPosition(); 9342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout == targetPos > anchorPosition) { 9352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 9362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 9372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace(); 9382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 9402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 9412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_END; 9432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD 9442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_TAIL; 9452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 9482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void offsetChildrenHorizontal(int dx) { 9492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super.offsetChildrenHorizontal(dx); 9502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 9512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].onOffset(dx); 9522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 9562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void offsetChildrenVertical(int dy) { 9572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super.offsetChildrenVertical(dy); 9582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 9592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].onOffset(dy); 9602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 9642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { 9652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (!considerSpanInvalidate(positionStart, itemCount)) { 9662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // If positions are not invalidated, move span offsets. 9672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.offsetForRemoval(positionStart, itemCount); 9682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 9722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { 9732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (!considerSpanInvalidate(positionStart, itemCount)) { 9742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // If positions are not invalidated, move span offsets. 9752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.offsetForAddition(positionStart, itemCount); 9762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 9802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Checks whether it should invalidate span assignments in response to an adapter change. 9812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 9822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean considerSpanInvalidate(int positionStart, int itemCount) { 9832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition(); 9842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (positionStart + itemCount <= minPosition) { 9852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return false;// nothing to update. 9862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition(); 9882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.invalidateAfter(positionStart); 9892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (positionStart <= maxPosition) { 9902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 9912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return true; 9932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int fill(RecyclerView.Recycler recycler, LayoutState layoutState, 9962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 9972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(0, mSpanCount, true); 9982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // The target position we are trying to reach. 9992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetLine; 10002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /* 10022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The line until which we can recycle, as long as we add views. 10032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Keep in mind, it is still the line in layout direction which means; to calculate the 10042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * actual recycle line, we should subtract/add the size in orientation. 10052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 10062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int recycleLine; 10072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Line of the furthest row. 10082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 10093ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar // ignore padding for recycler 10100ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleLine = mPrimaryOrientation.getEndAfterPadding() + mLayoutState.mAvailable; 10110ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar targetLine = recycleLine + mLayoutState.mExtra + mPrimaryOrientation.getEndPadding(); 10122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getStartAfterPadding(); 10132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 10142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span span = mSpans[i]; 10152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getEndLine(defaultLine); 10162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line > targetLine) { 10172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(i, false); 10182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { // LAYOUT_START 10213ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar // ignore padding for recycler 10220ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleLine = mPrimaryOrientation.getStartAfterPadding() - mLayoutState.mAvailable; 10230ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar targetLine = recycleLine - mLayoutState.mExtra - 10240ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar mPrimaryOrientation.getStartAfterPadding(); 10252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 10262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span span = mSpans[i]; 10272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getEndAfterPadding(); 10282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getStartLine(defaultLine); 10292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line < targetLine) { 10302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(i, false); 10312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int widthSpec, heightSpec; 10362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL) { 10372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar widthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY); 10382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 10392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar heightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY); 10412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 10422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) { 10452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View view = layoutState.next(recycler); 10462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = ((LayoutParams) view.getLayoutParams()); 10472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 10482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar addView(view); 10492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar addView(view, 0); 10512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 10532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int fullSizeSpec = View.MeasureSpec.makeMeasureSpec( 10542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY); 10552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL) { 10562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar measureChildWithDecorationsAndMargin(view, fullSizeSpec, heightSpec); 10572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar measureChildWithDecorationsAndMargin(view, widthSpec, fullSizeSpec); 10592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar measureChildWithDecorationsAndMargin(view, widthSpec, heightSpec); 10622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int position = getPosition(view); 10652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanIndex = mLazySpanLookup.getSpan(position); 10662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span currentSpan; 10672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanIndex == LayoutParams.INVALID_SPAN_ID) { 10682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 10692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // assign full span items to first span 10702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan = mSpans[0]; 10712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan = getNextSpan(layoutState); 10732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.setSpan(position, currentSpan); 10752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan = mSpans[spanIndex]; 10772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int start; 10792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int end; 10802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 10812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int def = mShouldReverseLayout ? mPrimaryOrientation.getEndAfterPadding() 10822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 10832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar start = lp.mFullSpan ? getMaxEnd(def) : currentSpan.getEndLine(def); 10842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar end = start + mPrimaryOrientation.getDecoratedMeasurement(view); 10852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 10862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 10872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].appendToSpan(view); 10882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan.appendToSpan(view); 10912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int def = mShouldReverseLayout ? mPrimaryOrientation.getEndAfterPadding() 10942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 10952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar end = lp.mFullSpan ? getMinStart(def) : currentSpan.getStartLine(def); 10962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar start = end - mPrimaryOrientation.getDecoratedMeasurement(view); 10972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 10982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 10992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].prependToSpan(view); 11002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan.prependToSpan(view); 11032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = currentSpan; 11072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 11092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "adding view item " + lp.getViewPosition() + " between " + start + "," 11102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar + end); 11112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding() 11142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : currentSpan.mIndex * mSizePerSpan + mSecondaryOrientation 11152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .getStartAfterPadding(); 11162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view); 11172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL) { 11182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end); 11192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd); 11212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 11232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 11242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar updateRemainingSpans(mSpans[i], mLayoutState.mLayoutDirection, targetLine); 11252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine); 11282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLayoutState.mLayoutDirection == LAYOUT_START) { 11302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // calculate recycle line 11312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxStart = getMaxStart(currentSpan.getStartLine()); 11320ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleFromEnd(recycler, Math.max(recycleLine, maxStart) + 11330ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding())); 11342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // calculate recycle line 11362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minEnd = getMinEnd(currentSpan.getEndLine()); 11370ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleFromStart(recycler, Math.min(recycleLine, minEnd) - 11380ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding())); 11392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 11422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "fill, " + getChildCount()); 11432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLayoutState.mLayoutDirection == LAYOUT_START) { 11452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding()); 11460ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar return Math.max(0, mLayoutState.mAvailable + (recycleLine - minStart)); 11472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int max = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); 11490ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar return Math.max(0, mLayoutState.mAvailable + (max - recycleLine)); 11502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void layoutDecoratedWithMargins(View child, int left, int top, int right, 11542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int bottom) { 11552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 11562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin 11572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar , bottom - lp.bottomMargin); 11582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateRemainingSpans(Span span, int layoutDir, int targetLine) { 11612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int deletedSize = span.getDeletedSize(); 11622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutDir == LAYOUT_START) { 11632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getStartLine(); 11642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line + deletedSize < targetLine) { 11652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(span.mIndex, false); 11662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getEndLine(); 11692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line - deletedSize > targetLine) { 11702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(span.mIndex, false); 11712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMaxStart(int def) { 11762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxStart = mSpans[0].getStartLine(def); 11772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 11782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanStart = mSpans[i].getStartLine(def); 11792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanStart > maxStart) { 11802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxStart = spanStart; 11812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return maxStart; 11842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMinStart(int def) { 11872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minStart = mSpans[0].getStartLine(def); 11882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 11892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanStart = mSpans[i].getStartLine(def); 11902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanStart < minStart) { 11912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minStart = spanStart; 11922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return minStart; 11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMaxEnd(int def) { 11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxEnd = mSpans[0].getEndLine(def); 11992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanEnd = mSpans[i].getEndLine(def); 12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanEnd > maxEnd) { 12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxEnd = spanEnd; 12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return maxEnd; 12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMinEnd(int def) { 12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minEnd = mSpans[0].getEndLine(def); 12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanEnd = mSpans[i].getEndLine(def); 12122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanEnd < minEnd) { 12132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minEnd = spanEnd; 12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return minEnd; 12172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void recycleFromStart(RecyclerView.Recycler recycler, int line) { 12202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 12212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "recycling from start for line " + line); 12222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (getChildCount() > 0) { 12242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(0); 12252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedEnd(child) < line) { 12262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 12272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 12282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int j = 0; j < mSpanCount; j++) { 12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[j].popStart(); 12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan.popStart(); 12332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar removeAndRecycleView(child, recycler); 12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return;// done 12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void recycleFromEnd(RecyclerView.Recycler recycler, int line) { 12422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 12432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int i; 12442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (i = childCount - 1; i >= 0; i--) { 12452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(i); 12462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(child) > line) { 12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 12482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 12492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int j = 0; j < mSpanCount; j++) { 12502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[j].popEnd(); 12512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan.popEnd(); 12542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar removeAndRecycleView(child, recycler); 12562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return;// done 12582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 12632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Finds the span for the next view. 12642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 12652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span getNextSpan(LayoutState layoutState) { 12662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final boolean preferLastSpan = mOrientation == VERTICAL && isLayoutRTL(); 12672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 12682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span min = mSpans[0]; 12692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minLine = min.getEndLine(mPrimaryOrientation.getStartAfterPadding()); 12702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getStartAfterPadding(); 12712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 12722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span other = mSpans[i]; 12732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherLine = other.getEndLine(defaultLine); 12742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (otherLine < minLine || (otherLine == minLine && preferLastSpan)) { 12752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar min = other; 12762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minLine = otherLine; 12772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return min; 12802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span max = mSpans[0]; 12822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxLine = max.getStartLine(mPrimaryOrientation.getEndAfterPadding()); 12832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getEndAfterPadding(); 12842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 12852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span other = mSpans[i]; 12862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherLine = other.getStartLine(defaultLine); 12872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (otherLine > maxLine || (otherLine == maxLine && !preferLastSpan)) { 12882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar max = other; 12892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxLine = otherLine; 12902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return max; 12932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean canScrollVertically() { 12982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation == VERTICAL; 12992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 13022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean canScrollHorizontally() { 13032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation == HORIZONTAL; 13042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 13072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 13082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 13092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return scrollBy(dx, recycler, state); 13102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 13132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 13142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 13152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return scrollBy(dy, recycler, state); 13162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int calculateScrollDirectionForPosition(int position) { 13192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() == 0) { 13202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START; 13212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int firstChildPos = getFirstChildPosition(); 13232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; 13242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 13272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 13282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int position) { 13292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) { 13302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 13312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 13322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int direction = calculateScrollDirectionForPosition(targetPosition); 13332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (direction == 0) { 13342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return null; 13352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == HORIZONTAL) { 13372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new PointF(direction, 0); 13382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 13392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new PointF(0, direction); 13402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar }; 13432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar scroller.setTargetPosition(position); 13442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar startSmoothScroll(scroller); 13452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 13482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void scrollToPosition(int position) { 13492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) { 13502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateAnchorPositionInfo(); 13512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = position; 13532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 13542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 13552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 13582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Scroll to the specified adapter position with the given offset from layout start. 13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 13602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Note that scroll position change will not be reflected until the next layout call. 13612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 13622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}. 13632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 13642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param position Index (starting at 0) of the reference item. 13652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param offset The distance (in pixels) between the start edge of the item view and 13662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * start edge of the RecyclerView. 13672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setReverseLayout(boolean) 13682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #scrollToPosition(int) 13692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 13702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void scrollToPositionWithOffset(int position, int offset) { 13712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 13722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateAnchorPositionInfo(); 13732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = position; 13752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = offset; 13762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 13772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) { 13802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureOrientationHelper(); 13812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int referenceChildPosition; 13822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (dt > 0) { // layout towards end 13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_END; 13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD 13852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_TAIL; 13862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar referenceChildPosition = getLastChildPosition(); 13872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_START; 13892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL 13902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_HEAD; 13912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar referenceChildPosition = getFirstChildPosition(); 13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection; 13942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int absDt = Math.abs(dt); 13952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = absDt; 13962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = isSmoothScrolling() ? mPrimaryOrientation.getTotalSpace() : 0; 13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int consumed = fill(recycler, mLayoutState, state); 13982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int totalScroll; 13992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (absDt < consumed) { 14002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = dt; 14012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (dt < 0) { 14022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = -consumed; 14032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { // dt > 0 14042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = consumed; 14052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 14072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "asked " + dt + " scrolled" + totalScroll); 14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 14102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mGapStrategy == GAP_HANDLING_LAZY 14112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar && mLayoutState.mItemDirection == ITEM_DIRECTION_HEAD) { 14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetStart = mPrimaryOrientation.getStartAfterPadding(); 14132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetEnd = mPrimaryOrientation.getEndAfterPadding(); 14142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lazyOffsetSpans(-totalScroll, targetStart, targetEnd); 14152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(-totalScroll); 14172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // always reset this if we scroll for a proper save instance state 14192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLastLayoutFromEnd = mShouldReverseLayout; 14202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 14212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (totalScroll != 0 && mGapStrategy != GAP_HANDLING_NONE 14222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar && mLayoutState.mItemDirection == ITEM_DIRECTION_HEAD && !mHasGaps) { 14232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int addedChildCount = Math.abs(mLayoutState.mCurrentPosition 14242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar - (referenceChildPosition + mLayoutState.mItemDirection)); 14252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (addedChildCount > 0) { 14262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // check if any child has been attached to wrong span. If so, trigger a re-layout 14272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // after scroll 14282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final View viewInWrongSpan; 14292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final View referenceView = findViewByPosition(referenceChildPosition); 14302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (referenceView == null) { 14312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar viewInWrongSpan = hasGapsToFix(0, getChildCount()); 14322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLayoutState.mLayoutDirection == LAYOUT_START) { 14342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar viewInWrongSpan = hasGapsToFix(0, addedChildCount); 14352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar viewInWrongSpan = hasGapsToFix(getChildCount() - addedChildCount, 14372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar getChildCount()); 14382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mHasGaps = viewInWrongSpan != null; 14412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return totalScroll; 14442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 14462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 14472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The actual method that implements {@link #GAP_HANDLING_LAZY} 14482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 14492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void lazyOffsetSpans(int offset, int targetStart, int targetEnd) { 14502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // For each span offset children one by one. 14512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // When a fullSpan item is reached, stop and wait for other spans to reach to that span. 14522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // When all reach, offset fullSpan to max of others and continue. 14532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int childrenToOffset = getChildCount(); 14542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] indexPerSpan = new int[mSpanCount]; 14552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] offsetPerSpan = new int[mSpanCount]; 14562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 14572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childOrder = offset > 0 ? ITEM_DIRECTION_TAIL : ITEM_DIRECTION_HEAD; 14582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (offset > 0) { 14592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(indexPerSpan, 0); 14602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 14622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar indexPerSpan[i] = mSpans[i].mViews.size() - 1; 14632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 14662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 14672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar offsetPerSpan[i] = mSpans[i].getNormalizedOffset(offset, targetStart, targetEnd); 14682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 14702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "lazy offset start. normalized: " + Arrays.toString(offsetPerSpan)); 14712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 14732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (childrenToOffset > 0) { 14742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View fullSpanView = null; 14752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int spanIndex = 0; spanIndex < mSpanCount; spanIndex++) { 14762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span span = mSpans[spanIndex]; 14772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int viewIndex; 14782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (viewIndex = indexPerSpan[spanIndex]; 14792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar viewIndex < span.mViews.size() && viewIndex >= 0; viewIndex += childOrder) { 14802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View view = span.mViews.get(viewIndex); 14812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 14822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "span " + spanIndex + ", view:" + viewIndex + ", pos:" 14832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar + getPosition(view)); 14842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) view.getLayoutParams(); 14862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 14872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 14882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "stopping on full span view on index " + viewIndex 14892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar + " in span " + spanIndex); 14902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fullSpanView = view; 14922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar viewIndex += childOrder;// move to next view 14932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar break; 14942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // offset this child normally 14962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChild(view, offsetPerSpan[spanIndex]); 14972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int nextChildIndex = viewIndex + childOrder; 14982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (nextChildIndex < span.mViews.size() && nextChildIndex >= 0) { 14992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View nextView = span.mViews.get(nextChildIndex); 15002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // find gap between, before offset 15012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (childOrder == ITEM_DIRECTION_HEAD) {// negative 15022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar offsetPerSpan[spanIndex] = Math 15032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .min(0, mPrimaryOrientation.getDecoratedStart(view) 15042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar - mPrimaryOrientation.getDecoratedEnd(nextView)); 15052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar offsetPerSpan[spanIndex] = Math 15072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .max(0, mPrimaryOrientation.getDecoratedEnd(view) - 15082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.getDecoratedStart(nextView)); 15092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 15112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "offset diff:" + offsetPerSpan[spanIndex] + " between " 15122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar + getPosition(nextView) + " and " + getPosition(view)); 15132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar childrenToOffset--; 15162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar indexPerSpan[spanIndex] = viewIndex; 15182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (fullSpanView != null) { 15202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // we have to offset this view. We'll offset it as the biggest amount necessary 15212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int winnerSpan = 0; 15222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int winnerSpanOffset = Math.abs(offsetPerSpan[winnerSpan]); 15232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanOffset = Math.abs(offsetPerSpan[i]); 15252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanOffset > winnerSpanOffset) { 15262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar winnerSpan = i; 15272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar winnerSpanOffset = spanOffset; 15282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 15312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "winner offset:" + offsetPerSpan[winnerSpan] + " of " + winnerSpan); 15322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChild(fullSpanView, offsetPerSpan[winnerSpan]); 15342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar childrenToOffset--; 15352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int spanIndex = 0; spanIndex < mSpanCount; spanIndex++) { 15372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int nextViewIndex = indexPerSpan[spanIndex]; 15382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span span = mSpans[spanIndex]; 15392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (nextViewIndex < span.mViews.size() && nextViewIndex > 0) { 15402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View nextView = span.mViews.get(nextViewIndex); 15412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // find gap between, before offset 15422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (childOrder == ITEM_DIRECTION_HEAD) {// negative 15432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar offsetPerSpan[spanIndex] = Math 15442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .min(0, mPrimaryOrientation.getDecoratedStart(fullSpanView) 15452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar - mPrimaryOrientation.getDecoratedEnd(nextView)); 15462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar offsetPerSpan[spanIndex] = Math 15482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .max(0, mPrimaryOrientation.getDecoratedEnd(fullSpanView) - 15492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.getDecoratedStart(nextView)); 15502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int spanIndex = 0; spanIndex < mSpanCount; spanIndex++) { 15562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[spanIndex].invalidateCache(); 15572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getLastChildPosition() { 15612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 15622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1)); 15632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getFirstChildPosition() { 15662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 15672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return childCount == 0 ? 0 : getPosition(getChildAt(0)); 15682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1570719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar /** 1571719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * Finds the first View that can be used as an anchor View. 1572719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * 1573719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * @return Position of the View or 0 if it cannot find any such View. 1574719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar */ 1575719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar private int findFirstReferenceChildPosition(int itemCount) { 1576719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int limit = getChildCount(); 1577719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar for (int i = 0; i < limit; i++) { 1578719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final View view = getChildAt(i); 1579719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int position = getPosition(view); 1580719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar if (position >= 0 && position < itemCount) { 1581719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return position; 1582719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1583719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1584719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return 0; 1585719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1586719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar 1587719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar /** 1588719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * Finds the last View that can be used as an anchor View. 1589719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * 1590719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * @return Position of the View or 0 if it cannot find any such View. 1591719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar */ 1592719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar private int findLastReferenceChildPosition(int itemCount) { 1593719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar for (int i = getChildCount() - 1; i >= 0; i--) { 1594719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final View view = getChildAt(i); 1595719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int position = getPosition(view); 1596719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar if (position >= 0 && position < itemCount) { 1597719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return position; 1598719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1599719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1600719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return 0; 1601719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1602719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar 16032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateDefaultLayoutParams() { 16052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 16062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 16072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { 16112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(c, attrs); 16122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 16162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp instanceof ViewGroup.MarginLayoutParams) { 16172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams((ViewGroup.MarginLayoutParams) lp); 16182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 16192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(lp); 16202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { 16252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return lp instanceof LayoutParams; 16262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getOrientation() { 16292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation; 16302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 16342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * LayoutParams used by StaggeredGridLayoutManager. 16352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 16362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static class LayoutParams extends RecyclerView.LayoutParams { 16372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 16392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Span Id for Views that are not laid out yet. 16402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 16412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int INVALID_SPAN_ID = -1; 16422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Package scope to be able to access from tests. 16442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span mSpan; 16452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mFullSpan; 16472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(Context c, AttributeSet attrs) { 16492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(c, attrs); 16502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(int width, int height) { 16532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(width, height); 16542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(ViewGroup.MarginLayoutParams source) { 16572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 16582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(ViewGroup.LayoutParams source) { 16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(RecyclerView.LayoutParams source) { 16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 16662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When set to true, the item will layout using all span area. That means, if orientation 16702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * is vertical, the view will have full width; if orientation is horizontal, the view will 16712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * have full height. 16722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 16732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param fullSpan True if this item should traverse all spans. 16742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 16752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setFullSpan(boolean fullSpan) { 16762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mFullSpan = fullSpan; 16772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 16802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the Span index to which this View is assigned. 16812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return The Span index of the View. If View is not yet assigned to any span, returns 16832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #INVALID_SPAN_ID}. 16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public final int getSpanIndex() { 16862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpan == null) { 16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return INVALID_SPAN_ID; 16882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mSpan.mIndex; 16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Package scoped to access from tests. 16942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar class Span { 16952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16966b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar static final int INVALID_LINE = Integer.MIN_VALUE; 16972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private ArrayList<View> mViews = new ArrayList<View>(); 16992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mCachedStart = INVALID_LINE; 17012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mCachedEnd = INVALID_LINE; 17032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mDeletedSize = 0; 17052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int mIndex; 17072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span(int index) { 17092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mIndex = index; 17102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getStartLine(int def) { 17132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 17142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 17152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 17172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return def; 17182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = mPrimaryOrientation.getDecoratedStart(mViews.get(0)); 17202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 17212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use this one when default value does not make sense and not having a value means a bug. 17242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getStartLine() { 17252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 17262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 17272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = mPrimaryOrientation.getDecoratedStart(mViews.get(0)); 17292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 17302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getEndLine(int def) { 17332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 17342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 17352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int size = mViews.size(); 17372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (size == 0) { 17382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return def; 17392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = mPrimaryOrientation.getDecoratedEnd(mViews.get(size - 1)); 17412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 17422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use this one when default value does not make sense and not having a value means a bug. 17452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getEndLine() { 17462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 17472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 17482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = mPrimaryOrientation.getDecoratedEnd(mViews.get(mViews.size() - 1)); 17502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 17512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void prependToSpan(View view) { 17542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = getLayoutParams(view); 17552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = this; 17562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.add(0, view); 17572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 17582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 1) { 17592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 17602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 17622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); 17632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void appendToSpan(View view) { 17672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = getLayoutParams(view); 17682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = this; 17692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.add(view); 17702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 17712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 1) { 17722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 17732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 17752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); 17762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Useful method to preserve positions on a re-layout. 17802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void cacheReferenceLineAndClear(boolean reverseLayout, int offset) { 17812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int reference; 17822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (reverseLayout) { 17832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference = getEndLine(INVALID_LINE); 17842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 17852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference = getStartLine(INVALID_LINE); 17862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar clear(); 17882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (reference == INVALID_LINE) { 17892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (offset != INVALID_OFFSET) { 17922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference += offset; 17932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = mCachedEnd = reference; 17952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void clear() { 17982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.clear(); 17992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateCache(); 18002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize = 0; 18012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateCache() { 18042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 18052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 18062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void setLine(int line) { 18092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = mCachedStart = line; 18102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void popEnd() { 18132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int size = mViews.size(); 18142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View end = mViews.remove(size - 1); 18152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final LayoutParams lp = getLayoutParams(end); 18162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = null; 18177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 18182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end); 18192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (size == 1) { 18212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 18222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void popStart() { 18272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View start = mViews.remove(0); 18282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final LayoutParams lp = getLayoutParams(start); 18292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = null; 18302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 18312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 18322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 18342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start); 18352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 18372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // TODO cache this. 18402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getDeletedSize() { 18412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mDeletedSize; 18422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams getLayoutParams(View view) { 18452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return (LayoutParams) view.getLayoutParams(); 18462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void onOffset(int dt) { 18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart += dt; 18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd += dt; 18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // normalized offset is how much this span can scroll 18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getNormalizedOffset(int dt, int targetStart, int targetEnd) { 18592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (dt < 0) { 18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int endSpace = getEndLine() - targetEnd; 18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (endSpace <= 0) { 18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return -dt > endSpace ? -endSpace : dt; 18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int startSpace = targetStart - getStartLine(); 18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startSpace <= 0) { 18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 18722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return startSpace < dt ? startSpace : dt; 18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 18782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns if there is no child between start-end lines 18792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 18802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param start The start line 18812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param end The end line 18822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return true if a new child can be added between start and end 18832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 18842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean isEmpty(int start, int end) { 18852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int count = mViews.size(); 18862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < count; i++) { 18872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final View view = mViews.get(i); 18882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(view) < end && 18892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.getDecoratedEnd(view) > start) { 18902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return false; 18912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return true; 18942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1895333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 1896333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findFirstVisibleItemPosition() { 1897333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 1898333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(mViews.size() - 1, -1, false) 1899333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(0, mViews.size(), false); 1900333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1901333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 1902333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findFirstCompletelyVisibleItemPosition() { 1903333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 1904333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(mViews.size() -1, -1, true) 1905333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(0, mViews.size(), true); 1906333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1907333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 1908333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findLastVisibleItemPosition() { 1909333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 1910333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(0, mViews.size(), false) 1911333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(mViews.size() - 1, -1, false); 1912333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1913333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 1914333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findLastCompletelyVisibleItemPosition() { 1915333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 1916333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(0, mViews.size(), true) 1917333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(mViews.size() - 1, -1, true); 1918333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1919333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 1920333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) { 1921333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int start = mPrimaryOrientation.getStartAfterPadding(); 1922333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int end = mPrimaryOrientation.getEndAfterPadding(); 1923333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int next = toIndex > fromIndex ? 1 : -1; 1924333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar for (int i = fromIndex; i != toIndex; i+=next) { 1925333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final View child = mViews.get(i); 1926333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int childStart = mPrimaryOrientation.getDecoratedStart(child); 1927333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); 1928333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (childStart < end && childEnd > start) { 1929333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (completelyVisible) { 1930333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (childStart >= start && childEnd <= end) { 1931333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 1932333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1933333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else { 1934333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 1935333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1936333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1937333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1938333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return RecyclerView.NO_POSITION; 1939333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 19402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 19432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * An array of mappings from adapter position to span. 19442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * This only grows when a write happens and it grows up to the size of the adapter. 19452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 19462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar static class LazySpanLookup { 19472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final int MIN_SIZE = 10; 19492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mData; 19512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mAdapterSize; // we don't want to grow beyond that, unless it grows 19532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateAfter(int position) { 19552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null) { 19562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 19572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (position >= mData.length) { 19592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 19602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID); 19622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getSpan(int position) { 19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null || position >= mData.length) { 19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return LayoutParams.INVALID_SPAN_ID; 19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 19682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mData[position]; 19692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void setSpan(int position, Span span) { 19732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(position); 19742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData[position] = span.mIndex; 19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int sizeForPosition(int position) { 19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int len = mData.length; 19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (len <= position) { 19802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar len *= 2; 19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (len > mAdapterSize) { 19832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar len = mAdapterSize; 19842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return len; 19862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void ensureSize(int position) { 19892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null) { 19902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData = new int[Math.max(position, MIN_SIZE) + 1]; 19912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); 19922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (position >= mData.length) { 19932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] old = mData; 19942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData = new int[sizeForPosition(position)]; 19952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(old, 0, mData, 0, old.length); 19962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID); 19972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void clear() { 20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData != null) { 20022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); 20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void offsetForRemoval(int positionStart, int itemCount) { 20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(positionStart + itemCount); 20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(mData, positionStart + itemCount, mData, positionStart, 20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData.length - positionStart - itemCount); 20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, mData.length - itemCount, mData.length, 20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams.INVALID_SPAN_ID); 20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void offsetForAddition(int positionStart, int itemCount) { 20152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(positionStart + itemCount); 20162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(mData, positionStart, mData, positionStart + itemCount, 20172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData.length - positionStart - itemCount); 20182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, positionStart, positionStart + itemCount, 20192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams.INVALID_SPAN_ID); 20202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar static class SavedState implements Parcelable { 20242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mOrientation; 20262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mSpanCount; 20282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mGapStrategy; 20302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mAnchorPosition; 20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2033333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int mVisibleAnchorPosition; // if span count changes (span offsets are invalidated), 2034333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar // we use this one instead 2035333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mSpanOffsets; 20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mSpanLookupSize; 20392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mSpanLookup; 20412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mReverseLayout; 20432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mAnchorLayoutFromEnd; 20452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mHasSpanOffsets; 20472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState() { 20492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar SavedState(Parcel in) { 20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = in.readInt(); 20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanCount = in.readInt(); 20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mGapStrategy = in.readInt(); 20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = in.readInt(); 2056333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = in.readInt(); 20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mHasSpanOffsets = in.readInt() == 1; 20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mHasSpanOffsets) { 20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = new int[mSpanCount]; 20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar in.readIntArray(mSpanOffsets); 20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = in.readInt(); 20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpanLookupSize > 0) { 20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = new int[mSpanLookupSize]; 20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar in.readIntArray(mSpanLookup); 20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = in.readInt() == 1; 20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorLayoutFromEnd = in.readInt() == 1; 20702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState(SavedState other) { 20732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = other.mOrientation; 20742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanCount = other.mSpanCount; 20752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mGapStrategy = other.mGapStrategy; 20762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = other.mAnchorPosition; 2077333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = other.mVisibleAnchorPosition; 20782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mHasSpanOffsets = other.mHasSpanOffsets; 20792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = other.mSpanOffsets; 20802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = other.mSpanLookupSize; 20812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = other.mSpanLookup; 20822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = other.mReverseLayout; 20832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd; 20842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateSpanInfo() { 20872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = null; 20882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mHasSpanOffsets = false; 20892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanCount = -1; 20902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = 0; 20912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = null; 20922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateAnchorPositionInfo() { 20952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = null; 20962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mHasSpanOffsets = false; 20972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = RecyclerView.NO_POSITION; 2098333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = RecyclerView.NO_POSITION; 20992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 21022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int describeContents() { 21032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 21042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 21072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void writeToParcel(Parcel dest, int flags) { 21082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mOrientation); 21092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mSpanCount); 21102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mGapStrategy); 21112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mAnchorPosition); 2112333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar dest.writeInt(mVisibleAnchorPosition); 21132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mHasSpanOffsets ? 1 : 0); 21142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mHasSpanOffsets) { 21152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeIntArray(mSpanOffsets); 21162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mSpanLookupSize); 21182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpanLookupSize > 0) { 21192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeIntArray(mSpanLookup); 21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mReverseLayout ? 1 : 0); 21222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0); 21232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 21262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public String toString() { 21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return "SavedState{" + 21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar "mOrientation=" + mOrientation + 21292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mSpanCount=" + mSpanCount + 21302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mGapStrategy=" + mGapStrategy + 21312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mAnchorPosition=" + mAnchorPosition + 2132333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ", mVisibleAnchorPosition=" + mVisibleAnchorPosition + 21332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mSpanOffsets=" + Arrays.toString(mSpanOffsets) + 21342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mSpanLookupSize=" + mSpanLookupSize + 21352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mSpanLookup=" + Arrays.toString(mSpanLookup) + 21362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mReverseLayout=" + mReverseLayout + 21372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mAnchorLayoutFromEnd=" + mAnchorLayoutFromEnd + 21382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ", mHasSpanOffsets=" + mHasSpanOffsets + 21392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar '}'; 21402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final Parcelable.Creator<SavedState> CREATOR 21432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar = new Parcelable.Creator<SavedState>() { 21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 21452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState createFromParcel(Parcel in) { 21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState(in); 21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState[] newArray(int size) { 21512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState[size]; 21522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar }; 21542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar} 2156