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: 77115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar * <pre> 782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * AAA 792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * _BC 802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DDD 81115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar * </pre> 82115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar * <p> 832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It will animate to the following state: 84115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar * <pre> 852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * AAA 862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * BC_ 872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * DDD 88115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar * </pre> 892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; 912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final int INVALID_OFFSET = Integer.MIN_VALUE; 932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Number of spans 962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mSpanCount = -1; 982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span[] mSpans; 1002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Primary orientation is the layout's orientation, secondary orientation is the orientation 1032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * for spans. Having both makes code much cleaner for calculations. 1042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper mPrimaryOrientation; 1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper mSecondaryOrientation; 1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mOrientation; 1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The width or height per span, depending on the orientation. 1122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mSizePerSpan; 1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private LayoutState mLayoutState; 1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mReverseLayout = false; 1182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Aggregated reverse layout value that takes RTL into account. 1212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 122d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mShouldReverseLayout = false; 1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Temporary variable used during fill method to check which spans needs to be filled. 1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private BitSet mRemainingSpans; 1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When LayoutManager needs to scroll to a position, it sets this variable and requests a 1312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * layout which will check this variable and re-layout accordingly. 1322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 133d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mPendingScrollPosition = NO_POSITION; 1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is 1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * called. 1382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1396e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar int mPendingScrollPositionOffset = INVALID_OFFSET; 1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Keeps the mapping between the adapter positions and spans. This is necessary to provide 1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * a consistent experience when user scrolls the list. 1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LazySpanLookup mLazySpanLookup = new LazySpanLookup(); 1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * how we handle gaps in UI. 1492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS; 1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Saved state needs this information to properly layout on restore. 1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private boolean mLastLayoutFromEnd; 1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 158d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Saved state and onLayout needs this information to re-layout properly 159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 160d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean mLastLayoutRTL; 161d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 162d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * SavedState is not handled until a layout happens. This is where we keep it until next 1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * layout. 1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private SavedState mPendingSavedState; 1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 169d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Re-used measurement specs. updated by onLayout. 1702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int mFullSizeSpec, mWidthSpec, mHeightSpec; 172d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Re-used anchor info. 175d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 176d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private final AnchorInfo mAnchorInfo = new AnchorInfo(); 177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 179d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * If a full span item is invalid / or created in reverse direction; it may create gaps in 180d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * the UI. While laying out, if such case is detected, we set this flag. 181d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * <p> 182d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * After scrolling stops, we check this flag and if it is set, re-layout. 183d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 184d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean mLaidOutInvalidFullSpan = false; 185d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 186d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 187d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}. 188d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)} 189d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 190d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean mSmoothScrollbarEnabled = true; 191d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 192d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private final Runnable checkForGapsRunnable = new Runnable() { 193d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void run() { 195d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar checkForGaps(); 196d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 197d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar }; 1982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 2002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Creates a StaggeredGridLayoutManager with given parameters. 2012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 2022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param spanCount If orientation is vertical, spanCount is number of columns. If 2032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * orientation is horizontal, spanCount is number of rows. 2049bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL} 2052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 2062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public StaggeredGridLayoutManager(int spanCount, int orientation) { 2072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = orientation; 2082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar setSpanCount(spanCount); 2092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Checks for gaps in the UI that may be caused by adapter changes. 213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * <p> 214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * When a full span item is laid out in reverse direction, it sets a flag which we check when 215d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * scroll is stopped (or re-layout happens) and re-layout after first valid item. 216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void checkForGaps() { 218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0 || mGapStrategy == GAP_HANDLING_NONE) { 219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int minPos, maxPos; 222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar minPos = getLastChildPosition(); 224d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar maxPos = getFirstChildPosition(); 225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar minPos = getFirstChildPosition(); 227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar maxPos = getLastChildPosition(); 228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 229d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (minPos == 0) { 230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View gapView = hasGapsToFix(); 231d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (gapView != null) { 232d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.clear(); 233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestSimpleAnimationsInNextLayout(); 234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestLayout(); 235d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 236d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 237d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 238d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!mLaidOutInvalidFullSpan) { 239d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 240d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 241d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int invalidGapDir = mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; 242d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LazySpanLookup.FullSpanItem invalidFsi = mLazySpanLookup 243f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar .getFirstFullSpanItemInRange(minPos, maxPos + 1, invalidGapDir, true); 244d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (invalidFsi == null) { 245d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan = false; 246d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.forceInvalidateAfter(maxPos + 1); 247d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 248d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 249d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LazySpanLookup.FullSpanItem validFsi = mLazySpanLookup 250d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar .getFirstFullSpanItemInRange(minPos, invalidFsi.mPosition, 251f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar invalidGapDir * -1, true); 252d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (validFsi == null) { 253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.forceInvalidateAfter(invalidFsi.mPosition); 254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.forceInvalidateAfter(validFsi.mPosition + 1); 256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestSimpleAnimationsInNextLayout(); 258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestLayout(); 259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 260d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 2622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onScrollStateChanged(int state) { 263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (state == RecyclerView.SCROLL_STATE_IDLE) { 264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar checkForGaps(); 265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 269d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 270d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 271d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].clear(); 272d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 273d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 274d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 276d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Checks for gaps if we've reached to the top of the list. 277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * <p> 278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Intermediate gaps created by full span items are tracked via mLaidOutInvalidFullSpan field. 279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View hasGapsToFix() { 281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int startChildIndex = 0; 282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int endChildIndex = getChildCount() - 1; 283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar BitSet mSpansToCheck = new BitSet(mSpanCount); 284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpansToCheck.set(0, mSpanCount, true); 285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int firstChildIndex, childLimit; 287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int preferredSpanDir = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1; 288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar firstChildIndex = endChildIndex - 1; 291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar childLimit = startChildIndex - 1; 292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar firstChildIndex = startChildIndex; 294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar childLimit = endChildIndex; 295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1; 297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) { 298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View child = getChildAt(i); 299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mSpansToCheck.get(lp.mSpan.mIndex)) { 301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (checkSpanForGap(lp.mSpan)) { 302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child; 303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpansToCheck.clear(lp.mSpan.mIndex); 305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; // quick reject 308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (i + nextChildDiff != childLimit) { 311d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View nextChild = getChildAt(i + nextChildDiff); 312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean compareSpans = false; 313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // ensure child's end is below nextChild's end 315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int myEnd = mPrimaryOrientation.getDecoratedEnd(child); 316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild); 317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (myEnd < nextEnd) { 318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child;//i should have a better position 319d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else if (myEnd == nextEnd) { 320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar compareSpans = true; 321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int myStart = mPrimaryOrientation.getDecoratedStart(child); 324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild); 325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (myStart > nextStart) { 326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child;//i should have a better position 327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else if (myStart == nextStart) { 328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar compareSpans = true; 329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (compareSpans) { 332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // equal, check span indices. 333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LayoutParams nextLp = (LayoutParams) nextChild.getLayoutParams(); 334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mSpan.mIndex - nextLp.mSpan.mIndex < 0 != preferredSpanDir < 0) { 335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return child; 336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 3382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // everything looks good 341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean checkSpanForGap(Span span) { 345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mShouldReverseLayout) { 346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) { 347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) { 350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 352d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return false; 3532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the number of spans for the layout. This will invalidate all of the span assignments 3572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * for Views. 3582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 3592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Calling this method will automatically result in a new layout request unless the spanCount 3602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * parameter is equal to current span count. 3612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 3622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param spanCount Number of spans to layout 3632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setSpanCount(int spanCount) { 3650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 3662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanCount != mSpanCount) { 3672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateSpanAssignments(); 3682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanCount = spanCount; 3692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans = new BitSet(mSpanCount); 3702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans = new Span[mSpanCount]; 3712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 3722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i] = new Span(i); 3732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 3752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 3782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 3792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep 380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * scroll position if this method is called after views are laid out. 3812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 382d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} 3832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 3842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setOrientation(int orientation) { 3852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (orientation != HORIZONTAL && orientation != VERTICAL) { 3862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar throw new IllegalArgumentException("invalid orientation."); 3872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 3892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (orientation == mOrientation) { 3902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 3912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mOrientation = orientation; 3932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation != null && mSecondaryOrientation != null) { 3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // swap 3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar OrientationHelper tmp = mPrimaryOrientation; 3962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation = mSecondaryOrientation; 3972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation = tmp; 3982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 3992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets whether LayoutManager should start laying out items from the end of the UI. The order 4042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * items are traversed is not affected by this call. 4052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * For vertical layout, if it is set to <code>true</code>, first item will be at the bottom of 407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * the list. 4082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 4092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For horizontal layouts, it depends on the layout direction. 4102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if 4112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link RecyclerView}} is RTL, it will layout from LTR. 4122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 4132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param reverseLayout Whether layout should be in reverse or not 4142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setReverseLayout(boolean reverseLayout) { 4160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) { 4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.mReverseLayout = reverseLayout; 4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = reverseLayout; 4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the current gap handling strategy for StaggeredGridLayoutManager. 4262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Staggered grid may have gaps in the layout due to changes in the adapter. To avoid gaps, 428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * StaggeredGridLayoutManager provides 2 options. Check {@link #GAP_HANDLING_NONE} and 429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} for details. 4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}. 4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return Current gap handling strategy. 4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setGapStrategy(int) 4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_NONE 4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS 4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getGapStrategy() { 4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mGapStrategy; 4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter 4442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * is different than the current strategy, calling this method will trigger a layout request. 4452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param gapStrategy The new gap handling strategy. Should be 447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or {@link 448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * #GAP_HANDLING_NONE}. 4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #getGapStrategy() 4502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setGapStrategy(int gapStrategy) { 4520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar assertNotInLayoutOrScroll(null); 4532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gapStrategy == mGapStrategy) { 4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 4552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (gapStrategy != GAP_HANDLING_NONE && 4572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) { 4582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE " 459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS"); 4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mGapStrategy = gapStrategy; 4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar @Override 4660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar public void assertNotInLayoutOrScroll(String message) { 4670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar if (mPendingSavedState == null) { 4680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar super.assertNotInLayoutOrScroll(message); 4690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 4700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar } 4710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar 4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the number of spans laid out by StaggeredGridLayoutManager. 4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 4752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return Number of spans in the layout 4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getSpanCount() { 4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mSpanCount; 4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items. 4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If you need to cancel current assignments, you can call this method which will clear all 4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * assignments and request a new layout. 4862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 4872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void invalidateSpanAssignments() { 4882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.clear(); 4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void ensureOrientationHelper() { 4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation == null) { 4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation); 4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSecondaryOrientation = OrientationHelper 4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar .createOrientationHelper(this, 1 - mOrientation); 4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState = new LayoutState(); 4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Calculates the views' layout order. (e.g. from end to start or start to end) 5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * RTL layout support is applied automatically. So if layout is RTL and 5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left. 5052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 5062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void resolveShouldLayoutReverse() { 5072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // A == B is the same result, but we rather keep it readable 5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL || !isLayoutRTL()) { 5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mShouldReverseLayout = mReverseLayout; 5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mShouldReverseLayout = !mReverseLayout; 5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean isLayoutRTL() { 5162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL; 5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns whether views are laid out in reverse order or not. 5212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Not that this value is not affected by RecyclerView's layout direction. 5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return True if layout is reversed, false otherwise 5252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setReverseLayout(boolean) 5262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 5272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean getReverseLayout() { 5282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mReverseLayout; 5292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureOrientationHelper(); 5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final AnchorInfo anchorInfo = mAnchorInfo; 536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.reset(); 5372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 539d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar applyPendingSavedState(anchorInfo); 5402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar resolveShouldLayoutReverse(); 542d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = mShouldReverseLayout; 5432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 545d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateAnchorInfoForLayout(state, anchorInfo); 5462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 547d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState == null) { 548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd || 549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar isLayoutRTL() != mLastLayoutRTL) { 550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.clear(); 551d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mInvalidateOffsets = true; 552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 5532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 554d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 5550ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar if (getChildCount() > 0 && (mPendingSavedState == null || 556b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mPendingSavedState.mSpanOffsetsSize < 1)) { 557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mInvalidateOffsets) { 5582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Scroll to position is set, clear. 5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].clear(); 561d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mOffset != INVALID_OFFSET) { 562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].setLine(anchorInfo.mOffset); 5632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 567d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset); 5682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar detachAndScrapAttachedViews(recycler); 572d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan = false; 573d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateMeasureSpecs(); 574d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mLayoutFromEnd) { 575d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout start. 576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillStart(anchorInfo.mPosition, state); 577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 578d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout end. 579d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillEnd(anchorInfo.mPosition, state); 5802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; 581d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 582d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout end. 584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillEnd(anchorInfo.mPosition, state); 585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout start. 587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateLayoutStateToFillStart(anchorInfo.mPosition, state); 5882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; 589d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fill(recycler, mLayoutState, state); 5902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 5912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 5922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() > 0) { 5932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout) { 5942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixEndGap(recycler, state, true); 5952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixStartGap(recycler, state, false); 5962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 5972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixStartGap(recycler, state, true); 5982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixEndGap(recycler, state, false); 5992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 6026e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar if (!state.isPreLayout()) { 603d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() > 0 && mPendingScrollPosition != NO_POSITION && 604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLaidOutInvalidFullSpan) { 605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ViewCompat.postOnAnimation(getChildAt(0), checkForGapsRunnable); 606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPosition = NO_POSITION; 6086e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 6096e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar } 610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd; 611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = isLayoutRTL(); 6122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState = null; // we don't need this anymore 6132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 6142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void applyPendingSavedState(AnchorInfo anchorInfo) { 616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "found saved state: " + mPendingSavedState); 6182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 619d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mSpanOffsetsSize > 0) { 620d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mSpanOffsetsSize == mSpanCount) { 621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].clear(); 623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int line = mPendingSavedState.mSpanOffsets[i]; 624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (line != Span.INVALID_LINE) { 625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mAnchorLayoutFromEnd) { 626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line += mPrimaryOrientation.getEndAfterPadding(); 627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line += mPrimaryOrientation.getStartAfterPadding(); 629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].setLine(line); 632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 634d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingSavedState.invalidateSpanInfo(); 635d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition; 636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 637d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 638d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = mPendingSavedState.mLastLayoutRTL; 639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar setReverseLayout(mPendingSavedState.mReverseLayout); 640d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar resolveShouldLayoutReverse(); 6412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 642d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mAnchorPosition != NO_POSITION) { 643d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPosition = mPendingSavedState.mAnchorPosition; 644d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd; 6452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = mShouldReverseLayout; 6472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 648d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState.mSpanLookupSize > 1) { 649d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.mData = mPendingSavedState.mSpanLookup; 650d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.mFullSpanItems = mPendingSavedState.mFullSpanItems; 651d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 652d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 653d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 654d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void updateAnchorInfoForLayout(RecyclerView.State state, AnchorInfo anchorInfo) { 655d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (updateAnchorFromPendingData(state, anchorInfo)) { 656d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 657d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 658d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (updateAnchorFromChildren(state, anchorInfo)) { 659d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 660d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 661d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 662d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "Deciding anchor info from fresh state"); 663d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 664d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.assignCoordinateFromPadding(); 665d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = 0; 666d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 667d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 668d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean updateAnchorFromChildren(RecyclerView.State state, AnchorInfo anchorInfo) { 669d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // We don't recycle views out of adapter order. This way, we can rely on the first or 670d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // last child as the anchor position. 671d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Layout direction may change but we should select the child depending on the latest 672d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // layout direction. Otherwise, we'll choose the wrong child. 673d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mLastLayoutFromEnd 674d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? findLastReferenceChildPosition(state.getItemCount()) 675d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : findFirstReferenceChildPosition(state.getItemCount()); 676d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = INVALID_OFFSET; 677d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 678d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 679d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 680d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) { 681d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Validate scroll position if exists. 682d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) { 683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return false; 684d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 685d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Validate it. 686d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) { 687d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPosition = NO_POSITION; 688d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 689d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return false; 690d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 691d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 692d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingSavedState == null || mPendingSavedState.mAnchorPosition == NO_POSITION 693d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar || mPendingSavedState.mSpanOffsetsSize < 1) { 694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // If item is visible, make it fully visible. 695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View child = findViewByPosition(mPendingScrollPosition); 696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (child != null) { 697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Use regular anchor position, offset according to pending offset and target 698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // child 699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mShouldReverseLayout ? getLastChildPosition() 700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : getFirstChildPosition(); 701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingScrollPositionOffset != INVALID_OFFSET) { 703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (anchorInfo.mLayoutFromEnd) { 704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int target = mPrimaryOrientation.getEndAfterPadding() - 705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPositionOffset; 706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child); 707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int target = mPrimaryOrientation.getStartAfterPadding() + 709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPendingScrollPositionOffset; 710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child); 711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // no offset provided. Decide according to the child location 716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child); 717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (childSize > mPrimaryOrientation.getTotalSpace()) { 718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Item does not fit. Fix depending on layout direction. 719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = anchorInfo.mLayoutFromEnd 720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? mPrimaryOrientation.getEndAfterPadding() 721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int startGap = mPrimaryOrientation.getDecoratedStart(child) 726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar - mPrimaryOrientation.getStartAfterPadding(); 727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (startGap < 0) { 728d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = -startGap; 729d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 731d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int endGap = mPrimaryOrientation.getEndAfterPadding() - 732d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPrimaryOrientation.getDecoratedEnd(child); 733d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (endGap < 0) { 734d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = endGap; 735d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 7362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 737d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // child already visible. just layout as usual 738d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = INVALID_OFFSET; 739d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 740d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // Child is not visible. Set anchor coordinate depending on in which direction 741d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // child will be visible. 742d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mPendingScrollPosition; 743d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mPendingScrollPositionOffset == INVALID_OFFSET) { 744d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int position = calculateScrollDirectionForPosition( 745d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition); 746d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mLayoutFromEnd = position == LAYOUT_END; 747d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.assignCoordinateFromPadding(); 748d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 749d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.assignCoordinateFromPadding(mPendingScrollPositionOffset); 750d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 751d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mInvalidateOffsets = true; 7522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 753d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 754d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mOffset = INVALID_OFFSET; 755d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar anchorInfo.mPosition = mPendingScrollPosition; 756d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 757d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return true; 758d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 759d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 760d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void updateMeasureSpecs() { 761d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount; 762d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSizeSpec = View.MeasureSpec.makeMeasureSpec( 763d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY); 764d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mOrientation == VERTICAL) { 765d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mWidthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY); 766d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mHeightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 767d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 768d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mHeightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY); 769d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mWidthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 7702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 7732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 7742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean supportsPredictiveItemAnimations() { 7756e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar return mPendingSavedState == null; 7762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 7772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 778333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 779333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the first visible view for each span. 780333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 781333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 782333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 783333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 784333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 785333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 786333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 787333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 788333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 789333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 790333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 791333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 792d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the first visible item in each span. If a span does not have 793d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * any items, {@link RecyclerView#NO_POSITION} is returned for that span. 794333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstCompletelyVisibleItemPositions(int[]) 795333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastVisibleItemPositions(int[]) 796333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 797333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findFirstVisibleItemPositions(int[] into) { 798333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 799333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 800333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 801333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 802333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 803333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 804d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 805333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findFirstVisibleItemPosition(); 806333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 807333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 808333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 809333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 810333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 811333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the first completely visible view for each span. 812333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 813333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 814333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 815333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 816333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 817333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 818333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 819333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 820333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 821333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 822333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 823333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 824d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the first fully visible item in each span. If a span does 825d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span. 826333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstVisibleItemPositions(int[]) 827333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastCompletelyVisibleItemPositions(int[]) 828333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 829333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findFirstCompletelyVisibleItemPositions(int[] into) { 830333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 831333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 832333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 833333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 834333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 835333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 836d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 837333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition(); 838333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 839333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 840333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 841333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 842333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 843333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the last visible view for each span. 844333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 845333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 846333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 847333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 848333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 849333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 850333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 851333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 852333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 853333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 854333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 855333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 856d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the last visible item in each span. If a span does not have 857d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * any items, {@link RecyclerView#NO_POSITION} is returned for that span. 858333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastCompletelyVisibleItemPositions(int[]) 859333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstVisibleItemPositions(int[]) 860333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 861333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findLastVisibleItemPositions(int[] into) { 862333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 863333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 864333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 865333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 866333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 867333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 868d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 869333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findLastVisibleItemPosition(); 870333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 871333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 872333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 873333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 874333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 875333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Returns the adapter position of the last completely visible view for each span. 876333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 877333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Note that, this value is not affected by layout orientation or item order traversal. 878333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, 879333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * not in the layout. 880333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 881333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * If RecyclerView has item decorators, they will be considered in calculations as well. 882333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * <p> 883333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those 884333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * views are ignored in this method. 885333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * 886333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @param into An array to put the results into. If you don't provide any, LayoutManager will 887333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * create a new one. 888d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return The adapter position of the last fully visible item in each span. If a span does not 889d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * have any items, {@link RecyclerView#NO_POSITION} is returned for that span. 890333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findFirstCompletelyVisibleItemPositions(int[]) 891333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * @see #findLastVisibleItemPositions(int[]) 892333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 893333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int[] findLastCompletelyVisibleItemPositions(int[] into) { 894333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (into == null) { 895333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into = new int[mSpanCount]; 896333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else if (into.length < mSpanCount) { 897333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" 898333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); 899333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 900d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 901333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar into[i] = mSpans[i].findLastCompletelyVisibleItemPosition(); 902333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 903333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return into; 904333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 905333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 906d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 907d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeHorizontalScrollOffset(RecyclerView.State state) { 908d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollOffset(state); 909d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 910d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 911d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int computeScrollOffset(RecyclerView.State state) { 912d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0) { 913d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 914d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 915ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar ensureOrientationHelper(); 916d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation, 9176490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) 9186490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), 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 } 936ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar ensureOrientationHelper(); 937d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation, 9386490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) 9396490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), 940d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar this, mSmoothScrollbarEnabled); 941d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 942d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 943d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 944d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeVerticalScrollExtent(RecyclerView.State state) { 945d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollExtent(state); 946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 947d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 948d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 949d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeHorizontalScrollRange(RecyclerView.State state) { 950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollRange(state); 951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int computeScrollRange(RecyclerView.State state) { 954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (getChildCount() == 0) { 955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 957ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar ensureOrientationHelper(); 958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation, 9596490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) 9606490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), 961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar this, mSmoothScrollbarEnabled); 962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 963d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 964d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 965d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int computeVerticalScrollRange(RecyclerView.State state) { 966d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return computeScrollRange(state); 967d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 969d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp) { 970d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 971d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mOrientation == VERTICAL) { 97242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar measureChildWithDecorationsAndMargin(child, mFullSizeSpec, 97342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar getSpecForDimension(lp.height, mHeightSpec)); 974d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 97542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar measureChildWithDecorationsAndMargin(child, 97642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar getSpecForDimension(lp.width, mWidthSpec), mFullSizeSpec); 977d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 978d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 97942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (mOrientation == VERTICAL) { 98042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar measureChildWithDecorationsAndMargin(child, mWidthSpec, 98142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar getSpecForDimension(lp.height, mHeightSpec)); 98242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } else { 98342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar measureChildWithDecorationsAndMargin(child, 98442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar getSpecForDimension(lp.width, mWidthSpec), mHeightSpec); 98542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 98642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 98742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } 98842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar 98942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar private int getSpecForDimension(int dim, int defaultSpec) { 99042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar if (dim < 0) { 99142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar return defaultSpec; 99242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar } else { 99342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY); 994d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 995d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 996d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 9972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void measureChildWithDecorationsAndMargin(View child, int widthSpec, 9982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int heightSpec) { 9992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); 10002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 10012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + insets.left, 10022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.rightMargin + insets.right); 10032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + insets.top, 10042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.bottomMargin + insets.bottom); 10052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar child.measure(widthSpec, heightSpec); 10062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int updateSpecWithExtra(int spec, int startInset, int endInset) { 10092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startInset == 0 && endInset == 0) { 10102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return spec; 10112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int mode = View.MeasureSpec.getMode(spec); 10132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) { 10142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return View.MeasureSpec.makeMeasureSpec( 10152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View.MeasureSpec.getSize(spec) - startInset - endInset, mode); 10162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return spec; 10182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 10212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onRestoreInstanceState(Parcelable state) { 10222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (state instanceof SavedState) { 10232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState = (SavedState) state; 10242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 10252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (DEBUG) { 10262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "invalid saved state class"); 10272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 10312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public Parcelable onSaveInstanceState() { 10322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 10332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState(mPendingSavedState); 10342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar SavedState state = new SavedState(); 10362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mReverseLayout = mReverseLayout; 10372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorLayoutFromEnd = mLastLayoutFromEnd; 1038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mLastLayoutRTL = mLastLayoutRTL; 10392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLazySpanLookup != null && mLazySpanLookup.mData != null) { 10412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookup = mLazySpanLookup.mData; 10422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookupSize = state.mSpanLookup.length; 1043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mFullSpanItems = mLazySpanLookup.mFullSpanItems; 10442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 10452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanLookupSize = 0; 10462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 10482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() > 0) { 1049ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar ensureOrientationHelper(); 10502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition() 10512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : getFirstChildPosition(); 1052333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt(); 1053b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar state.mSpanOffsetsSize = mSpanCount; 10542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar state.mSpanOffsets = new int[mSpanCount]; 10552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1056d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int line; 1057d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mLastLayoutFromEnd) { 1058d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line = mSpans[i].getEndLine(Span.INVALID_LINE); 1059d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (line != Span.INVALID_LINE) { 1060d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line -= mPrimaryOrientation.getEndAfterPadding(); 1061d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1062d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1063d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line = mSpans[i].getStartLine(Span.INVALID_LINE); 1064d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (line != Span.INVALID_LINE) { 1065d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar line -= mPrimaryOrientation.getStartAfterPadding(); 1066d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1067d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1068d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mSpanOffsets[i] = line; 10692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1071d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mAnchorPosition = NO_POSITION; 1072d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar state.mVisibleAnchorPosition = NO_POSITION; 1073b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar state.mSpanOffsetsSize = 0; 10742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 10762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "saved state:\n" + state); 10772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return state; 10792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 10802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1081a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1082a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler, 1083a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) { 1084a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ViewGroup.LayoutParams lp = host.getLayoutParams(); 1085a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (!(lp instanceof LayoutParams)) { 1086a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar super.onInitializeAccessibilityNodeInfoForItem(host, info); 1087a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return; 1088a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1089a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar LayoutParams sglp = (LayoutParams) lp; 1090a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == HORIZONTAL) { 1091a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( 1092a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1, 1093a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar -1, -1, 1094a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.mFullSpan, false)); 1095a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else { // VERTICAL 1096a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( 1097a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar -1, -1, 1098a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1, 1099a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar sglp.mFullSpan, false)); 1100a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1101a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1102a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1103a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1104a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1105a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar super.onInitializeAccessibilityEvent(event); 1106a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (getChildCount() > 0) { 1107a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final AccessibilityRecordCompat record = AccessibilityEventCompat 1108a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar .asRecord(event); 11096490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar final View start = findFirstVisibleItemClosestToStart(false, true); 11106490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar final View end = findFirstVisibleItemClosestToEnd(false, true); 1111a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (start == null || end == null) { 1112a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return; 1113a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1114a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final int startPos = getPosition(start); 1115a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final int endPos = getPosition(end); 1116a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (startPos < endPos) { 1117a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setFromIndex(startPos); 1118a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setToIndex(endPos); 1119a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else { 1120a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setFromIndex(endPos); 1121a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar record.setToIndex(startPos); 1122a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1123a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1124a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1125a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1126333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar /** 1127333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar * Finds the first fully visible child to be used as an anchor child if span count changes when 11286490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar * state is restored. If no children is fully visible, returns a partially visible child instead 11296490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar * of returning null. 1130333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar */ 1131333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int findFirstVisibleItemPositionInt() { 11326490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true, true) : 11336490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar findFirstVisibleItemClosestToStart(true, true); 1134d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return first == null ? NO_POSITION : getPosition(first); 1135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1136d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1137a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1138a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getRowCountForAccessibility(RecyclerView.Recycler recycler, 1139a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 1140a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == HORIZONTAL) { 1141a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanCount; 1142a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1143a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return super.getRowCountForAccessibility(recycler, state); 1144a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1145a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 1146a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 1147a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getColumnCountForAccessibility(RecyclerView.Recycler recycler, 1148a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 1149a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == VERTICAL) { 1150a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanCount; 1151a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1152a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return super.getColumnCountForAccessibility(recycler, state); 1153a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 1154a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 11556490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar View findFirstVisibleItemClosestToStart(boolean fullyVisible, boolean acceptPartiallyVisible) { 1156ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar ensureOrientationHelper(); 1157333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); 1158333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); 1159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int limit = getChildCount(); 11606490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar View partiallyVisible = null; 116142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar for (int i = 0; i < limit; i++) { 1162333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final View child = getChildAt(i); 11636490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar if (mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) { 11646490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar if ((!fullyVisible 11656490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar || mPrimaryOrientation.getDecoratedStart(child) >= boundsStart)) { 11666490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar return child; 11676490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar } else if (acceptPartiallyVisible && partiallyVisible == null) { 11686490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar partiallyVisible = child; 11696490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar } 1170d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 11726490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar return partiallyVisible; 1173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 11756490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar View findFirstVisibleItemClosestToEnd(boolean fullyVisible, boolean acceptPartiallyVisible) { 1176ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar ensureOrientationHelper(); 1177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); 1178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); 11796490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar View partiallyVisible = null; 118042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar for (int i = getChildCount() - 1; i >= 0; i--) { 1181d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View child = getChildAt(i); 11826490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(child) >= boundsStart) { 11836490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar if (!fullyVisible || mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) { 11846490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar return child; 11856490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar } else if (acceptPartiallyVisible && partiallyVisible == null) { 11866490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar partiallyVisible = child; 11876490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar } 1188333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1189333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 11906490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar return partiallyVisible; 1191333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 1192333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state, 11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean canOffsetChildren) { 11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); 11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine; 11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int fixOffset; 11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gap > 0) { 11992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixOffset = -scrollBy(-gap, recycler, state); 12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; // nothing to fix 12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gap -= fixOffset; 12042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (canOffsetChildren && gap > 0) { 12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(gap); 12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state, 12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean canOffsetChildren) { 12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding()); 12122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding(); 12132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int fixOffset; 12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (gap > 0) { 12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar fixOffset = scrollBy(gap, recycler, state); 12162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; // nothing to fix 12182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar gap -= fixOffset; 12202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (canOffsetChildren && gap > 0) { 12212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.offsetChildren(-gap); 12222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateLayoutStateToFillStart(int anchorPosition, RecyclerView.State state) { 12262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = 0; 12272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = anchorPosition; 12282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (isSmoothScrolling()) { 12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetPos = state.getTargetScrollPosition(); 12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout == targetPos < anchorPosition) { 12312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace(); 12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_START; 12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL 12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_HEAD; 12412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateLayoutStateToFillEnd(int anchorPosition, RecyclerView.State state) { 12442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = 0; 12452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = anchorPosition; 12462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (isSmoothScrolling()) { 12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetPos = state.getTargetScrollPosition(); 12482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mShouldReverseLayout == targetPos > anchorPosition) { 12492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace(); 12522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 12542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = 0; 12552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_END; 12572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD 12582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_TAIL; 12592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void offsetChildrenHorizontal(int dx) { 12632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super.offsetChildrenHorizontal(dx); 12642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 12652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].onOffset(dx); 12662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void offsetChildrenVertical(int dy) { 12712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super.offsetChildrenVertical(dy); 12722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 12732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[i].onOffset(dy); 12742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { 1279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.REMOVE); 12802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 12812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 12822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 12832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { 1284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.ADD); 1285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 1288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onItemsChanged(RecyclerView recyclerView) { 1289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.clear(); 1290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar requestLayout(); 1291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 1294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { 1295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(from, to, AdapterHelper.UpdateOp.MOVE); 1296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 1299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) { 1300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.UPDATE); 13012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 13042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Checks whether it should invalidate span assignments in response to an adapter change. 13052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 1306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) { 13072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition(); 1308f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar final int affectedRangeEnd;// exclusive 1309f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar final int affectedRangeStart;// inclusive 1310f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar 1311f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (cmd == AdapterHelper.UpdateOp.MOVE) { 1312f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (positionStart < itemCountOrToPosition) { 1313f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar affectedRangeEnd = itemCountOrToPosition + 1; 1314f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar affectedRangeStart = positionStart; 1315f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } else { 1316f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar affectedRangeEnd = positionStart + 1; 1317f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar affectedRangeStart = itemCountOrToPosition; 1318f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1319f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } else { 1320f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar affectedRangeStart = positionStart; 1321f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar affectedRangeEnd = positionStart + itemCountOrToPosition; 1322f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1323f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar 1324f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar mLazySpanLookup.invalidateAfter(affectedRangeStart); 1325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar switch (cmd) { 1326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar case AdapterHelper.UpdateOp.ADD: 1327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForAddition(positionStart, itemCountOrToPosition); 1328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 1329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar case AdapterHelper.UpdateOp.REMOVE: 1330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForRemoval(positionStart, itemCountOrToPosition); 1331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 1332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar case AdapterHelper.UpdateOp.MOVE: 1333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // TODO optimize 1334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForRemoval(positionStart, 1); 1335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.offsetForAddition(itemCountOrToPosition, 1); 1336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 1337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1338d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1339f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (affectedRangeEnd <= minPosition) { 1340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 13412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1342f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar 13432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition(); 1344f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (affectedRangeStart <= maxPosition) { 13452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 13462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 13482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int fill(RecyclerView.Recycler recycler, LayoutState layoutState, 13502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 13512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(0, mSpanCount, true); 13522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // The target position we are trying to reach. 13532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int targetLine; 13542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /* 13552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * The line until which we can recycle, as long as we add views. 13562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Keep in mind, it is still the line in layout direction which means; to calculate the 13572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * actual recycle line, we should subtract/add the size in orientation. 13582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int recycleLine; 13602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Line of the furthest row. 13612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 13623ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar // ignore padding for recycler 13630ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleLine = mPrimaryOrientation.getEndAfterPadding() + mLayoutState.mAvailable; 13640ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar targetLine = recycleLine + mLayoutState.mExtra + mPrimaryOrientation.getEndPadding(); 1365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 13662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { // LAYOUT_START 13673ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar // ignore padding for recycler 13680ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar recycleLine = mPrimaryOrientation.getStartAfterPadding() - mLayoutState.mAvailable; 13690ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar targetLine = recycleLine - mLayoutState.mExtra - 1370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPrimaryOrientation.getStartAfterPadding(); 13712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1372d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine); 13732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // the default coordinate to add new view. 1375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int defaultNewViewLine = mShouldReverseLayout 1376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? mPrimaryOrientation.getEndAfterPadding() 1377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 13782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 13792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) { 13802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View view = layoutState.next(recycler); 13812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = ((LayoutParams) view.getLayoutParams()); 1382115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int position = lp.getViewLayoutPosition(); 13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanIndex = mLazySpanLookup.getSpan(position); 13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span currentSpan; 1385f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar final boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID; 1386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (assignSpan) { 1387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState); 13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLazySpanLookup.setSpan(position, currentSpan); 1389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 1390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position); 1391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 1394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Log.d(TAG, "using " + spanIndex + " for pos " + position); 1395d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 13962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar currentSpan = mSpans[spanIndex]; 13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1398ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar // assign span before measuring so that item decorators can get updated span index 1399ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar lp.mSpan = currentSpan; 1400ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 1401ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar addView(view); 1402ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar } else { 1403ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar addView(view, 0); 1404ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar } 1405ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar measureChildWithDecorationsAndMargin(view, lp); 1406ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar 14072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int start; 14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int end; 14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 1410d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine) 1411d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : currentSpan.getEndLine(defaultNewViewLine); 14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar end = start + mPrimaryOrientation.getDecoratedMeasurement(view); 1413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (assignSpan && lp.mFullSpan) { 1414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fullSpanItem; 1415d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem = createFullSpanItemFromEnd(start); 1416d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mGapDir = LAYOUT_START; 1417d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mPosition = position; 1418d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.addFullSpanItem(fullSpanItem); 14192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar end = lp.mFullSpan ? getMinStart(defaultNewViewLine) 1422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : currentSpan.getStartLine(defaultNewViewLine); 14232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar start = end - mPrimaryOrientation.getDecoratedMeasurement(view); 1424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (assignSpan && lp.mFullSpan) { 1425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fullSpanItem; 1426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem = createFullSpanItemFromStart(end); 1427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mGapDir = LAYOUT_END; 1428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fullSpanItem.mPosition = position; 1429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLazySpanLookup.addFullSpanItem(fullSpanItem); 14302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // check if this item may create gaps in the future 1434f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD) { 1435f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (assignSpan) { 1436f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar mLaidOutInvalidFullSpan = true; 1437f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } else { 1438f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar final boolean hasInvalidGap; 1439f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 1440f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar hasInvalidGap = !areAllEndsEqual(); 1441f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } else { // layoutState.mLayoutDirection == LAYOUT_START 1442f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar hasInvalidGap = !areAllStartsEqual(); 1443f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1444f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (hasInvalidGap) { 1445f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar final LazySpanLookup.FullSpanItem fullSpanItem = mLazySpanLookup 1446f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar .getFullSpanItem(position); 1447f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (fullSpanItem != null) { 1448f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar fullSpanItem.mHasUnwantedGapAfter = true; 1449f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1450f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar mLaidOutInvalidFullSpan = true; 1451f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1452f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1453f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar 14542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar attachViewToSpans(view, lp, layoutState); 14562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding() 1457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : currentSpan.mIndex * mSizePerSpan + 1458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSecondaryOrientation.getStartAfterPadding(); 14592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view); 14602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == VERTICAL) { 14612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end); 14622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd); 14642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 14662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 1467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine); 14682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine); 14702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 1471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar recycle(recycler, mLayoutState, currentSpan, recycleLine); 14722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 14742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "fill, " + getChildCount()); 14752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mLayoutState.mLayoutDirection == LAYOUT_START) { 14772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding()); 14780ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar return Math.max(0, mLayoutState.mAvailable + (recycleLine - minStart)); 14792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 14802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int max = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); 14810ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar return Math.max(0, mLayoutState.mAvailable + (max - recycleLine)); 14822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 14842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1485d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private LazySpanLookup.FullSpanItem createFullSpanItemFromEnd(int newItemTop) { 1486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem(); 1487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan = new int[mSpanCount]; 1488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan[i] = newItemTop - mSpans[i].getEndLine(newItemTop); 1490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 1492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private LazySpanLookup.FullSpanItem createFullSpanItemFromStart(int newItemBottom) { 1495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem(); 1496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan = new int[mSpanCount]; 1497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1498d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mGapPerSpan[i] = mSpans[i].getStartLine(newItemBottom) - newItemBottom; 1499d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 1501d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1502d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void attachViewToSpans(View view, LayoutParams lp, LayoutState layoutState) { 1504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { 1505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 1506d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar appendViewToAllSpans(view); 1507d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1508d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar lp.mSpan.appendToSpan(view); 1509d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1511d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 1512d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar prependViewToAllSpans(view); 1513d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1514d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar lp.mSpan.prependToSpan(view); 1515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1516d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1517d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1518d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1519d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState, 1520d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Span updatedSpan, int recycleLine) { 1521d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_START) { 1522d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // calculate recycle line 1523d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int maxStart = getMaxStart(updatedSpan.getStartLine()); 1524d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar recycleFromEnd(recycler, Math.max(recycleLine, maxStart) + 1525d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding())); 1526d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1527d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // calculate recycle line 1528d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int minEnd = getMinEnd(updatedSpan.getEndLine()); 1529d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar recycleFromStart(recycler, Math.min(recycleLine, minEnd) - 1530d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding())); 1531d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1532d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1533d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void appendViewToAllSpans(View view) { 1535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // traverse in reverse so that we end up assigning full span items to 0 1536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mSpanCount - 1; i >= 0; i--) { 1537d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].appendToSpan(view); 1538d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1539d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1540d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1541d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void prependViewToAllSpans(View view) { 1542d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // traverse in reverse so that we end up assigning full span items to 0 1543d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mSpanCount - 1; i >= 0; i--) { 1544d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mSpans[i].prependToSpan(view); 1545d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1546d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1547d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void layoutDecoratedWithMargins(View child, int left, int top, int right, int bottom) { 15492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 1551115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar Log.d(TAG, "layout decorated pos: " + lp.getViewLayoutPosition() + ", span:" 1552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + lp.getSpanIndex() + ", fullspan:" + lp.mFullSpan 1553d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + ". l:" + left + ",t:" + top 1554d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + ", r:" + right + ", b:" + bottom); 1555d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 15562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin 15572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar , bottom - lp.bottomMargin); 15582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1560d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void updateAllRemainingSpans(int layoutDir, int targetLine) { 1561d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < mSpanCount; i++) { 1562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mSpans[i].mViews.isEmpty()) { 1563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; 1564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1565d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar updateRemainingSpans(mSpans[i], layoutDir, targetLine); 1566d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1567d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1568d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 15692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void updateRemainingSpans(Span span, int layoutDir, int targetLine) { 15702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int deletedSize = span.getDeletedSize(); 15712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutDir == LAYOUT_START) { 15722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getStartLine(); 15732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line + deletedSize < targetLine) { 15742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(span.mIndex, false); 15752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 15772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int line = span.getEndLine(); 15782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (line - deletedSize > targetLine) { 15792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mRemainingSpans.set(span.mIndex, false); 15802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMaxStart(int def) { 15852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxStart = mSpans[0].getStartLine(def); 15862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanStart = mSpans[i].getStartLine(def); 15882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanStart > maxStart) { 15892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxStart = spanStart; 15902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return maxStart; 15932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 15942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 15952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMinStart(int def) { 15962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minStart = mSpans[0].getStartLine(def); 15972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 15982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanStart = mSpans[i].getStartLine(def); 15992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanStart < minStart) { 16002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minStart = spanStart; 16012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return minStart; 16042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1606f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar boolean areAllEndsEqual() { 1607f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar int end = mSpans[0].getEndLine(Span.INVALID_LINE); 1608f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar for (int i = 1; i < mSpanCount; i++) { 1609f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (mSpans[i].getEndLine(Span.INVALID_LINE) != end) { 1610f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar return false; 1611f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1612f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1613f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar return true; 1614f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1615f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar 1616f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar boolean areAllStartsEqual() { 1617f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar int start = mSpans[0].getStartLine(Span.INVALID_LINE); 1618f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar for (int i = 1; i < mSpanCount; i++) { 1619f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (mSpans[i].getStartLine(Span.INVALID_LINE) != start) { 1620f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar return false; 1621f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1622f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1623f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar return true; 1624f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar } 1625f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar 16262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMaxEnd(int def) { 16272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int maxEnd = mSpans[0].getEndLine(def); 16282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 16292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanEnd = mSpans[i].getEndLine(def); 16302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanEnd > maxEnd) { 16312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxEnd = spanEnd; 16322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return maxEnd; 16352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getMinEnd(int def) { 16382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int minEnd = mSpans[0].getEndLine(def); 16392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 1; i < mSpanCount; i++) { 16402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int spanEnd = mSpans[i].getEndLine(def); 16412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (spanEnd < minEnd) { 16422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minEnd = spanEnd; 16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return minEnd; 16462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void recycleFromStart(RecyclerView.Recycler recycler, int line) { 16492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 16502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "recycling from start for line " + line); 16512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (getChildCount() > 0) { 16532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(0); 16542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedEnd(child) < line) { 16552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 16572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int j = 0; j < mSpanCount; j++) { 16582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[j].popStart(); 16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan.popStart(); 16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar removeAndRecycleView(child, recycler); 16642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return;// done 16662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private void recycleFromEnd(RecyclerView.Recycler recycler, int line) { 16712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 16722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int i; 16732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (i = childCount - 1; i >= 0; i--) { 16742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View child = getChildAt(i); 16752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(child) > line) { 16762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp.mFullSpan) { 16782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int j = 0; j < mSpanCount; j++) { 16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpans[j].popEnd(); 16802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan.popEnd(); 16832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar removeAndRecycleView(child, recycler); 16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 16862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return;// done 16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 16912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 1692d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @return True if last span is the first one we want to fill 1693d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 1694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private boolean preferLastSpan(int layoutDir) { 1695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mOrientation == HORIZONTAL) { 1696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return (layoutDir == LAYOUT_START) != mShouldReverseLayout; 1697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return ((layoutDir == LAYOUT_START) == mShouldReverseLayout) == isLayoutRTL(); 1699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 1700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 1701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 17022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Finds the span for the next view. 17032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 17042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span getNextSpan(LayoutState layoutState) { 1705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final boolean preferLastSpan = preferLastSpan(layoutState.mLayoutDirection); 1706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int startIndex, endIndex, diff; 1707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (preferLastSpan) { 1708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar startIndex = mSpanCount - 1; 1709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endIndex = -1; 1710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar diff = -1; 1711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 1712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar startIndex = 0; 1713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endIndex = mSpanCount; 1714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar diff = 1; 1715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 17162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (layoutState.mLayoutDirection == LAYOUT_END) { 1717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Span min = null; 1718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int minLine = Integer.MAX_VALUE; 17192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getStartAfterPadding(); 1720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = startIndex; i != endIndex; i += diff) { 17212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span other = mSpans[i]; 1722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int otherLine = other.getEndLine(defaultLine); 1723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (otherLine < minLine) { 17242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar min = other; 17252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar minLine = otherLine; 17262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return min; 17292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 1730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Span max = null; 1731d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int maxLine = Integer.MIN_VALUE; 17322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int defaultLine = mPrimaryOrientation.getEndAfterPadding(); 1733d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = startIndex; i != endIndex; i += diff) { 17342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final Span other = mSpans[i]; 1735d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int otherLine = other.getStartLine(defaultLine); 1736d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (otherLine > maxLine) { 17372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar max = other; 17382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar maxLine = otherLine; 17392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return max; 17422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean canScrollVertically() { 17472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation == VERTICAL; 17482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean canScrollHorizontally() { 17522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation == HORIZONTAL; 17532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, 17572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 17582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return scrollBy(dx, recycler, state); 17592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, 17632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar RecyclerView.State state) { 17642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return scrollBy(dy, recycler, state); 17652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int calculateScrollDirectionForPosition(int position) { 17682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (getChildCount() == 0) { 17692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START; 17702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int firstChildPos = getFirstChildPosition(); 17722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; 17732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, 17772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int position) { 17782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) { 17792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public PointF computeScrollVectorForPosition(int targetPosition) { 17812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int direction = calculateScrollDirectionForPosition(targetPosition); 17822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (direction == 0) { 17832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return null; 17842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mOrientation == HORIZONTAL) { 17862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new PointF(direction, 0); 17872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 17882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new PointF(0, direction); 17892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar }; 17922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar scroller.setTargetPosition(position); 17932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar startSmoothScroll(scroller); 17942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 17952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 17962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 17972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void scrollToPosition(int position) { 17982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) { 17992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateAnchorPositionInfo(); 18002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = position; 18022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = INVALID_OFFSET; 18032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 18042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 18072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Scroll to the specified adapter position with the given offset from layout start. 18082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 18092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Note that scroll position change will not be reflected until the next layout call. 18102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p> 18112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}. 18122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 18132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param position Index (starting at 0) of the reference item. 18142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param offset The distance (in pixels) between the start edge of the item view and 18152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * start edge of the RecyclerView. 18162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #setReverseLayout(boolean) 18172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @see #scrollToPosition(int) 18182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 18192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void scrollToPositionWithOffset(int position, int offset) { 18202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPendingSavedState != null) { 18212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingSavedState.invalidateAnchorPositionInfo(); 18222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPosition = position; 18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPendingScrollPositionOffset = offset; 18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar requestLayout(); 18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1828d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) { 18292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureOrientationHelper(); 18302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int referenceChildPosition; 18312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (dt > 0) { // layout towards end 18322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_END; 18332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD 18342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_TAIL; 18352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar referenceChildPosition = getLastChildPosition(); 18362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 18372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mLayoutDirection = LAYOUT_START; 18382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL 18392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar : ITEM_DIRECTION_HEAD; 18402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar referenceChildPosition = getFirstChildPosition(); 18412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection; 18432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int absDt = Math.abs(dt); 18442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mAvailable = absDt; 18452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLayoutState.mExtra = isSmoothScrolling() ? mPrimaryOrientation.getTotalSpace() : 0; 18462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int consumed = fill(recycler, mLayoutState, state); 18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int totalScroll; 18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (absDt < consumed) { 18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = dt; 18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (dt < 0) { 18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = -consumed; 18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { // dt > 0 18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar totalScroll = consumed; 18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (DEBUG) { 18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Log.d(TAG, "asked " + dt + " scrolled" + totalScroll); 18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1859d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPrimaryOrientation.offsetChildren(-totalScroll); 18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // always reset this if we scroll for a proper save instance state 18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mLastLayoutFromEnd = mShouldReverseLayout; 18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return totalScroll; 18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getLastChildPosition() { 18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1)); 18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private int getFirstChildPosition() { 18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int childCount = getChildCount(); 18722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return childCount == 0 ? 0 : getPosition(getChildAt(0)); 18732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 1875719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar /** 1876719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * Finds the first View that can be used as an anchor View. 1877719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * 1878719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * @return Position of the View or 0 if it cannot find any such View. 1879719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar */ 1880719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar private int findFirstReferenceChildPosition(int itemCount) { 1881719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int limit = getChildCount(); 1882719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar for (int i = 0; i < limit; i++) { 1883719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final View view = getChildAt(i); 1884719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int position = getPosition(view); 1885719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar if (position >= 0 && position < itemCount) { 1886719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return position; 1887719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1888719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1889719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return 0; 1890719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1891719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar 1892719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar /** 1893719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * Finds the last View that can be used as an anchor View. 1894719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * 1895719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar * @return Position of the View or 0 if it cannot find any such View. 1896719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar */ 1897719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar private int findLastReferenceChildPosition(int itemCount) { 1898719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar for (int i = getChildCount() - 1; i >= 0; i--) { 1899719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final View view = getChildAt(i); 1900719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar final int position = getPosition(view); 1901719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar if (position >= 0 && position < itemCount) { 1902719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return position; 1903719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1904719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1905719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar return 0; 1906719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar } 1907719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar 19082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 19092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateDefaultLayoutParams() { 19102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 19112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 19122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 19152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { 19162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(c, attrs); 19172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 19202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 19212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (lp instanceof ViewGroup.MarginLayoutParams) { 19222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams((ViewGroup.MarginLayoutParams) lp); 19232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 19242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new LayoutParams(lp); 19252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 19292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { 19302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return lp instanceof LayoutParams; 19312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getOrientation() { 19342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mOrientation; 19352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 19392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * LayoutParams used by StaggeredGridLayoutManager. 194042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * <p> 194142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the 194242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is 194342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * expected to fill all of the space given to it. 19442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 19452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static class LayoutParams extends RecyclerView.LayoutParams { 19462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 19482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Span Id for Views that are not laid out yet. 19492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 19502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final int INVALID_SPAN_ID = -1; 19512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Package scope to be able to access from tests. 19532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Span mSpan; 19542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mFullSpan; 19562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(Context c, AttributeSet attrs) { 19582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(c, attrs); 19592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(int width, int height) { 19622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(width, height); 19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(ViewGroup.MarginLayoutParams source) { 19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(ViewGroup.LayoutParams source) { 19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 19712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public LayoutParams(RecyclerView.LayoutParams source) { 19742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar super(source); 19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * When set to true, the item will layout using all span area. That means, if orientation 19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * is vertical, the view will have full width; if orientation is horizontal, the view will 19802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * have full height. 19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param fullSpan True if this item should traverse all spans. 19837499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * @see #isFullSpan() 19842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 19852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void setFullSpan(boolean fullSpan) { 19862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mFullSpan = fullSpan; 19872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 19882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 19892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 19907499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * Returns whether this View occupies all available spans or just one. 19917499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * 19927499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * @return True if the View occupies all spans or false otherwise. 19937499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar * @see #setFullSpan(boolean) 19947499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar */ 19957499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar public boolean isFullSpan() { 19967499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar return mFullSpan; 19977499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar } 19987499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar 19997499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar /** 20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns the Span index to which this View is assigned. 20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 20022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return The Span index of the View. If View is not yet assigned to any span, returns 20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * {@link #INVALID_SPAN_ID}. 20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public final int getSpanIndex() { 20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpan == null) { 20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return INVALID_SPAN_ID; 20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mSpan.mIndex; 20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Package scoped to access from tests. 20142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar class Span { 20152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20166b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar static final int INVALID_LINE = Integer.MIN_VALUE; 20172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private ArrayList<View> mViews = new ArrayList<View>(); 20182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mCachedStart = INVALID_LINE; 20192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mCachedEnd = INVALID_LINE; 20202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mDeletedSize = 0; 20212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int mIndex; 20222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private Span(int index) { 20242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mIndex = index; 20252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getStartLine(int def) { 20282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 20292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 20302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return def; 20332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2034d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedStart(); 20352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void calculateCachedStart() { 2039d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View startView = mViews.get(0); 2040d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LayoutParams lp = getLayoutParams(startView); 2041d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedStart = mPrimaryOrientation.getDecoratedStart(startView); 2042d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 2043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = mLazySpanLookup 2044115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar .getFullSpanItem(lp.getViewLayoutPosition()); 2045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi != null && fsi.mGapDir == LAYOUT_START) { 2046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedStart -= fsi.getGapForSpan(mIndex); 2047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2048d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2049d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2050d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use this one when default value does not make sense and not having a value means a bug. 20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getStartLine() { 20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2056d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedStart(); 20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedStart; 20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getEndLine(int def) { 20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int size = mViews.size(); 20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (size == 0) { 20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return def; 20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2068d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedEnd(); 20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 20702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2072d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void calculateCachedEnd() { 2073d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final View endView = mViews.get(mViews.size() - 1); 2074d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final LayoutParams lp = getLayoutParams(endView); 2075d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedEnd = mPrimaryOrientation.getDecoratedEnd(endView); 2076d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lp.mFullSpan) { 2077d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem fsi = mLazySpanLookup 2078115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar .getFullSpanItem(lp.getViewLayoutPosition()); 2079d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi != null && fsi.mGapDir == LAYOUT_END) { 2080d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mCachedEnd += fsi.getGapForSpan(mIndex); 2081d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2082d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2083d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2084d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 20852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Use this one when default value does not make sense and not having a value means a bug. 20862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getEndLine() { 20872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 20882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 20892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2090d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar calculateCachedEnd(); 20912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mCachedEnd; 20922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 20932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 20942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void prependToSpan(View view) { 20952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = getLayoutParams(view); 20962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = this; 20972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.add(0, view); 20982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 20992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 1) { 21002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 21012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 21032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); 21042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void appendToSpan(View view) { 21082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams lp = getLayoutParams(view); 21092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = this; 21102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.add(view); 21112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 21122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 1) { 21132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 21142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 21162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); 21172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // Useful method to preserve positions on a re-layout. 21212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void cacheReferenceLineAndClear(boolean reverseLayout, int offset) { 21222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int reference; 21232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (reverseLayout) { 21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference = getEndLine(INVALID_LINE); 21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 21262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference = getStartLine(INVALID_LINE); 21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar clear(); 21292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (reference == INVALID_LINE) { 21302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return; 21312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2132d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding()) || 213342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding())) { 2134d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 21362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (offset != INVALID_OFFSET) { 21372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar reference += offset; 21382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = mCachedEnd = reference; 21402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void clear() { 21432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mViews.clear(); 21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar invalidateCache(); 21452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize = 0; 21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateCache() { 21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 21512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void setLine(int line) { 21542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = mCachedStart = line; 21552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void popEnd() { 21582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int size = mViews.size(); 21592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View end = mViews.remove(size - 1); 21602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final LayoutParams lp = getLayoutParams(end); 21612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = null; 21627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 21632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end); 21642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (size == 1) { 21662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 21672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 21692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void popStart() { 21722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar View start = mViews.remove(0); 21732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final LayoutParams lp = getLayoutParams(start); 21742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar lp.mSpan = null; 21752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 21762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd = INVALID_LINE; 21772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen if (lp.isItemRemoved() || lp.isItemChanged()) { 21792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start); 21802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart = INVALID_LINE; 21822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int getDeletedSize() { 21852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mDeletedSize; 21862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams getLayoutParams(View view) { 21892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return (LayoutParams) view.getLayoutParams(); 21902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 21922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void onOffset(int dt) { 21932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedStart != INVALID_LINE) { 21942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedStart += dt; 21952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mCachedEnd != INVALID_LINE) { 21972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mCachedEnd += dt; 21982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 21992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar // normalized offset is how much this span can scroll 22022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getNormalizedOffset(int dt, int targetStart, int targetEnd) { 22032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mViews.size() == 0) { 22042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 22052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (dt < 0) { 22072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int endSpace = getEndLine() - targetEnd; 22082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (endSpace <= 0) { 22092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 22102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return -dt > endSpace ? -endSpace : dt; 22122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 22132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int startSpace = targetStart - getStartLine(); 22142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (startSpace <= 0) { 22152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 22162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return startSpace < dt ? startSpace : dt; 22182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 22222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Returns if there is no child between start-end lines 22232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * 22242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param start The start line 22252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @param end The end line 22262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * @return true if a new child can be added between start and end 22272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 22282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean isEmpty(int start, int end) { 22292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final int count = mViews.size(); 22302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar for (int i = 0; i < count; i++) { 22312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar final View view = mViews.get(i); 22322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mPrimaryOrientation.getDecoratedStart(view) < end && 22332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mPrimaryOrientation.getDecoratedEnd(view) > start) { 22342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return false; 22352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return true; 22382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2239333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2240333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findFirstVisibleItemPosition() { 2241333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 224242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ? findOneVisibleChild(mViews.size() - 1, -1, false) 2243333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(0, mViews.size(), false); 2244333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2245333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2246333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findFirstCompletelyVisibleItemPosition() { 2247333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 224842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar ? findOneVisibleChild(mViews.size() - 1, -1, true) 2249333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar : findOneVisibleChild(0, mViews.size(), true); 2250333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2251333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2252333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findLastVisibleItemPosition() { 2253333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 2254333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(0, mViews.size(), false) 225542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar : findOneVisibleChild(mViews.size() - 1, -1, false); 2256333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2257333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2258333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar public int findLastCompletelyVisibleItemPosition() { 2259333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return mReverseLayout 2260333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar ? findOneVisibleChild(0, mViews.size(), true) 226142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar : findOneVisibleChild(mViews.size() - 1, -1, true); 2262333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2263333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar 2264333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) { 2265333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int start = mPrimaryOrientation.getStartAfterPadding(); 2266333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int end = mPrimaryOrientation.getEndAfterPadding(); 2267333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int next = toIndex > fromIndex ? 1 : -1; 2268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = fromIndex; i != toIndex; i += next) { 2269333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final View child = mViews.get(i); 2270333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int childStart = mPrimaryOrientation.getDecoratedStart(child); 2271333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); 2272333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (childStart < end && childEnd > start) { 2273333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (completelyVisible) { 2274333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar if (childStart >= start && childEnd <= end) { 2275333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 2276333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2277333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } else { 2278333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar return getPosition(child); 2279333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2280333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2281333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 2282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return NO_POSITION; 2283333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar } 22842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 22852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar /** 22872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * An array of mappings from adapter position to span. 22882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * This only grows when a write happens and it grows up to the size of the adapter. 22892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */ 22902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar static class LazySpanLookup { 22912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 22922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar private static final int MIN_SIZE = 10; 22932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mData; 2294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar List<FullSpanItem> mFullSpanItems; 2295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Invalidates everything after this position, including full span information 2299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int forceInvalidateAfter(int position) { 2301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems != null) { 2302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= position) { 2305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(i); 2306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return invalidateAfter(position); 2310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 23112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 2312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * returns end position for invalidation. 2314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int invalidateAfter(int position) { 23162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null) { 2317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 23182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (position >= mData.length) { 2320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 2321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int endPosition = invalidateFullSpansAfter(position); 2323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (endPosition == RecyclerView.NO_POSITION) { 2324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID); 2325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return mData.length; 2326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // just invalidate items in between 2328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar Arrays.fill(mData, position, endPosition + 1, LayoutParams.INVALID_SPAN_ID); 2329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return endPosition + 1; 23302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int getSpan(int position) { 23342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null || position >= mData.length) { 23352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return LayoutParams.INVALID_SPAN_ID; 23362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else { 23372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return mData[position]; 23382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void setSpan(int position, Span span) { 23422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(position); 23432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData[position] = span.mIndex; 23442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int sizeForPosition(int position) { 23472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int len = mData.length; 23482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar while (len <= position) { 23492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar len *= 2; 23502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return len; 23522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void ensureSize(int position) { 23552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData == null) { 23562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData = new int[Math.max(position, MIN_SIZE) + 1]; 23572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); 23582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } else if (position >= mData.length) { 23592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] old = mData; 23602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData = new int[sizeForPosition(position)]; 23612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(old, 0, mData, 0, old.length); 23622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID); 23632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void clear() { 23672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mData != null) { 23682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); 23692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = null; 23712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 23722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 23732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void offsetForRemoval(int positionStart, int itemCount) { 2374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mData == null || positionStart >= mData.length) { 2375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 23772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(positionStart + itemCount); 23782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(mData, positionStart + itemCount, mData, positionStart, 23792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData.length - positionStart - itemCount); 23802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, mData.length - itemCount, mData.length, 23812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams.INVALID_SPAN_ID); 2382d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar offsetFullSpansForRemoval(positionStart, itemCount); 2383d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2384d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void offsetFullSpansForRemoval(int positionStart, int itemCount) { 2386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2388d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int end = positionStart + itemCount; 2390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2392d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition < positionStart) { 2393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; 2394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2395d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition < end) { 2396d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(i); 2397d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2398d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mPosition -= itemCount; 2399d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2400d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 24012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 24022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 24032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void offsetForAddition(int positionStart, int itemCount) { 2404d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mData == null || positionStart >= mData.length) { 2405d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 24072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar ensureSize(positionStart + itemCount); 24082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar System.arraycopy(mData, positionStart, mData, positionStart + itemCount, 24092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mData.length - positionStart - itemCount); 24102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar Arrays.fill(mData, positionStart, positionStart + itemCount, 24112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar LayoutParams.INVALID_SPAN_ID); 2412d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar offsetFullSpansForAddition(positionStart, itemCount); 2413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2415d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private void offsetFullSpansForAddition(int positionStart, int itemCount) { 2416d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2417d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2418d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2419d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2420d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition < positionStart) { 2422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar continue; 2423d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar fsi.mPosition += itemCount; 2425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Returns when invalidation should end. e.g. hitting a full span position. 2430d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Returned position SHOULD BE invalidated. 2431d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2432d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private int invalidateFullSpansAfter(int position) { 2433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2434d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 2435d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2436d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final FullSpanItem item = getFullSpanItem(position); 2437d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // if there is an fsi at this position, get rid of it. 2438d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (item != null) { 2439d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(item); 2440d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2441d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int nextFsiIndex = -1; 2442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int count = mFullSpanItems.size(); 2443d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < count; i++) { 2444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= position) { 2446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar nextFsiIndex = i; 2447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar break; 2448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2449d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2450d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (nextFsiIndex != -1) { 2451d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(nextFsiIndex); 2452d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(nextFsiIndex); 2453d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi.mPosition; 2454d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return RecyclerView.NO_POSITION; 2456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void addFullSpanItem(FullSpanItem fullSpanItem) { 2459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2460d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = new ArrayList<FullSpanItem>(); 2461d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2462d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int size = mFullSpanItems.size(); 2463d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = 0; i < size; i++) { 2464d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem other = mFullSpanItems.get(i); 2465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (other.mPosition == fullSpanItem.mPosition) { 2466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (DEBUG) { 2467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar throw new IllegalStateException("two fsis for same position"); 2468d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2469d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.remove(i); 2470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (other.mPosition >= fullSpanItem.mPosition) { 2473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.add(i, fullSpanItem); 2474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return; 2475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // if it is not added to a position. 2478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems.add(fullSpanItem); 2479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem getFullSpanItem(int position) { 2482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2485d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { 2486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final FullSpanItem fsi = mFullSpanItems.get(i); 2487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition == position) { 2488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 2489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param minPos inclusive 2496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param maxPos exclusive 2497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param gapDir if not 0, returns FSIs on in that direction 2498f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar * @param hasUnwantedGapAfter If true, when full span item has unwanted gaps, it will be 2499f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar * returned even if its gap direction does not match. 2500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2501f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar public FullSpanItem getFirstFullSpanItemInRange(int minPos, int maxPos, int gapDir, 2502f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar boolean hasUnwantedGapAfter) { 2503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mFullSpanItems == null) { 2504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2506f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar final int limit = mFullSpanItems.size(); 2507f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar for (int i = 0; i < limit; i++) { 2508d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar FullSpanItem fsi = mFullSpanItems.get(i); 2509d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (fsi.mPosition >= maxPos) { 2510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2511d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2512f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar if (fsi.mPosition >= minPos 2513f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar && (gapDir == 0 || fsi.mGapDir == gapDir || 2514f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar (hasUnwantedGapAfter && fsi.mHasUnwantedGapAfter))) { 2515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return fsi; 2516d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2517d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2518d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return null; 2519d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2520d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2521d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2522d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * We keep information about full span items because they may create gaps in the UI. 2523d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2524d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static class FullSpanItem implements Parcelable { 2525d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2526d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mPosition; 2527d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mGapDir; 2528d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int[] mGapPerSpan; 2529f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar // A full span may be laid out in primary direction but may have gaps due to 2530f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar // invalidation of views after it. This is recorded during a reverse scroll and if 2531f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar // view is still on the screen after scroll stops, we have to recalculate layout 2532f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar boolean mHasUnwantedGapAfter; 2533d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem(Parcel in) { 2535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPosition = in.readInt(); 2536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mGapDir = in.readInt(); 2537f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar mHasUnwantedGapAfter = in.readInt() == 1; 2538d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int spanCount = in.readInt(); 2539d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (spanCount > 0) { 2540d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mGapPerSpan = new int[spanCount]; 2541d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar in.readIntArray(mGapPerSpan); 2542d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2543d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2544d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2545d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem() { 2546d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2547d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int getGapForSpan(int spanIndex) { 2549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex]; 2550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2551d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void invalidateSpanGaps() { 2553d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mGapPerSpan = null; 2554d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2555d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2556d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public int describeContents() { 2558d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 2559d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2560d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2561d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public void writeToParcel(Parcel dest, int flags) { 2563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mPosition); 2564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mGapDir); 2565f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar dest.writeInt(mHasUnwantedGapAfter ? 1 : 0); 2566d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mGapPerSpan != null && mGapPerSpan.length > 0) { 2567d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mGapPerSpan.length); 2568d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeIntArray(mGapPerSpan); 2569d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2570d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(0); 2571d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2572d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2573d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2574d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2575d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public String toString() { 2576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return "FullSpanItem{" + 2577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar "mPosition=" + mPosition + 2578d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ", mGapDir=" + mGapDir + 2579f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar ", mHasUnwantedGapAfter=" + mHasUnwantedGapAfter + 2580d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ", mGapPerSpan=" + Arrays.toString(mGapPerSpan) + 2581d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar '}'; 2582d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public static final Parcelable.Creator<FullSpanItem> CREATOR 2585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar = new Parcelable.Creator<FullSpanItem>() { 2586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem createFromParcel(Parcel in) { 2588d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return new FullSpanItem(in); 2589d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2590d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2591d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar @Override 2592d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar public FullSpanItem[] newArray(int size) { 2593d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return new FullSpanItem[size]; 2594d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2595d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar }; 25962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 25982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 25992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar static class SavedState implements Parcelable { 26002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mAnchorPosition; 2602d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated 2603b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar int mSpanOffsetsSize; 26042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mSpanOffsets; 26052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int mSpanLookupSize; 26062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar int[] mSpanLookup; 2607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar List<LazySpanLookup.FullSpanItem> mFullSpanItems; 26082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mReverseLayout; 26092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar boolean mAnchorLayoutFromEnd; 2610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mLastLayoutRTL; 26112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState() { 26132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar SavedState(Parcel in) { 26162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = in.readInt(); 2617333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = in.readInt(); 2618b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = in.readInt(); 2619b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar if (mSpanOffsetsSize > 0) { 2620b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsets = new int[mSpanOffsetsSize]; 26212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar in.readIntArray(mSpanOffsets); 26222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = in.readInt(); 26252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpanLookupSize > 0) { 26262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = new int[mSpanLookupSize]; 26272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar in.readIntArray(mSpanLookup); 26282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = in.readInt() == 1; 26302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorLayoutFromEnd = in.readInt() == 1; 2631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = in.readInt() == 1; 2632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = in.readArrayList( 2633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar LazySpanLookup.FullSpanItem.class.getClassLoader()); 26342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState(SavedState other) { 2637b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = other.mSpanOffsetsSize; 26382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorPosition = other.mAnchorPosition; 2639333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar mVisibleAnchorPosition = other.mVisibleAnchorPosition; 26402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = other.mSpanOffsets; 26412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = other.mSpanLookupSize; 26422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = other.mSpanLookup; 26432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mReverseLayout = other.mReverseLayout; 26442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd; 2645d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLastLayoutRTL = other.mLastLayoutRTL; 2646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = other.mFullSpanItems; 26472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateSpanInfo() { 26502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = null; 2651b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = 0; 26522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookupSize = 0; 26532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanLookup = null; 2654d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mFullSpanItems = null; 26552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar void invalidateAnchorPositionInfo() { 26582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar mSpanOffsets = null; 2659b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar mSpanOffsetsSize = 0; 2660d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mAnchorPosition = NO_POSITION; 2661d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mVisibleAnchorPosition = NO_POSITION; 26622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 26652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public int describeContents() { 26662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return 0; 26672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 26702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public void writeToParcel(Parcel dest, int flags) { 26712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mAnchorPosition); 2672333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar dest.writeInt(mVisibleAnchorPosition); 2673b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar dest.writeInt(mSpanOffsetsSize); 2674b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar if (mSpanOffsetsSize > 0) { 26752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeIntArray(mSpanOffsets); 26762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mSpanLookupSize); 26782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar if (mSpanLookupSize > 0) { 26792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeIntArray(mSpanLookup); 26802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mReverseLayout ? 1 : 0); 26822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0); 2683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeInt(mLastLayoutRTL ? 1 : 0); 2684d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar dest.writeList(mFullSpanItems); 26852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public static final Parcelable.Creator<SavedState> CREATOR 26882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar = new Parcelable.Creator<SavedState>() { 26892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 26902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState createFromParcel(Parcel in) { 26912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState(in); 26922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar 26942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar @Override 26952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar public SavedState[] newArray(int size) { 26962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar return new SavedState[size]; 26972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 26982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar }; 26992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar } 2700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 2702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Data class to hold the information about an anchor position which is used in onLayout call. 2703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 2704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar private class AnchorInfo { 2705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mPosition; 2707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar int mOffset; 2708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mLayoutFromEnd; 2709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean mInvalidateOffsets; 2710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void reset() { 2712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mPosition = NO_POSITION; 2713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = INVALID_OFFSET; 2714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mLayoutFromEnd = false; 2715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mInvalidateOffsets = false; 2716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void assignCoordinateFromPadding() { 2719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = mLayoutFromEnd ? mPrimaryOrientation.getEndAfterPadding() 2720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar : mPrimaryOrientation.getStartAfterPadding(); 2721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 2723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar void assignCoordinateFromPadding(int addedDistance) { 2724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (mLayoutFromEnd) { 2725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = mPrimaryOrientation.getEndAfterPadding() - addedDistance; 2726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } else { 2727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar mOffset = mPrimaryOrientation.getStartAfterPadding() + addedDistance; 2728d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2729d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 2730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 27312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar} 2732