StaggeredGridLayoutManager.java revision 7499c6e5b853057aa81bfc20c39e6fa188805c55
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; 25a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityEventCompat; 26a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 27a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityRecordCompat; 282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.AttributeSet; 292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.Log; 302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.View; 312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.ViewGroup; 32a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.accessibility.AccessibilityEvent; 332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.ArrayList; 352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.Arrays; 362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.BitSet; 37d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarimport java.util.List; 382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START; 402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END; 412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_HEAD; 422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_TAIL; 43d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION; 44d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/** 462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * A LayoutManager that lays out children in a staggered grid formation. 472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It supports horizontal & vertical layout as well as an ability to layout children in reverse. 482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps, 502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * StaggeredGridLayoutManager can offset spans independently or move items between spans. You can 512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * control this behavior via {@link #setGapStrategy(int)}. 522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarpublic class StaggeredGridLayoutManager extends RecyclerView.LayoutManager { 542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final String TAG = "StaggeredGridLayoutManager"; 562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final boolean DEBUG = false; 582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5903a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; 6003a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar 6103a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar public static final int VERTICAL = OrientationHelper.VERTICAL; 6203a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar 632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 64d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Does not do anything to hide gaps. 652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_NONE = 0; 672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 68d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Deprecated 692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_LAZY = 1; 702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 72d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * When scroll state is changed to {@link RecyclerView#SCROLL_STATE_IDLE}, StaggeredGrid will 73d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * check if there are gaps in the because of full span items. If it finds, it will re-layout 74d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * and move items to correct positions with animations. 752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For example, if LayoutManager ends up with the following layout due to adapter changes: 772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * AAA 792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * _BC 802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DDD 812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It will animate to the following state: 832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <code> 842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * AAA 852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BC_ 862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DDD 872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * </code> 882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; 902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final int INVALID_OFFSET = Integer.MIN_VALUE; 922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Number of spans 952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mSpanCount = -1; 972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span[] mSpans; 992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Primary orientation is the layout's orientation, secondary orientation is the orientation 1022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * for spans. Having both makes code much cleaner for calculations. 1032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper mPrimaryOrientation; 1052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper mSecondaryOrientation; 1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mOrientation; 1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The width or height per span, depending on the orientation. 1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mSizePerSpan; 1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private LayoutState mLayoutState; 1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mReverseLayout = false; 1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Aggregated reverse layout value that takes RTL into account. 1202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 121d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mShouldReverseLayout = false; 1222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Temporary variable used during fill method to check which spans needs to be filled. 1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private BitSet mRemainingSpans; 1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When LayoutManager needs to scroll to a position, it sets this variable and requests a 1302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * layout which will check this variable and re-layout accordingly. 1312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 132d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mPendingScrollPosition = NO_POSITION; 1332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is 1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * called. 1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1386e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar int mPendingScrollPositionOffset = INVALID_OFFSET; 1392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Keeps the mapping between the adapter positions and spans. This is necessary to provide 1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * a consistent experience when user scrolls the list. 1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LazySpanLookup mLazySpanLookup = new LazySpanLookup(); 1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * how we handle gaps in UI. 1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS; 1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Saved state needs this information to properly layout on restore. 1532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mLastLayoutFromEnd; 1552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 157d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Saved state and onLayout needs this information to re-layout properly 158d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean mLastLayoutRTL; 160d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 161d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 1622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * SavedState is not handled until a layout happens. This is where we keep it until next 1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * layout. 1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private SavedState mPendingSavedState; 1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 168d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Re-used measurement specs. updated by onLayout. 1692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 170d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int mFullSizeSpec, mWidthSpec, mHeightSpec; 171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 172d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Re-used anchor info. 174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 175d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private final AnchorInfo mAnchorInfo = new AnchorInfo(); 176d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * If a full span item is invalid / or created in reverse direction; it may create gaps in 179d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * the UI. While laying out, if such case is detected, we set this flag. 180d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * <p> 181d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * After scrolling stops, we check this flag and if it is set, re-layout. 182d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 183d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean mLaidOutInvalidFullSpan = false; 184d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 185d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 186d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}. 187d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)} 188d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 189d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean mSmoothScrollbarEnabled = true; 190d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 191d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private final Runnable checkForGapsRunnable = new Runnable() { 192d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 193d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void run() { 194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar checkForGaps(); 195d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 196d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar }; 1972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Creates a StaggeredGridLayoutManager with given parameters. 2002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 2012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param spanCount If orientation is vertical, spanCount is number of columns. If 2022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * orientation is horizontal, spanCount is number of rows. 2039bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL} 2042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 2052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public StaggeredGridLayoutManager(int spanCount, int orientation) { 2062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = orientation; 2072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setSpanCount(spanCount); 2082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 210d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Checks for gaps in the UI that may be caused by adapter changes. 212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * <p> 213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * When a full span item is laid out in reverse direction, it sets a flag which we check when 214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * scroll is stopped (or re-layout happens) and re-layout after first valid item. 215d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void checkForGaps() { 217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0 || mGapStrategy == GAP_HANDLING_NONE) { 218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int minPos, maxPos; 221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar minPos = getLastChildPosition(); 223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar maxPos = getFirstChildPosition(); 224d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar minPos = getFirstChildPosition(); 226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar maxPos = getLastChildPosition(); 227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (minPos == 0) { 229d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View gapView = hasGapsToFix(); 230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (gapView != null) { 231d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.clear(); 232d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestSimpleAnimationsInNextLayout(); 233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestLayout(); 234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 235d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 236d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 237d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!mLaidOutInvalidFullSpan) { 238d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 239d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 240d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int invalidGapDir = mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; 241d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LazySpanLookup.FullSpanItem invalidFsi = mLazySpanLookup 242d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar .getFirstFullSpanItemInRange(minPos, maxPos + 1, invalidGapDir); 243d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (invalidFsi == null) { 244d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan = false; 245d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.forceInvalidateAfter(maxPos + 1); 246d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 247d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 248d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LazySpanLookup.FullSpanItem validFsi = mLazySpanLookup 249d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar .getFirstFullSpanItemInRange(minPos, invalidFsi.mPosition, 250d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar invalidGapDir * -1); 251d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (validFsi == null) { 252d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.forceInvalidateAfter(invalidFsi.mPosition); 253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.forceInvalidateAfter(validFsi.mPosition + 1); 255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestSimpleAnimationsInNextLayout(); 257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestLayout(); 258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onScrollStateChanged(int state) { 262d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (state == RecyclerView.SCROLL_STATE_IDLE) { 263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar checkForGaps(); 264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 269d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 270d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].clear(); 271d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 272d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 273d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 274d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Checks for gaps if we've reached to the top of the list. 276d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * <p> 277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Intermediate gaps created by full span items are tracked via mLaidOutInvalidFullSpan field. 278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View hasGapsToFix() { 280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int startChildIndex = 0; 281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int endChildIndex = getChildCount() - 1; 282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar BitSet mSpansToCheck = new BitSet(mSpanCount); 283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpansToCheck.set(0, mSpanCount, true); 284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int firstChildIndex, childLimit; 286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int preferredSpanDir = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1; 287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar firstChildIndex = endChildIndex - 1; 290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar childLimit = startChildIndex - 1; 291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar firstChildIndex = startChildIndex; 293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar childLimit = endChildIndex; 294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1; 296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) { 297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View child = getChildAt(i); 298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mSpansToCheck.get(lp.mSpan.mIndex)) { 300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (checkSpanForGap(lp.mSpan)) { 301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child; 302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpansToCheck.clear(lp.mSpan.mIndex); 304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; // quick reject 307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (i + nextChildDiff != childLimit) { 310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View nextChild = getChildAt(i + nextChildDiff); 311d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean compareSpans = false; 312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // ensure child's end is below nextChild's end 314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int myEnd = mPrimaryOrientation.getDecoratedEnd(child); 315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild); 316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (myEnd < nextEnd) { 317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child;//i should have a better position 318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else if (myEnd == nextEnd) { 319d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar compareSpans = true; 320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int myStart = mPrimaryOrientation.getDecoratedStart(child); 323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild); 324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (myStart > nextStart) { 325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child;//i should have a better position 326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else if (myStart == nextStart) { 327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar compareSpans = true; 328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (compareSpans) { 331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // equal, check span indices. 332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LayoutParams nextLp = (LayoutParams) nextChild.getLayoutParams(); 333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mSpan.mIndex - nextLp.mSpan.mIndex < 0 != preferredSpanDir < 0) { 334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child; 335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 3372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 339d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // everything looks good 340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean checkSpanForGap(Span span) { 344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) { 346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) { 349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return false; 3522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the number of spans for the layout. This will invalidate all of the span assignments 3562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * for Views. 3572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 3582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Calling this method will automatically result in a new layout request unless the spanCount 3592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * parameter is equal to current span count. 3602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 3612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param spanCount Number of spans to layout 3622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setSpanCount(int spanCount) { 3640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 3652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanCount != mSpanCount) { 3662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateSpanAssignments(); 3672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanCount = spanCount; 3682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans = new BitSet(mSpanCount); 3692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans = new Span[mSpanCount]; 3702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 3712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i] = new Span(i); 3722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 3742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep 379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * scroll position if this method is called after views are laid out. 3802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} 3822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setOrientation(int orientation) { 3842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (orientation != HORIZONTAL && orientation != VERTICAL) { 3852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar throw new IllegalArgumentException("invalid orientation."); 3862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 3882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (orientation == mOrientation) { 3892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 3902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = orientation; 3922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation != null && mSecondaryOrientation != null) { 3932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // swap 3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper tmp = mPrimaryOrientation; 3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation = mSecondaryOrientation; 3962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation = tmp; 3972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 3992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets whether LayoutManager should start laying out items from the end of the UI. The order 4032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * items are traversed is not affected by this call. 4042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 405d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * For vertical layout, if it is set to <code>true</code>, first item will be at the bottom of 406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * the list. 4072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 4082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For horizontal layouts, it depends on the layout direction. 4092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if 4102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link RecyclerView}} is RTL, it will layout from LTR. 4112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 4122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param reverseLayout Whether layout should be in reverse or not 4132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setReverseLayout(boolean reverseLayout) { 4150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 4162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) { 4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.mReverseLayout = reverseLayout; 4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = reverseLayout; 4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the current gap handling strategy for StaggeredGridLayoutManager. 4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Staggered grid may have gaps in the layout due to changes in the adapter. To avoid gaps, 427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * StaggeredGridLayoutManager provides 2 options. Check {@link #GAP_HANDLING_NONE} and 428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} for details. 4292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}. 4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return Current gap handling strategy. 4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setGapStrategy(int) 4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_NONE 4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS 4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getGapStrategy() { 4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mGapStrategy; 4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter 4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * is different than the current strategy, calling this method will trigger a layout request. 4442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param gapStrategy The new gap handling strategy. Should be 446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or {@link 447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * #GAP_HANDLING_NONE}. 4482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #getGapStrategy() 4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setGapStrategy(int gapStrategy) { 4510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 4522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gapStrategy == mGapStrategy) { 4532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (gapStrategy != GAP_HANDLING_NONE && 4562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) { 4572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE " 458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS"); 4592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mGapStrategy = gapStrategy; 4612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 4650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void assertNotInLayoutOrScroll(String message) { 4660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar if (mPendingSavedState == null) { 4670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.assertNotInLayoutOrScroll(message); 4680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 4690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 4700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 4712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the number of spans laid out by StaggeredGridLayoutManager. 4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return Number of spans in the layout 4752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getSpanCount() { 4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mSpanCount; 4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items. 4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If you need to cancel current assignments, you can call this method which will clear all 4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * assignments and request a new layout. 4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void invalidateSpanAssignments() { 4872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.clear(); 4882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void ensureOrientationHelper() { 4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation == null) { 4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation); 4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation = OrientationHelper 4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .createOrientationHelper(this, 1 - mOrientation); 4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState = new LayoutState(); 4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Calculates the views' layout order. (e.g. from end to start or start to end) 5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * RTL layout support is applied automatically. So if layout is RTL and 5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left. 5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 5052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void resolveShouldLayoutReverse() { 5062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // A == B is the same result, but we rather keep it readable 5072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL || !isLayoutRTL()) { 5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mShouldReverseLayout = mReverseLayout; 5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mShouldReverseLayout = !mReverseLayout; 5112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 514d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean isLayoutRTL() { 5152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL; 5162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns whether views are laid out in reverse order or not. 5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 5212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Not that this value is not affected by RecyclerView's layout direction. 5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return True if layout is reversed, false otherwise 5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setReverseLayout(boolean) 5252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 5262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean getReverseLayout() { 5272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mReverseLayout; 5282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 5312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureOrientationHelper(); 5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Update adapter size. 5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.mAdapterSize = state.getItemCount(); 5352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final AnchorInfo anchorInfo = mAnchorInfo; 537d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.reset(); 5382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 540d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar applyPendingSavedState(anchorInfo); 5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar resolveShouldLayoutReverse(); 543d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = mShouldReverseLayout; 5442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 546d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateAnchorInfoForLayout(state, anchorInfo); 5472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState == null) { 549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd || 550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar isLayoutRTL() != mLastLayoutRTL) { 551d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.clear(); 552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mInvalidateOffsets = true; 553d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 5542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 555d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 5560ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar if (getChildCount() > 0 && (mPendingSavedState == null || 557b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mPendingSavedState.mSpanOffsetsSize < 1)) { 558d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mInvalidateOffsets) { 5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Scroll to position is set, clear. 5612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].clear(); 562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mOffset != INVALID_OFFSET) { 563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].setLine(anchorInfo.mOffset); 5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 568d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset); 5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar detachAndScrapAttachedViews(recycler); 573d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan = false; 574d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateMeasureSpecs(); 575d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mLayoutFromEnd) { 576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout start. 577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillStart(anchorInfo.mPosition, state); 578d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 579d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout end. 580d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillEnd(anchorInfo.mPosition, state); 5812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; 582d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout end. 585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillEnd(anchorInfo.mPosition, state); 586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout start. 588d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillStart(anchorInfo.mPosition, state); 5892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; 590d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 5912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() > 0) { 5942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout) { 5952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixEndGap(recycler, state, true); 5962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixStartGap(recycler, state, false); 5972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixStartGap(recycler, state, true); 5992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixEndGap(recycler, state, false); 6002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 6036e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar if (!state.isPreLayout()) { 604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() > 0 && mPendingScrollPosition != NO_POSITION && 605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan) { 606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ViewCompat.postOnAnimation(getChildAt(0), checkForGapsRunnable); 607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPosition = NO_POSITION; 6096e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 6106e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar } 611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd; 612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = isLayoutRTL(); 6132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState = null; // we don't need this anymore 6142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void applyPendingSavedState(AnchorInfo anchorInfo) { 617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 618d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "found saved state: " + mPendingSavedState); 6192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 620d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mSpanOffsetsSize > 0) { 621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mSpanOffsetsSize == mSpanCount) { 622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].clear(); 624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int line = mPendingSavedState.mSpanOffsets[i]; 625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (line != Span.INVALID_LINE) { 626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mAnchorLayoutFromEnd) { 627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line += mPrimaryOrientation.getEndAfterPadding(); 628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line += mPrimaryOrientation.getStartAfterPadding(); 630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].setLine(line); 633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 634d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 635d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingSavedState.invalidateSpanInfo(); 636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition; 637d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 638d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = mPendingSavedState.mLastLayoutRTL; 640d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar setReverseLayout(mPendingSavedState.mReverseLayout); 641d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar resolveShouldLayoutReverse(); 6422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 643d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mAnchorPosition != NO_POSITION) { 644d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPosition = mPendingSavedState.mAnchorPosition; 645d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd; 6462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 647d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = mShouldReverseLayout; 6482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 649d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mSpanLookupSize > 1) { 650d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.mData = mPendingSavedState.mSpanLookup; 651d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.mFullSpanItems = mPendingSavedState.mFullSpanItems; 652d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 653d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 654d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 655d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void updateAnchorInfoForLayout(RecyclerView.State state, AnchorInfo anchorInfo) { 656d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (updateAnchorFromPendingData(state, anchorInfo)) { 657d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 658d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 659d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (updateAnchorFromChildren(state, anchorInfo)) { 660d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 661d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 662d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 663d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "Deciding anchor info from fresh state"); 664d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 665d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.assignCoordinateFromPadding(); 666d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = 0; 667d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 668d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 669d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean updateAnchorFromChildren(RecyclerView.State state, AnchorInfo anchorInfo) { 670d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // We don't recycle views out of adapter order. This way, we can rely on the first or 671d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // last child as the anchor position. 672d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout direction may change but we should select the child depending on the latest 673d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // layout direction. Otherwise, we'll choose the wrong child. 674d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mLastLayoutFromEnd 675d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? findLastReferenceChildPosition(state.getItemCount()) 676d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : findFirstReferenceChildPosition(state.getItemCount()); 677d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = INVALID_OFFSET; 678d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 679d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 680d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 681d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) { 682d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Validate scroll position if exists. 683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) { 684d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return false; 685d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 686d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Validate it. 687d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) { 688d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPosition = NO_POSITION; 689d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 690d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return false; 691d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 692d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 693d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState == null || mPendingSavedState.mAnchorPosition == NO_POSITION 694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar || mPendingSavedState.mSpanOffsetsSize < 1) { 695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // If item is visible, make it fully visible. 696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View child = findViewByPosition(mPendingScrollPosition); 697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (child != null) { 698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Use regular anchor position, offset according to pending offset and target 699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // child 700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mShouldReverseLayout ? getLastChildPosition() 701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : getFirstChildPosition(); 702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingScrollPositionOffset != INVALID_OFFSET) { 704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mLayoutFromEnd) { 705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int target = mPrimaryOrientation.getEndAfterPadding() - 706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPositionOffset; 707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child); 708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int target = mPrimaryOrientation.getStartAfterPadding() + 710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPositionOffset; 711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child); 712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // no offset provided. Decide according to the child location 717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child); 718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (childSize > mPrimaryOrientation.getTotalSpace()) { 719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Item does not fit. Fix depending on layout direction. 720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = anchorInfo.mLayoutFromEnd 721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? mPrimaryOrientation.getEndAfterPadding() 722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int startGap = mPrimaryOrientation.getDecoratedStart(child) 727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar - mPrimaryOrientation.getStartAfterPadding(); 728d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (startGap < 0) { 729d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = -startGap; 730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 731d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 732d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int endGap = mPrimaryOrientation.getEndAfterPadding() - 733d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPrimaryOrientation.getDecoratedEnd(child); 734d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (endGap < 0) { 735d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = endGap; 736d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 7372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 738d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // child already visible. just layout as usual 739d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = INVALID_OFFSET; 740d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 741d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Child is not visible. Set anchor coordinate depending on in which direction 742d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // child will be visible. 743d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mPendingScrollPosition; 744d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingScrollPositionOffset == INVALID_OFFSET) { 745d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int position = calculateScrollDirectionForPosition( 746d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition); 747d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = position == LAYOUT_END; 748d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.assignCoordinateFromPadding(); 749d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 750d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.assignCoordinateFromPadding(mPendingScrollPositionOffset); 751d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 752d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mInvalidateOffsets = true; 7532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 754d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 755d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = INVALID_OFFSET; 756d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mPendingScrollPosition; 757d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 758d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 759d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 760d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 761d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void updateMeasureSpecs() { 762d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount; 763d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSizeSpec = View.MeasureSpec.makeMeasureSpec( 764d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY); 765d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mOrientation == VERTICAL) { 766d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mWidthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY); 767d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mHeightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 768d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 769d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mHeightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY); 770d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mWidthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 7712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 7742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 7752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean supportsPredictiveItemAnimations() { 7766e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar return mPendingSavedState == null; 7772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 779333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 780333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the first visible view for each span. 781333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 782333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 783333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 784333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 785333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 786333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 787333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 788333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 789333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 790333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 791333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 792333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 793d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the first visible item in each span. If a span does not have 794d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * any items, {@link RecyclerView#NO_POSITION} is returned for that span. 795333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstCompletelyVisibleItemPositions(int[]) 796333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastVisibleItemPositions(int[]) 797333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 798333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findFirstVisibleItemPositions(int[] into) { 799333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 800333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 801333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 802333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 803333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 804333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 805d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 806333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findFirstVisibleItemPosition(); 807333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 808333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 809333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 810333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 811333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 812333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the first completely visible view for each span. 813333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 814333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 815333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 816333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 817333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 818333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 819333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 820333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 821333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 822333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 823333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 824333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 825d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the first fully visible item in each span. If a span does 826d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span. 827333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstVisibleItemPositions(int[]) 828333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastCompletelyVisibleItemPositions(int[]) 829333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 830333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findFirstCompletelyVisibleItemPositions(int[] into) { 831333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 832333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 833333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 834333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 835333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 836333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 837d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 838333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition(); 839333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 840333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 841333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 842333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 843333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 844333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the last visible view for each span. 845333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 846333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 847333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 848333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 849333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 850333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 851333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 852333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 853333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 854333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 855333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 856333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 857d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the last visible item in each span. If a span does not have 858d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * any items, {@link RecyclerView#NO_POSITION} is returned for that span. 859333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastCompletelyVisibleItemPositions(int[]) 860333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstVisibleItemPositions(int[]) 861333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 862333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findLastVisibleItemPositions(int[] into) { 863333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 864333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 865333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 866333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 867333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 868333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 869d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 870333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findLastVisibleItemPosition(); 871333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 872333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 873333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 874333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 875333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 876333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the last completely visible view for each span. 877333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 878333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 879333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 880333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 881333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 882333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 883333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 884333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 885333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 886333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 887333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 888333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 889d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the last fully visible item in each span. If a span does not 890d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * have any items, {@link RecyclerView#NO_POSITION} is returned for that span. 891333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstCompletelyVisibleItemPositions(int[]) 892333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastVisibleItemPositions(int[]) 893333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 894333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findLastCompletelyVisibleItemPositions(int[] into) { 895333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 896333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 897333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 898333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 899333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 900333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 901d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 902333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findLastCompletelyVisibleItemPosition(); 903333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 904333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 905333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 906333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 907d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 908d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeHorizontalScrollOffset(RecyclerView.State state) { 909d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollOffset(state); 910d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 911d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 912d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int computeScrollOffset(RecyclerView.State state) { 913d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0) { 914d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 915d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 916d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation, 917d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled) 918d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled), 919d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar this, mSmoothScrollbarEnabled, mShouldReverseLayout); 920d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 921d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 922d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 923d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeVerticalScrollOffset(RecyclerView.State state) { 924d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollOffset(state); 925d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 926d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 927d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 928d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeHorizontalScrollExtent(RecyclerView.State state) { 929d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollExtent(state); 930d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 931d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 932d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int computeScrollExtent(RecyclerView.State state) { 933d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0) { 934d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 935d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 936d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation, 937d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled) 938d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled), 939d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar this, mSmoothScrollbarEnabled); 940d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 941d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 942d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 943d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeVerticalScrollExtent(RecyclerView.State state) { 944d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollExtent(state); 945d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 947d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 948d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeHorizontalScrollRange(RecyclerView.State state) { 949d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollRange(state); 950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int computeScrollRange(RecyclerView.State state) { 953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0) { 954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation, 957d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled) 958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled), 959d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar this, mSmoothScrollbarEnabled); 960d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 963d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeVerticalScrollRange(RecyclerView.State state) { 964d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollRange(state); 965d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 966d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 967d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp) { 968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 969d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mOrientation == VERTICAL) { 970d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar measureChildWithDecorationsAndMargin(child, mFullSizeSpec, mHeightSpec); 971d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 972d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar measureChildWithDecorationsAndMargin(child, mWidthSpec, mFullSizeSpec); 973d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 974d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 975d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar measureChildWithDecorationsAndMargin(child, mWidthSpec, mHeightSpec); 976d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 977d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 978d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 9792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void measureChildWithDecorationsAndMargin(View child, int widthSpec, 9802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int heightSpec) { 9812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); 9822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 9832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + insets.left, 9842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.rightMargin + insets.right); 9852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + insets.top, 9862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.bottomMargin + insets.bottom); 9872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar child.measure(widthSpec, heightSpec); 9882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 9902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int updateSpecWithExtra(int spec, int startInset, int endInset) { 9912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startInset == 0 && endInset == 0) { 9922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return spec; 9932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int mode = View.MeasureSpec.getMode(spec); 9952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) { 9962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return View.MeasureSpec.makeMeasureSpec( 9972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View.MeasureSpec.getSize(spec) - startInset - endInset, mode); 9982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 9992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return spec; 10002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 10032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onRestoreInstanceState(Parcelable state) { 10042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (state instanceof SavedState) { 10052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState = (SavedState) state; 10062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 10072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (DEBUG) { 10082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "invalid saved state class"); 10092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 10132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public Parcelable onSaveInstanceState() { 10142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 10152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState(mPendingSavedState); 10162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar SavedState state = new SavedState(); 10182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mReverseLayout = mReverseLayout; 10192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorLayoutFromEnd = mLastLayoutFromEnd; 1020d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mLastLayoutRTL = mLastLayoutRTL; 10212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLazySpanLookup != null && mLazySpanLookup.mData != null) { 10232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookup = mLazySpanLookup.mData; 10242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookupSize = state.mSpanLookup.length; 1025d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mFullSpanItems = mLazySpanLookup.mFullSpanItems; 10262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookupSize = 0; 10282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() > 0) { 10312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition() 10322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getFirstChildPosition(); 1033333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt(); 1034b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar state.mSpanOffsetsSize = mSpanCount; 10352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanOffsets = new int[mSpanCount]; 10362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1037d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int line; 1038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mLastLayoutFromEnd) { 1039d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line = mSpans[i].getEndLine(Span.INVALID_LINE); 1040d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (line != Span.INVALID_LINE) { 1041d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line -= mPrimaryOrientation.getEndAfterPadding(); 1042d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1044d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line = mSpans[i].getStartLine(Span.INVALID_LINE); 1045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (line != Span.INVALID_LINE) { 1046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line -= mPrimaryOrientation.getStartAfterPadding(); 1047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1048d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1049d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mSpanOffsets[i] = line; 10502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1052d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mAnchorPosition = NO_POSITION; 1053d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mVisibleAnchorPosition = NO_POSITION; 1054b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar state.mSpanOffsetsSize = 0; 10552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 10572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "saved state:\n" + state); 10582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return state; 10602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1062a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1063a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler, 1064a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) { 1065a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ViewGroup.LayoutParams lp = host.getLayoutParams(); 1066a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (!(lp instanceof LayoutParams)) { 1067a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar super.onInitializeAccessibilityNodeInfoForItem(host, info); 1068a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return; 1069a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1070a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar LayoutParams sglp = (LayoutParams) lp; 1071a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == HORIZONTAL) { 1072a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( 1073a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1, 1074a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar -1, -1, 1075a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.mFullSpan, false)); 1076a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else { // VERTICAL 1077a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( 1078a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar -1, -1, 1079a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1, 1080a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.mFullSpan, false)); 1081a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1082a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1083a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1084a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1085a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1086a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar super.onInitializeAccessibilityEvent(event); 1087a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (getChildCount() > 0) { 1088a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityRecordCompat record = AccessibilityEventCompat 1089a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .asRecord(event); 1090a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final View start = findFirstVisibleItemClosestToStart(false); 1091a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final View end = findFirstVisibleItemClosestToEnd(false); 1092a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (start == null || end == null) { 1093a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return; 1094a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1095a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final int startPos = getPosition(start); 1096a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final int endPos = getPosition(end); 1097a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (startPos < endPos) { 1098a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setFromIndex(startPos); 1099a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setToIndex(endPos); 1100a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else { 1101a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setFromIndex(endPos); 1102a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setToIndex(startPos); 1103a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1104a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1105a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1106a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1107333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 1108333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Finds the first fully visible child to be used as an anchor child if span count changes when 1109333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * state is restored. 1110333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 1111333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int findFirstVisibleItemPositionInt() { 1112d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true) : 1113d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar findFirstVisibleItemClosestToStart(true); 1114d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return first == null ? NO_POSITION : getPosition(first); 1115d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1116d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1117a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1118a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getRowCountForAccessibility(RecyclerView.Recycler recycler, 1119a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 1120a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == HORIZONTAL) { 1121a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanCount; 1122a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1123a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return super.getRowCountForAccessibility(recycler, state); 1124a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1125a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1126a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1127a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getColumnCountForAccessibility(RecyclerView.Recycler recycler, 1128a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 1129a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == VERTICAL) { 1130a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanCount; 1131a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1132a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return super.getColumnCountForAccessibility(recycler, state); 1133a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1134a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View findFirstVisibleItemClosestToStart(boolean fullyVisible) { 1136333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); 1137333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); 1138d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int limit = getChildCount(); 1139d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < limit; i ++) { 1140333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final View child = getChildAt(i); 1141d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if ((!fullyVisible || mPrimaryOrientation.getDecoratedStart(child) >= boundsStart) 1142333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar && mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) { 1143d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child; 1144d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1145d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1146d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 1147d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1148d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1149d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View findFirstVisibleItemClosestToEnd(boolean fullyVisible) { 1150d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); 1151d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); 1152d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = getChildCount() - 1; i >= 0; i --) { 1153d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View child = getChildAt(i); 1154d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(child) >= boundsStart && (!fullyVisible 1155d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar || mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd)) { 1156d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child; 1157333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1158333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 1160333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1161333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 11622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state, 11632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean canOffsetChildren) { 11642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); 11652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine; 11662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int fixOffset; 11672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gap > 0) { 11682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixOffset = -scrollBy(-gap, recycler, state); 11692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; // nothing to fix 11712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gap -= fixOffset; 11732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (canOffsetChildren && gap > 0) { 11742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(gap); 11752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state, 11792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean canOffsetChildren) { 11802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding()); 11812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding(); 11822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int fixOffset; 11832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gap > 0) { 11842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixOffset = scrollBy(gap, recycler, state); 11852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 11862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; // nothing to fix 11872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gap -= fixOffset; 11892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (canOffsetChildren && gap > 0) { 11902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(-gap); 11912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateLayoutStateToFillStart(int anchorPosition, RecyclerView.State state) { 11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = 0; 11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = anchorPosition; 11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (isSmoothScrolling()) { 11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetPos = state.getTargetScrollPosition(); 11992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout == targetPos < anchorPosition) { 12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace(); 12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_START; 12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL 12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_HEAD; 12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateLayoutStateToFillEnd(int anchorPosition, RecyclerView.State state) { 12132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = 0; 12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = anchorPosition; 12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (isSmoothScrolling()) { 12162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetPos = state.getTargetScrollPosition(); 12172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout == targetPos > anchorPosition) { 12182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace(); 12212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_END; 12262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD 12272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_TAIL; 12282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void offsetChildrenHorizontal(int dx) { 12322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super.offsetChildrenHorizontal(dx); 12332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].onOffset(dx); 12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void offsetChildrenVertical(int dy) { 12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super.offsetChildrenVertical(dy); 12412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 12422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].onOffset(dy); 12432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { 1248d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.REMOVE); 12492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { 1253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.ADD); 1254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 1257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onItemsChanged(RecyclerView recyclerView) { 1258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.clear(); 1259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestLayout(); 1260d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1261d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1262d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 1263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { 1264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(from, to, AdapterHelper.UpdateOp.MOVE); 1265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 1268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) { 1269d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.UPDATE); 12702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 12732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Checks whether it should invalidate span assignments in response to an adapter change. 12742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) { 12762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition(); 1277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.invalidateAfter(positionStart); 1278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar switch (cmd) { 1279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar case AdapterHelper.UpdateOp.ADD: 1280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForAddition(positionStart, itemCountOrToPosition); 1281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 1282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar case AdapterHelper.UpdateOp.REMOVE: 1283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForRemoval(positionStart, itemCountOrToPosition); 1284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 1285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar case AdapterHelper.UpdateOp.MOVE: 1286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // TODO optimize 1287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForRemoval(positionStart, 1); 1288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForAddition(itemCountOrToPosition, 1); 1289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 1290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (positionStart + itemCountOrToPosition <= minPosition) { 1293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 1294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 12952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition(); 12972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (positionStart <= maxPosition) { 12982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 12992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int fill(RecyclerView.Recycler recycler, LayoutState layoutState, 13032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 13042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(0, mSpanCount, true); 13052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // The target position we are trying to reach. 13062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetLine; 13072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /* 13082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The line until which we can recycle, as long as we add views. 13092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Keep in mind, it is still the line in layout direction which means; to calculate the 13102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * actual recycle line, we should subtract/add the size in orientation. 13112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 13122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int recycleLine; 13132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Line of the furthest row. 13142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 13153ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar // ignore padding for recycler 13160ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleLine = mPrimaryOrientation.getEndAfterPadding() + mLayoutState.mAvailable; 13170ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar targetLine = recycleLine + mLayoutState.mExtra + mPrimaryOrientation.getEndPadding(); 1318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 13192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { // LAYOUT_START 13203ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar // ignore padding for recycler 13210ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleLine = mPrimaryOrientation.getStartAfterPadding() - mLayoutState.mAvailable; 13220ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar targetLine = recycleLine - mLayoutState.mExtra - 1323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPrimaryOrientation.getStartAfterPadding(); 13242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine); 13262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // the default coordinate to add new view. 1328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int defaultNewViewLine = mShouldReverseLayout 1329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? mPrimaryOrientation.getEndAfterPadding() 1330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 13312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) { 13332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View view = layoutState.next(recycler); 13342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = ((LayoutParams) view.getLayoutParams()); 13352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 13362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar addView(view); 13372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 13382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar addView(view, 0); 13392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar measureChildWithDecorationsAndMargin(view, lp); 13412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int position = lp.getViewPosition(); 13432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanIndex = mLazySpanLookup.getSpan(position); 13442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span currentSpan; 1345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID; 1346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (assignSpan) { 1347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState); 13482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.setSpan(position, currentSpan); 1349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 1350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position); 1351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 13522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1353d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 1354d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "using " + spanIndex + " for pos " + position); 1355d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 13562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan = mSpans[spanIndex]; 13572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int start; 13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int end; 1360d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 13612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 1362d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine) 1363d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : currentSpan.getEndLine(defaultNewViewLine); 13642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar end = start + mPrimaryOrientation.getDecoratedMeasurement(view); 1365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (assignSpan && lp.mFullSpan) { 1366d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fullSpanItem; 1367d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem = createFullSpanItemFromEnd(start); 1368d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mGapDir = LAYOUT_START; 1369d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mPosition = position; 1370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.addFullSpanItem(fullSpanItem); 13712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1373d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar end = lp.mFullSpan ? getMinStart(defaultNewViewLine) 1374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : currentSpan.getStartLine(defaultNewViewLine); 13752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar start = end - mPrimaryOrientation.getDecoratedMeasurement(view); 1376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (assignSpan && lp.mFullSpan) { 1377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fullSpanItem; 1378d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem = createFullSpanItemFromStart(end); 1379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mGapDir = LAYOUT_END; 1380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mPosition = position; 1381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.addFullSpanItem(fullSpanItem); 13822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // check if this item may create gaps in the future 1386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD && assignSpan) { 1387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan = true; 13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar lp.mSpan = currentSpan; 1391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar attachViewToSpans(view, lp, layoutState); 13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding() 1393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : currentSpan.mIndex * mSizePerSpan + 1394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSecondaryOrientation.getStartAfterPadding(); 13952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view); 13962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL) { 13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end); 13982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 13992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd); 14002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1401d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 14022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 1403d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine); 14042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine); 14062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar recycle(recycler, mLayoutState, currentSpan, recycleLine); 14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 14102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "fill, " + getChildCount()); 14112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLayoutState.mLayoutDirection == LAYOUT_START) { 14132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding()); 14140ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar return Math.max(0, mLayoutState.mAvailable + (recycleLine - minStart)); 14152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int max = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); 14170ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar return Math.max(0, mLayoutState.mAvailable + (max - recycleLine)); 14182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private LazySpanLookup.FullSpanItem createFullSpanItemFromEnd(int newItemTop) { 1422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem(); 1423d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan = new int[mSpanCount]; 1424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan[i] = newItemTop - mSpans[i].getEndLine(newItemTop); 1426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 1428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1430d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private LazySpanLookup.FullSpanItem createFullSpanItemFromStart(int newItemBottom) { 1431d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem(); 1432d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan = new int[mSpanCount]; 1433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1434d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan[i] = mSpans[i].getStartLine(newItemBottom) - newItemBottom; 1435d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1436d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 1437d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1438d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1439d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void attachViewToSpans(View view, LayoutParams lp, LayoutState layoutState) { 1440d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { 1441d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 1442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar appendViewToAllSpans(view); 1443d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar lp.mSpan.appendToSpan(view); 1445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 1448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar prependViewToAllSpans(view); 1449d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1450d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar lp.mSpan.prependToSpan(view); 1451d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1452d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1453d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1454d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState, 1456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Span updatedSpan, int recycleLine) { 1457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_START) { 1458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // calculate recycle line 1459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int maxStart = getMaxStart(updatedSpan.getStartLine()); 1460d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar recycleFromEnd(recycler, Math.max(recycleLine, maxStart) + 1461d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding())); 1462d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1463d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // calculate recycle line 1464d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int minEnd = getMinEnd(updatedSpan.getEndLine()); 1465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar recycleFromStart(recycler, Math.min(recycleLine, minEnd) - 1466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding())); 1467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1468d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1469d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void appendViewToAllSpans(View view) { 1471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // traverse in reverse so that we end up assigning full span items to 0 1472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mSpanCount - 1; i >= 0; i--) { 1473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].appendToSpan(view); 1474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void prependViewToAllSpans(View view) { 1478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // traverse in reverse so that we end up assigning full span items to 0 1479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mSpanCount - 1; i >= 0; i--) { 1480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].prependToSpan(view); 1481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void layoutDecoratedWithMargins(View child, int left, int top, int right, int bottom) { 14852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 1487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "layout decorated pos: " + lp.getViewPosition() + ", span:" 1488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + lp.getSpanIndex() + ", fullspan:" + lp.mFullSpan 1489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + ". l:" + left + ",t:" + top 1490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + ", r:" + right + ", b:" + bottom); 1491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 14922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin 14932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar , bottom - lp.bottomMargin); 14942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void updateAllRemainingSpans(int layoutDir, int targetLine) { 1497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1498d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mSpans[i].mViews.isEmpty()) { 1499d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; 1500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1501d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateRemainingSpans(mSpans[i], layoutDir, targetLine); 1502d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 15052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateRemainingSpans(Span span, int layoutDir, int targetLine) { 15062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int deletedSize = span.getDeletedSize(); 15072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutDir == LAYOUT_START) { 15082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getStartLine(); 15092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line + deletedSize < targetLine) { 15102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(span.mIndex, false); 15112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getEndLine(); 15142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line - deletedSize > targetLine) { 15152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(span.mIndex, false); 15162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMaxStart(int def) { 15212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxStart = mSpans[0].getStartLine(def); 15222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanStart = mSpans[i].getStartLine(def); 15242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanStart > maxStart) { 15252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxStart = spanStart; 15262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return maxStart; 15292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMinStart(int def) { 15322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minStart = mSpans[0].getStartLine(def); 15332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanStart = mSpans[i].getStartLine(def); 15352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanStart < minStart) { 15362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minStart = spanStart; 15372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return minStart; 15402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMaxEnd(int def) { 15432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxEnd = mSpans[0].getEndLine(def); 15442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanEnd = mSpans[i].getEndLine(def); 15462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanEnd > maxEnd) { 15472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxEnd = spanEnd; 15482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return maxEnd; 15512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMinEnd(int def) { 15542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minEnd = mSpans[0].getEndLine(def); 15552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanEnd = mSpans[i].getEndLine(def); 15572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanEnd < minEnd) { 15582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minEnd = spanEnd; 15592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return minEnd; 15622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void recycleFromStart(RecyclerView.Recycler recycler, int line) { 15652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 15662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "recycling from start for line " + line); 15672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (getChildCount() > 0) { 15692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(0); 15702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedEnd(child) < line) { 15712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 15722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 15732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int j = 0; j < mSpanCount; j++) { 15742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[j].popStart(); 15752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan.popStart(); 15782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar removeAndRecycleView(child, recycler); 15802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return;// done 15822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void recycleFromEnd(RecyclerView.Recycler recycler, int line) { 15872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 15882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int i; 15892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (i = childCount - 1; i >= 0; i--) { 15902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(i); 15912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(child) > line) { 15922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 15932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 15942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int j = 0; j < mSpanCount; j++) { 15952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[j].popEnd(); 15962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan.popEnd(); 15992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar removeAndRecycleView(child, recycler); 16012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 16022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return;// done 16032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return True if last span is the first one we want to fill 1609d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 1610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean preferLastSpan(int layoutDir) { 1611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mOrientation == HORIZONTAL) { 1612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return (layoutDir == LAYOUT_START) != mShouldReverseLayout; 1613d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1614d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ((layoutDir == LAYOUT_START) == mShouldReverseLayout) == isLayoutRTL(); 1615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 16182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Finds the span for the next view. 16192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 16202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span getNextSpan(LayoutState layoutState) { 1621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final boolean preferLastSpan = preferLastSpan(layoutState.mLayoutDirection); 1622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int startIndex, endIndex, diff; 1623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (preferLastSpan) { 1624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar startIndex = mSpanCount - 1; 1625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endIndex = -1; 1626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar diff = -1; 1627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar startIndex = 0; 1629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endIndex = mSpanCount; 1630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar diff = 1; 1631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 16322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 1633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Span min = null; 1634d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int minLine = Integer.MAX_VALUE; 16352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getStartAfterPadding(); 1636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = startIndex; i != endIndex; i += diff) { 16372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span other = mSpans[i]; 1638d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int otherLine = other.getEndLine(defaultLine); 1639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (otherLine < minLine) { 16402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar min = other; 16412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minLine = otherLine; 16422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return min; 16452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Span max = null; 1647d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int maxLine = Integer.MIN_VALUE; 16482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getEndAfterPadding(); 1649d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = startIndex; i != endIndex; i += diff) { 16502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span other = mSpans[i]; 1651d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int otherLine = other.getStartLine(defaultLine); 1652d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (otherLine > maxLine) { 16532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar max = other; 16542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxLine = otherLine; 16552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return max; 16582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean canScrollVertically() { 16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation == VERTICAL; 16642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean canScrollHorizontally() { 16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation == HORIZONTAL; 16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 16732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 16742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return scrollBy(dx, recycler, state); 16752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 16802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return scrollBy(dy, recycler, state); 16812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int calculateScrollDirectionForPosition(int position) { 16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() == 0) { 16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START; 16862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int firstChildPos = getFirstChildPosition(); 16882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; 16892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 16932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int position) { 16942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) { 16952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 16962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 16972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int direction = calculateScrollDirectionForPosition(targetPosition); 16982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (direction == 0) { 16992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return null; 17002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == HORIZONTAL) { 17022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new PointF(direction, 0); 17032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 17042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new PointF(0, direction); 17052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar }; 17082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar scroller.setTargetPosition(position); 17092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar startSmoothScroll(scroller); 17102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void scrollToPosition(int position) { 17142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) { 17152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateAnchorPositionInfo(); 17162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = position; 17182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 17192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 17202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 17232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Scroll to the specified adapter position with the given offset from layout start. 17242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 17252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Note that scroll position change will not be reflected until the next layout call. 17262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 17272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}. 17282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 17292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param position Index (starting at 0) of the reference item. 17302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param offset The distance (in pixels) between the start edge of the item view and 17312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * start edge of the RecyclerView. 17322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setReverseLayout(boolean) 17332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #scrollToPosition(int) 17342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 17352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void scrollToPositionWithOffset(int position, int offset) { 17362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 17372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateAnchorPositionInfo(); 17382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = position; 17402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = offset; 17412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 17422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1744d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) { 17452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureOrientationHelper(); 17462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int referenceChildPosition; 17472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (dt > 0) { // layout towards end 17482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_END; 17492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD 17502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_TAIL; 17512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar referenceChildPosition = getLastChildPosition(); 17522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 17532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_START; 17542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL 17552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_HEAD; 17562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar referenceChildPosition = getFirstChildPosition(); 17572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection; 17592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int absDt = Math.abs(dt); 17602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = absDt; 17612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = isSmoothScrolling() ? mPrimaryOrientation.getTotalSpace() : 0; 17622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int consumed = fill(recycler, mLayoutState, state); 17632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int totalScroll; 17642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (absDt < consumed) { 17652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = dt; 17662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (dt < 0) { 17672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = -consumed; 17682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { // dt > 0 17692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = consumed; 17702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 17722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "asked " + dt + " scrolled" + totalScroll); 17732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1775d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPrimaryOrientation.offsetChildren(-totalScroll); 17762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // always reset this if we scroll for a proper save instance state 17772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLastLayoutFromEnd = mShouldReverseLayout; 17782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return totalScroll; 17792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getLastChildPosition() { 17822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 17832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1)); 17842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getFirstChildPosition() { 17872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 17882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return childCount == 0 ? 0 : getPosition(getChildAt(0)); 17892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1791719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar /** 1792719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * Finds the first View that can be used as an anchor View. 1793719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * 1794719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * @return Position of the View or 0 if it cannot find any such View. 1795719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar */ 1796719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar private int findFirstReferenceChildPosition(int itemCount) { 1797719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int limit = getChildCount(); 1798719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar for (int i = 0; i < limit; i++) { 1799719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final View view = getChildAt(i); 1800719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int position = getPosition(view); 1801719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar if (position >= 0 && position < itemCount) { 1802719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return position; 1803719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1804719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1805719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return 0; 1806719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1807719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar 1808719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar /** 1809719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * Finds the last View that can be used as an anchor View. 1810719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * 1811719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * @return Position of the View or 0 if it cannot find any such View. 1812719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar */ 1813719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar private int findLastReferenceChildPosition(int itemCount) { 1814719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar for (int i = getChildCount() - 1; i >= 0; i--) { 1815719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final View view = getChildAt(i); 1816719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int position = getPosition(view); 1817719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar if (position >= 0 && position < itemCount) { 1818719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return position; 1819719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1820719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1821719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return 0; 1822719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1823719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar 18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateDefaultLayoutParams() { 18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 18272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 18282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 18312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { 18322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(c, attrs); 18332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 18362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 18372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp instanceof ViewGroup.MarginLayoutParams) { 18382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams((ViewGroup.MarginLayoutParams) lp); 18392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 18402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(lp); 18412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 18452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { 18462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return lp instanceof LayoutParams; 18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getOrientation() { 18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation; 18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * LayoutParams used by StaggeredGridLayoutManager. 18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static class LayoutParams extends RecyclerView.LayoutParams { 18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Span Id for Views that are not laid out yet. 18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int INVALID_SPAN_ID = -1; 18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Package scope to be able to access from tests. 18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span mSpan; 18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mFullSpan; 18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(Context c, AttributeSet attrs) { 18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(c, attrs); 18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(int width, int height) { 18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(width, height); 18752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(ViewGroup.MarginLayoutParams source) { 18782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 18792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(ViewGroup.LayoutParams source) { 18822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 18832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(RecyclerView.LayoutParams source) { 18862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 18872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 18902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When set to true, the item will layout using all span area. That means, if orientation 18912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * is vertical, the view will have full width; if orientation is horizontal, the view will 18922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * have full height. 18932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 18942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param fullSpan True if this item should traverse all spans. 18957499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * @see #isFullSpan() 18962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 18972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setFullSpan(boolean fullSpan) { 18982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mFullSpan = fullSpan; 18992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 19027499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * Returns whether this View occupies all available spans or just one. 19037499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * 19047499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * @return True if the View occupies all spans or false otherwise. 19057499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * @see #setFullSpan(boolean) 19067499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar */ 19077499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar public boolean isFullSpan() { 19087499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar return mFullSpan; 19097499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar } 19107499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar 19117499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar /** 19122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the Span index to which this View is assigned. 19132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 19142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return The Span index of the View. If View is not yet assigned to any span, returns 19152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #INVALID_SPAN_ID}. 19162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 19172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public final int getSpanIndex() { 19182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpan == null) { 19192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return INVALID_SPAN_ID; 19202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mSpan.mIndex; 19222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Package scoped to access from tests. 19262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar class Span { 19272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19286b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar static final int INVALID_LINE = Integer.MIN_VALUE; 19292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private ArrayList<View> mViews = new ArrayList<View>(); 19302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mCachedStart = INVALID_LINE; 19312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mCachedEnd = INVALID_LINE; 19322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mDeletedSize = 0; 19332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int mIndex; 19342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span(int index) { 19362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mIndex = index; 19372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getStartLine(int def) { 19402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 19412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 19422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 19442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return def; 19452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedStart(); 19472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 19482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void calculateCachedStart() { 1951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View startView = mViews.get(0); 1952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LayoutParams lp = getLayoutParams(startView); 1953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedStart = mPrimaryOrientation.getDecoratedStart(startView); 1954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 1955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = mLazySpanLookup 1956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar .getFullSpanItem(lp.getViewPosition()); 1957d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi != null && fsi.mGapDir == LAYOUT_START) { 1958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedStart -= fsi.getGapForSpan(mIndex); 1959d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1960d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use this one when default value does not make sense and not having a value means a bug. 19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getStartLine() { 19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedStart(); 19692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getEndLine(int def) { 19732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 19742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int size = mViews.size(); 19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (size == 0) { 19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return def; 19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1980d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedEnd(); 19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1984d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void calculateCachedEnd() { 1985d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View endView = mViews.get(mViews.size() - 1); 1986d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LayoutParams lp = getLayoutParams(endView); 1987d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedEnd = mPrimaryOrientation.getDecoratedEnd(endView); 1988d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 1989d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = mLazySpanLookup 1990d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar .getFullSpanItem(lp.getViewPosition()); 1991d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi != null && fsi.mGapDir == LAYOUT_END) { 1992d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedEnd += fsi.getGapForSpan(mIndex); 1993d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1994d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1995d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1996d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 19972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use this one when default value does not make sense and not having a value means a bug. 19982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getEndLine() { 19992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2002d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedEnd(); 20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void prependToSpan(View view) { 20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = getLayoutParams(view); 20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = this; 20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.add(0, view); 20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 1) { 20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 20152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); 20162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void appendToSpan(View view) { 20202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = getLayoutParams(view); 20212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = this; 20222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.add(view); 20232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 20242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 1) { 20252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 20262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 20282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); 20292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Useful method to preserve positions on a re-layout. 20332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void cacheReferenceLineAndClear(boolean reverseLayout, int offset) { 20342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int reference; 20352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (reverseLayout) { 20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference = getEndLine(INVALID_LINE); 20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 20382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference = getStartLine(INVALID_LINE); 20392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar clear(); 20412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (reference == INVALID_LINE) { 20422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 20432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2044d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding()) || 2045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding()) ) { 2046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 20482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (offset != INVALID_OFFSET) { 20492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference += offset; 20502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = mCachedEnd = reference; 20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void clear() { 20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.clear(); 20562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateCache(); 20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize = 0; 20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateCache() { 20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void setLine(int line) { 20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = mCachedStart = line; 20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void popEnd() { 20702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int size = mViews.size(); 20712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View end = mViews.remove(size - 1); 20722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final LayoutParams lp = getLayoutParams(end); 20732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = null; 20747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 20752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end); 20762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (size == 1) { 20782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 20792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 20812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void popStart() { 20842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View start = mViews.remove(0); 20852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final LayoutParams lp = getLayoutParams(start); 20862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = null; 20872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 20882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 20892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 20912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start); 20922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 20942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getDeletedSize() { 20972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mDeletedSize; 20982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams getLayoutParams(View view) { 21012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return (LayoutParams) view.getLayoutParams(); 21022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void onOffset(int dt) { 21052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 21062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart += dt; 21072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 21092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd += dt; 21102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // normalized offset is how much this span can scroll 21142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getNormalizedOffset(int dt, int targetStart, int targetEnd) { 21152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 21162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 21172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (dt < 0) { 21192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int endSpace = getEndLine() - targetEnd; 21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (endSpace <= 0) { 21212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 21222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return -dt > endSpace ? -endSpace : dt; 21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int startSpace = targetStart - getStartLine(); 21262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startSpace <= 0) { 21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return startSpace < dt ? startSpace : dt; 21302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 21342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns if there is no child between start-end lines 21352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 21362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param start The start line 21372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param end The end line 21382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return true if a new child can be added between start and end 21392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 21402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean isEmpty(int start, int end) { 21412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int count = mViews.size(); 21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < count; i++) { 21432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final View view = mViews.get(i); 21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(view) < end && 21452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.getDecoratedEnd(view) > start) { 21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return false; 21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return true; 21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2151333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2152333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findFirstVisibleItemPosition() { 2153333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 2154d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? findOneVisibleChild(mViews.size() -1, -1, false) 2155333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(0, mViews.size(), false); 2156333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2157333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2158333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findFirstCompletelyVisibleItemPosition() { 2159333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 2160333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(mViews.size() -1, -1, true) 2161333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(0, mViews.size(), true); 2162333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2163333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2164333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findLastVisibleItemPosition() { 2165333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 2166333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(0, mViews.size(), false) 2167d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : findOneVisibleChild(mViews.size() -1, -1, false); 2168333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2169333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2170333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findLastCompletelyVisibleItemPosition() { 2171333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 2172333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(0, mViews.size(), true) 2173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : findOneVisibleChild(mViews.size() -1, -1, true); 2174333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2175333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2176333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) { 2177333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int start = mPrimaryOrientation.getStartAfterPadding(); 2178333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int end = mPrimaryOrientation.getEndAfterPadding(); 2179333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int next = toIndex > fromIndex ? 1 : -1; 2180d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = fromIndex; i != toIndex; i += next) { 2181333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final View child = mViews.get(i); 2182333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int childStart = mPrimaryOrientation.getDecoratedStart(child); 2183333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); 2184333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (childStart < end && childEnd > start) { 2185333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (completelyVisible) { 2186333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (childStart >= start && childEnd <= end) { 2187333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 2188333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2189333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else { 2190333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 2191333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2192333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2193333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return NO_POSITION; 2195333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 21962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 21992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * An array of mappings from adapter position to span. 22002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * This only grows when a write happens and it grows up to the size of the adapter. 22012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 22022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar static class LazySpanLookup { 22032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final int MIN_SIZE = 10; 22052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mData; 22062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mAdapterSize; // we don't want to grow beyond that, unless it grows 2207d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar List<FullSpanItem> mFullSpanItems; 2208d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2209d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2210d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Invalidates everything after this position, including full span information 2212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int forceInvalidateAfter(int position) { 2214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems != null) { 2215d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= position) { 2218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(i); 2219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return invalidateAfter(position); 2223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 22242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * returns end position for invalidation. 2227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int invalidateAfter(int position) { 22292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null) { 2230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 22312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (position >= mData.length) { 2233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 2234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2235d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int endPosition = invalidateFullSpansAfter(position); 2236d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (endPosition == RecyclerView.NO_POSITION) { 2237d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID); 2238d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return mData.length; 2239d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2240d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // just invalidate items in between 2241d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Arrays.fill(mData, position, endPosition + 1, LayoutParams.INVALID_SPAN_ID); 2242d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return endPosition + 1; 22432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getSpan(int position) { 22472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null || position >= mData.length) { 22482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return LayoutParams.INVALID_SPAN_ID; 22492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 22502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mData[position]; 22512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void setSpan(int position, Span span) { 22552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(position); 22562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData[position] = span.mIndex; 22572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int sizeForPosition(int position) { 22602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int len = mData.length; 22612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (len <= position) { 22622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar len *= 2; 22632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (len > mAdapterSize) { 22652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar len = mAdapterSize; 22662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return len; 22682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void ensureSize(int position) { 22712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null) { 22722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData = new int[Math.max(position, MIN_SIZE) + 1]; 22732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); 22742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (position >= mData.length) { 22752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] old = mData; 22762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData = new int[sizeForPosition(position)]; 22772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(old, 0, mData, 0, old.length); 22782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID); 22792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void clear() { 22832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData != null) { 22842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); 22852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = null; 22872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void offsetForRemoval(int positionStart, int itemCount) { 2290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mData == null || positionStart >= mData.length) { 2291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 22932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(positionStart + itemCount); 22942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(mData, positionStart + itemCount, mData, positionStart, 22952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData.length - positionStart - itemCount); 22962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, mData.length - itemCount, mData.length, 22972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams.INVALID_SPAN_ID); 2298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar offsetFullSpansForRemoval(positionStart, itemCount); 2299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void offsetFullSpansForRemoval(int positionStart, int itemCount) { 2302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int end = positionStart + itemCount; 2306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition < positionStart) { 2309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; 2310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2311d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition < end) { 2312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(i); 2313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mPosition -= itemCount; 2315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 23172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void offsetForAddition(int positionStart, int itemCount) { 2320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mData == null || positionStart >= mData.length) { 2321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 23232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(positionStart + itemCount); 23242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(mData, positionStart, mData, positionStart + itemCount, 23252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData.length - positionStart - itemCount); 23262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, positionStart, positionStart + itemCount, 23272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams.INVALID_SPAN_ID); 2328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar offsetFullSpansForAddition(positionStart, itemCount); 2329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void offsetFullSpansForAddition(int positionStart, int itemCount) { 2332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition < positionStart) { 2338d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; 2339d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mPosition += itemCount; 2341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Returns when invalidation should end. e.g. hitting a full span position. 2346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Returned position SHOULD BE invalidated. 2347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int invalidateFullSpansAfter(int position) { 2349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 2351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2352d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final FullSpanItem item = getFullSpanItem(position); 2353d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // if there is an fsi at this position, get rid of it. 2354d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (item != null) { 2355d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(item); 2356d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2357d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int nextFsiIndex = -1; 2358d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int count = mFullSpanItems.size(); 2359d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < count; i++) { 2360d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2361d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= position) { 2362d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar nextFsiIndex = i; 2363d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 2364d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2366d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (nextFsiIndex != -1) { 2367d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(nextFsiIndex); 2368d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(nextFsiIndex); 2369d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi.mPosition; 2370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2371d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 2372d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2373d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void addFullSpanItem(FullSpanItem fullSpanItem) { 2375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = new ArrayList<FullSpanItem>(); 2377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2378d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int size = mFullSpanItems.size(); 2379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < size; i++) { 2380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem other = mFullSpanItems.get(i); 2381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (other.mPosition == fullSpanItem.mPosition) { 2382d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 2383d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar throw new IllegalStateException("two fsis for same position"); 2384d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(i); 2386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2388d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (other.mPosition >= fullSpanItem.mPosition) { 2389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.add(i, fullSpanItem); 2390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2392d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // if it is not added to a position. 2394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.add(fullSpanItem); 2395d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2396d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2397d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem getFullSpanItem(int position) { 2398d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2399d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2400d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2401d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2402d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final FullSpanItem fsi = mFullSpanItems.get(i); 2403d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition == position) { 2404d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 2405d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2408d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2409d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2410d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2411d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param minPos inclusive 2412d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param maxPos exclusive 2413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param gapDir if not 0, returns FSIs on in that direction 2414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2415d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem getFirstFullSpanItemInRange(int minPos, int maxPos, int gapDir) { 2416d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2417d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2418d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2419d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mFullSpanItems.size(); i++) { 2420d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= maxPos) { 2422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2423d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= minPos && (gapDir == 0 || fsi.mGapDir == gapDir)) { 2425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 2426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2430d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2431d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2432d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * We keep information about full span items because they may create gaps in the UI. 2433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2434d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static class FullSpanItem implements Parcelable { 2435d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2436d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mPosition; 2437d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mGapDir; 2438d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int[] mGapPerSpan; 2439d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2440d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem(Parcel in) { 2441d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPosition = in.readInt(); 2442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mGapDir = in.readInt(); 2443d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int spanCount = in.readInt(); 2444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (spanCount > 0) { 2445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mGapPerSpan = new int[spanCount]; 2446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar in.readIntArray(mGapPerSpan); 2447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2449d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2450d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem() { 2451d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2452d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2453d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int getGapForSpan(int spanIndex) { 2454d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex]; 2455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void invalidateSpanGaps() { 2458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mGapPerSpan = null; 2459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2460d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2461d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2462d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int describeContents() { 2463d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 2464d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void writeToParcel(Parcel dest, int flags) { 2468d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mPosition); 2469d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mGapDir); 2470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mGapPerSpan != null && mGapPerSpan.length > 0) { 2471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mGapPerSpan.length); 2472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeIntArray(mGapPerSpan); 2473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(0); 2475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public String toString() { 2480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return "FullSpanItem{" + 2481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar "mPosition=" + mPosition + 2482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ", mGapDir=" + mGapDir + 2483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ", mGapPerSpan=" + Arrays.toString(mGapPerSpan) + 2484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar '}'; 2485d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public static final Parcelable.Creator<FullSpanItem> CREATOR 2488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar = new Parcelable.Creator<FullSpanItem>() { 2489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem createFromParcel(Parcel in) { 2491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return new FullSpanItem(in); 2492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem[] newArray(int size) { 2496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return new FullSpanItem[size]; 2497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2498d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar }; 24992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar static class SavedState implements Parcelable { 25032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mAnchorPosition; 2505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated 2506b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar int mSpanOffsetsSize; 25072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mSpanOffsets; 25082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mSpanLookupSize; 25092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mSpanLookup; 2510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar List<LazySpanLookup.FullSpanItem> mFullSpanItems; 25112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mReverseLayout; 25122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mAnchorLayoutFromEnd; 2513d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mLastLayoutRTL; 25142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState() { 25162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar SavedState(Parcel in) { 25192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = in.readInt(); 2520333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = in.readInt(); 2521b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = in.readInt(); 2522b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar if (mSpanOffsetsSize > 0) { 2523b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsets = new int[mSpanOffsetsSize]; 25242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar in.readIntArray(mSpanOffsets); 25252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = in.readInt(); 25282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpanLookupSize > 0) { 25292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = new int[mSpanLookupSize]; 25302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar in.readIntArray(mSpanLookup); 25312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = in.readInt() == 1; 25332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorLayoutFromEnd = in.readInt() == 1; 2534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = in.readInt() == 1; 2535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = in.readArrayList( 2536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem.class.getClassLoader()); 25372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState(SavedState other) { 2540b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = other.mSpanOffsetsSize; 25412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = other.mAnchorPosition; 2542333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = other.mVisibleAnchorPosition; 25432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = other.mSpanOffsets; 25442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = other.mSpanLookupSize; 25452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = other.mSpanLookup; 25462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = other.mReverseLayout; 25472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd; 2548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = other.mLastLayoutRTL; 2549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = other.mFullSpanItems; 25502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateSpanInfo() { 25532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = null; 2554b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = 0; 25552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = 0; 25562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = null; 2557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = null; 25582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateAnchorPositionInfo() { 25612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = null; 2562b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = 0; 2563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mAnchorPosition = NO_POSITION; 2564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mVisibleAnchorPosition = NO_POSITION; 25652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 25682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int describeContents() { 25692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 25702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 25732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void writeToParcel(Parcel dest, int flags) { 25742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mAnchorPosition); 2575333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar dest.writeInt(mVisibleAnchorPosition); 2576b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar dest.writeInt(mSpanOffsetsSize); 2577b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar if (mSpanOffsetsSize > 0) { 25782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeIntArray(mSpanOffsets); 25792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mSpanLookupSize); 25812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpanLookupSize > 0) { 25822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeIntArray(mSpanLookup); 25832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mReverseLayout ? 1 : 0); 25852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0); 2586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mLastLayoutRTL ? 1 : 0); 2587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeList(mFullSpanItems); 25882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final Parcelable.Creator<SavedState> CREATOR 25912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar = new Parcelable.Creator<SavedState>() { 25922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 25932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState createFromParcel(Parcel in) { 25942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState(in); 25952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 25982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState[] newArray(int size) { 25992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState[size]; 26002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar }; 26022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2603d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Data class to hold the information about an anchor position which is used in onLayout call. 2606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private class AnchorInfo { 2608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2609d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mPosition; 2610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mOffset; 2611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mLayoutFromEnd; 2612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mInvalidateOffsets; 2613d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2614d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void reset() { 2615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPosition = NO_POSITION; 2616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = INVALID_OFFSET; 2617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLayoutFromEnd = false; 2618d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mInvalidateOffsets = false; 2619d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2620d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void assignCoordinateFromPadding() { 2622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = mLayoutFromEnd ? mPrimaryOrientation.getEndAfterPadding() 2623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 2624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void assignCoordinateFromPadding(int addedDistance) { 2627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mLayoutFromEnd) { 2628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = mPrimaryOrientation.getEndAfterPadding() - addedDistance; 2629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = mPrimaryOrientation.getStartAfterPadding() + addedDistance; 2631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 26342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar} 2635