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