GridLayoutManager.java revision 0194ed84ad6f1d3d489db52b9431fa93a7697b50
1b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar/* 2b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 3b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 4b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * you may not use this file except in compliance with the License. 6b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * You may obtain a copy of the License at 7b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 8b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 10b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * See the License for the specific languag`e governing permissions and 14b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * limitations under the License. 15b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 16b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarpackage android.support.v7.widget; 17b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 18b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport android.content.Context; 19b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport android.graphics.Rect; 20a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 21b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport android.util.AttributeSet; 22b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport android.util.Log; 239ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyarimport android.util.SparseIntArray; 24b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport android.view.View; 25b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport android.view.ViewGroup; 26b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 27b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarimport java.util.Arrays; 28b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 29b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar/** 30b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * A {@link RecyclerView.LayoutManager} implementations that lays out items in a grid. 31b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 32b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * By default, each item occupies 1 span. You can change it by providing a custom 33b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * {@link SpanSizeLookup} instance via {@link #setSpanSizeLookup(SpanSizeLookup)}. 34b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 35b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyarpublic class GridLayoutManager extends LinearLayoutManager { 36b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 37b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private static final boolean DEBUG = false; 38b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private static final String TAG = "GridLayoutManager"; 39b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public static final int DEFAULT_SPAN_COUNT = -1; 40061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar /** 41061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * The measure spec for the scroll direction. 42061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar */ 43061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar static final int MAIN_DIR_SPEC = 44061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 45204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar /** 46204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar * Span size have been changed but we've not done a new layout calculation. 47204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar */ 48204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar boolean mPendingSpanCountChange = false; 49b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int mSpanCount = DEFAULT_SPAN_COUNT; 50b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 517e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko * Right borders for each span. 527e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko * <p>For <b>i-th</b> item start is {@link #mCachedBorders}[i-1] + 1 537e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko * and end is {@link #mCachedBorders}[i]. 54b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 557e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int [] mCachedBorders; 56b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 57b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Temporary array to keep views in layoutChunk method 58b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 59b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar View[] mSet; 609ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar final SparseIntArray mPreLayoutSpanSizeCache = new SparseIntArray(); 61061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final SparseIntArray mPreLayoutSpanIndexCache = new SparseIntArray(); 62b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar SpanSizeLookup mSpanSizeLookup = new DefaultSpanSizeLookup(); 635e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar // re-used variable to acquire decor insets from RecyclerView 645e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar final Rect mDecorInsets = new Rect(); 655e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar 660194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta 670194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta /** 680194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta * Constructor used when layout manager is set in XML by RecyclerView attribute 690194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta * "layoutManager". If spanCount is not specified in the XML, it defaults to a 700194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta * single column. 710194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta * 720194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount 730194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta */ 740194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta public GridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, 750194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta int defStyleRes) { 760194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta super(context, attrs, defStyleAttr, defStyleRes); 770194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes); 780194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta setSpanCount(properties.spanCount); 790194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta } 800194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta 815f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar /** 825f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * Creates a vertical GridLayoutManager 835f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * 845f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * @param context Current context, will be used to access resources. 855f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * @param spanCount The number of columns in the grid 865f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar */ 87b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public GridLayoutManager(Context context, int spanCount) { 88b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(context); 89b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar setSpanCount(spanCount); 90b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 91b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 925f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar /** 935f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * @param context Current context, will be used to access resources. 945f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * @param spanCount The number of columns or rows in the grid 955f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link 965f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * #VERTICAL}. 975f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * @param reverseLayout When set to true, layouts from end to start. 985f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar */ 99b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public GridLayoutManager(Context context, int spanCount, int orientation, 100b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar boolean reverseLayout) { 101b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(context, orientation, reverseLayout); 102b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar setSpanCount(spanCount); 103b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 104b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 1055f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar /** 1065f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * stackFromEnd is not supported by GridLayoutManager. Consider using 1075f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar * {@link #setReverseLayout(boolean)}. 1085f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar */ 109b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 110061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void setStackFromEnd(boolean stackFromEnd) { 1115f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar if (stackFromEnd) { 1125f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar throw new UnsupportedOperationException( 1135f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar "GridLayoutManager does not support stack from end." 1145f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar + " Consider using reverse layout"); 1155f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar } 1165f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar super.setStackFromEnd(false); 117061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 118061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 119061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 120a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getRowCountForAccessibility(RecyclerView.Recycler recycler, 121a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 122a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == HORIZONTAL) { 123a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanCount; 124a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 125a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (state.getItemCount() < 1) { 126a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 0; 127a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 128a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return getSpanGroupIndex(recycler, state, state.getItemCount() - 1); 129a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 130a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 131a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 132a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getColumnCountForAccessibility(RecyclerView.Recycler recycler, 133a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state) { 134a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == VERTICAL) { 135a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanCount; 136a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 137a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (state.getItemCount() < 1) { 138a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 0; 139a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 140a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return getSpanGroupIndex(recycler, state, state.getItemCount() - 1); 141a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 142a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 143a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 144a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler, 145a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) { 146a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar ViewGroup.LayoutParams lp = host.getLayoutParams(); 147a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (!(lp instanceof LayoutParams)) { 148a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar super.onInitializeAccessibilityNodeInfoForItem(host, info); 149a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return; 150a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 151a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar LayoutParams glp = (LayoutParams) lp; 152115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar int spanGroupIndex = getSpanGroupIndex(recycler, state, glp.getViewLayoutPosition()); 153a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (mOrientation == HORIZONTAL) { 154a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( 155a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar glp.getSpanIndex(), glp.getSpanSize(), 156a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar spanGroupIndex, 1, 157a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false)); 158a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else { // VERTICAL 159a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( 160a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar spanGroupIndex , 1, 161a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar glp.getSpanIndex(), glp.getSpanSize(), 162a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false)); 163a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 164a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 165a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 166a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar @Override 167b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 1689ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (state.isPreLayout()) { 169061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar cachePreLayoutSpanMapping(); 1709ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 171b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super.onLayoutChildren(recycler, state); 172b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (DEBUG) { 173b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar validateChildOrder(); 174b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 175061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar clearPreLayoutSpanMappingCache(); 176204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar if (!state.isPreLayout()) { 177204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mPendingSpanCountChange = false; 178204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar } 179061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 180061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 181061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private void clearPreLayoutSpanMappingCache() { 1829ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar mPreLayoutSpanSizeCache.clear(); 183061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mPreLayoutSpanIndexCache.clear(); 1849ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 1859ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar 186061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private void cachePreLayoutSpanMapping() { 1879ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar final int childCount = getChildCount(); 188061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < childCount; i++) { 1899ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); 190115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int viewPosition = lp.getViewLayoutPosition(); 191061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mPreLayoutSpanSizeCache.put(viewPosition, lp.getSpanSize()); 192061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mPreLayoutSpanIndexCache.put(viewPosition, lp.getSpanIndex()); 1939ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 194b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 195b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 196b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 197061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { 198061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanSizeLookup.invalidateSpanIndexCache(); 199061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 200061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 201061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 202061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onItemsChanged(RecyclerView recyclerView) { 203061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanSizeLookup.invalidateSpanIndexCache(); 204061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 205061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 206061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 207061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { 208061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanSizeLookup.invalidateSpanIndexCache(); 209061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 210061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 211061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 212061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) { 213061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanSizeLookup.invalidateSpanIndexCache(); 214061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 215061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 216061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 217061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { 218061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanSizeLookup.invalidateSpanIndexCache(); 219061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 220061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 221061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar @Override 222b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public RecyclerView.LayoutParams generateDefaultLayoutParams() { 223b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 224b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar ViewGroup.LayoutParams.WRAP_CONTENT); 225b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 226b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 227b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 228b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { 229b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return new LayoutParams(c, attrs); 230b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 231b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 232b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 233b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 234b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (lp instanceof ViewGroup.MarginLayoutParams) { 235b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return new LayoutParams((ViewGroup.MarginLayoutParams) lp); 236b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 237b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return new LayoutParams(lp); 238b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 239b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 240b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 241b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 242b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { 243b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return lp instanceof LayoutParams; 244b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 245b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 246b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 247b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Sets the source to get the number of spans occupied by each item in the adapter. 248b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 249b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @param spanSizeLookup {@link SpanSizeLookup} instance to be used to query number of spans 250061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * occupied by each item 251b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 252b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) { 253b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar mSpanSizeLookup = spanSizeLookup; 254b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 255b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 256b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 257b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Returns the current {@link SpanSizeLookup} used by the GridLayoutManager. 258b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 259b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @return The current {@link SpanSizeLookup} used by the GridLayoutManager. 260b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 261b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public SpanSizeLookup getSpanSizeLookup() { 262b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return mSpanSizeLookup; 263b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 264b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 265b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private void updateMeasurements() { 266b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int totalSpace; 267b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (getOrientation() == VERTICAL) { 268b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar totalSpace = getWidth() - getPaddingRight() - getPaddingLeft(); 269b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 270b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar totalSpace = getHeight() - getPaddingBottom() - getPaddingTop(); 271b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 2727e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko calculateItemBorders(totalSpace); 2737e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2747e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko 2757e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko private void calculateItemBorders(int totalSpace) { 2767e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko if (mCachedBorders == null || mCachedBorders.length != mSpanCount + 1 2777e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko || mCachedBorders[mCachedBorders.length - 1] != totalSpace) { 2787e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders = new int[mSpanCount + 1]; 2797e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2807e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders[0] = 0; 2817e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int sizePerSpan = totalSpace / mSpanCount; 2827e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int sizePerSpanRemainder = totalSpace % mSpanCount; 2837e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int consumedPixels = 0; 2847e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int additionalSize = 0; 2857e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko for (int i = 1; i <= mSpanCount; i++) { 2867e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko int itemSize = sizePerSpan; 2877e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko additionalSize += sizePerSpanRemainder; 2887e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko if (additionalSize > 0 && (mSpanCount - additionalSize) < sizePerSpanRemainder) { 2897e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko itemSize += 1; 2907e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko additionalSize -= mSpanCount; 2917e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 2927e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko consumedPixels += itemSize; 2937e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders[i] = consumedPixels; 2947e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko } 295b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 296b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 297b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 2989ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar void onAnchorReady(RecyclerView.State state, AnchorInfo anchorInfo) { 2999ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar super.onAnchorReady(state, anchorInfo); 300b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar updateMeasurements(); 301061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (state.getItemCount() > 0 && !state.isPreLayout()) { 3029ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar ensureAnchorIsInFirstSpan(anchorInfo); 3039ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 3049ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (mSet == null || mSet.length != mSpanCount) { 3059ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar mSet = new View[mSpanCount]; 3069ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 3079ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 3089ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar 3099ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar private void ensureAnchorIsInFirstSpan(AnchorInfo anchorInfo) { 310061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int span = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount); 31173304eff156157f62075215e795e774803a6f96aYigit Boyar while (span > 0 && anchorInfo.mPosition > 0) { 312061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar anchorInfo.mPosition--; 313061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar span = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount); 314061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 315061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 316061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 3171f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar @Override 3181f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View findReferenceChild(int start, int end, int itemCount) { 3191f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar ensureLayoutState(); 3201f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View invalidMatch = null; 3211f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar View outOfBoundsMatch = null; 3221f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int boundsStart = mOrientationHelper.getStartAfterPadding(); 3231f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int boundsEnd = mOrientationHelper.getEndAfterPadding(); 3241f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int diff = end > start ? 1 : -1; 3251f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar for (int i = start; i != end; i += diff) { 3261f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final View view = getChildAt(i); 3271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int position = getPosition(view); 3281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (position >= 0 && position < itemCount) { 3291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar final int span = mSpanSizeLookup.getCachedSpanIndex(position, mSpanCount); 3301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (span != 0) { 3311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar continue; 3321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3331f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) { 3341f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (invalidMatch == null) { 3351f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar invalidMatch = view; // removed item, least preferred 3361f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3371f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd || 3381f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar mOrientationHelper.getDecoratedEnd(view) < boundsStart) { 3391f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar if (outOfBoundsMatch == null) { 3401f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar outOfBoundsMatch = view; // item is not visible, less preferred 3411f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3421f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } else { 3431f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar return view; 3441f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3451f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3461f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3471f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch; 3481f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar } 3491f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar 350a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar private int getSpanGroupIndex(RecyclerView.Recycler recycler, RecyclerView.State state, 351a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar int viewPosition) { 352a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (!state.isPreLayout()) { 353a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanSizeLookup.getSpanGroupIndex(viewPosition, mSpanCount); 354a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 355a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(viewPosition); 356a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (adapterPosition == -1) { 357a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (DEBUG) { 358a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar throw new RuntimeException("Cannot find span group index for position " 359a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar + viewPosition); 360a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 361a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar Log.w(TAG, "Cannot find span size for pre layout position. " + viewPosition); 362a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return 0; 363a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 364a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return mSpanSizeLookup.getSpanGroupIndex(adapterPosition, mSpanCount); 365a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 366a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 367061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private int getSpanIndex(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) { 368061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!state.isPreLayout()) { 369061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return mSpanSizeLookup.getCachedSpanIndex(pos, mSpanCount); 370061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 371061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int cached = mPreLayoutSpanIndexCache.get(pos, -1); 372061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (cached != -1) { 373061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return cached; 374061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 375061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos); 376061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (adapterPosition == -1) { 377061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (DEBUG) { 378061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar throw new RuntimeException("Cannot find span index for pre layout position. It is" 379061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar + " not cached, not in the adapter. Pos:" + pos); 380061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 381061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar Log.w(TAG, "Cannot find span size for pre layout position. It is" 382061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar + " not cached, not in the adapter. Pos:" + pos); 383061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return 0; 384b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 385061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return mSpanSizeLookup.getCachedSpanIndex(adapterPosition, mSpanCount); 3869ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 3879ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar 3889ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar private int getSpanSize(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) { 3899ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (!state.isPreLayout()) { 3909ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar return mSpanSizeLookup.getSpanSize(pos); 391b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 3929ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar final int cached = mPreLayoutSpanSizeCache.get(pos, -1); 3939ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (cached != -1) { 3949ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar return cached; 3959ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 3969ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos); 3979ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (adapterPosition == -1) { 3989ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (DEBUG) { 3999ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar throw new RuntimeException("Cannot find span size for pre layout position. It is" 4009ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar + " not cached, not in the adapter. Pos:" + pos); 4019ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 4029ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar Log.w(TAG, "Cannot find span size for pre layout position. It is" 4039ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar + " not cached, not in the adapter. Pos:" + pos); 4049ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar return 1; 4059ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 4069ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar return mSpanSizeLookup.getSpanSize(adapterPosition); 407b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 408b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 409b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 410b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, 411b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar LayoutState layoutState, LayoutChunkResult result) { 412061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final boolean layingOutInPrimaryDirection = 413061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL; 414b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int count = 0; 415061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int consumedSpanCount = 0; 416b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int remainingSpan = mSpanCount; 417061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!layingOutInPrimaryDirection) { 418061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int itemSpanIndex = getSpanIndex(recycler, state, layoutState.mCurrentPosition); 419061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int itemSpanSize = getSpanSize(recycler, state, layoutState.mCurrentPosition); 420061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar remainingSpan = itemSpanIndex + itemSpanSize; 421061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 422b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) { 423b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int pos = layoutState.mCurrentPosition; 4249ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar final int spanSize = getSpanSize(recycler, state, pos); 42573304eff156157f62075215e795e774803a6f96aYigit Boyar if (spanSize > mSpanCount) { 42673304eff156157f62075215e795e774803a6f96aYigit Boyar throw new IllegalArgumentException("Item at position " + pos + " requires " + 42773304eff156157f62075215e795e774803a6f96aYigit Boyar spanSize + " spans but GridLayoutManager has only " + mSpanCount 42873304eff156157f62075215e795e774803a6f96aYigit Boyar + " spans."); 42973304eff156157f62075215e795e774803a6f96aYigit Boyar } 430b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar remainingSpan -= spanSize; 431b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (remainingSpan < 0) { 432b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar break; // item did not fit into this row or column 433b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 434b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar View view = layoutState.next(recycler); 435b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (view == null) { 436b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar break; 437b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 438061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar consumedSpanCount += spanSize; 439b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar mSet[count] = view; 440061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar count++; 441b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 442b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 443b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (count == 0) { 444b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar result.mFinished = true; 445b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return; 446b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 447b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 448b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int maxSize = 0; 449061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 4505e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar // we should assign spans before item decor offsets are calculated 451061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection); 452061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < count; i++) { 453b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar View view = mSet[i]; 4549ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (layoutState.mScrapList == null) { 4559ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (layingOutInPrimaryDirection) { 4569ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar addView(view); 4579ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } else { 4589ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar addView(view, 0); 4599ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 460b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 4619ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar if (layingOutInPrimaryDirection) { 4629ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar addDisappearingView(view); 4639ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } else { 4649ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar addDisappearingView(view, 0); 4659ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar } 466b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 4679ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar 468061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final LayoutParams lp = (LayoutParams) view.getLayoutParams(); 4697e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int spec = View.MeasureSpec.makeMeasureSpec( 4707e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - 4717e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders[lp.mSpanIndex], 4727e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko View.MeasureSpec.EXACTLY); 473b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (mOrientation == VERTICAL) { 474061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar measureChildWithDecorationsAndMargin(view, spec, getMainDirSpec(lp.height)); 475b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 476061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar measureChildWithDecorationsAndMargin(view, getMainDirSpec(lp.width), spec); 477b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 478b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar final int size = mOrientationHelper.getDecoratedMeasurement(view); 479b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (size > maxSize) { 480b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar maxSize = size; 481b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 482b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 483afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 484afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar // views that did not measure the maxSize has to be re-measured 485afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final int maxMeasureSpec = getMainDirSpec(maxSize); 486afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar for (int i = 0; i < count; i ++) { 487afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar final View view = mSet[i]; 488afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) { 4897e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final LayoutParams lp = (LayoutParams) view.getLayoutParams(); 4907e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko final int spec = View.MeasureSpec.makeMeasureSpec( 4917e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - 4927e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko mCachedBorders[lp.mSpanIndex], 493afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar View.MeasureSpec.EXACTLY); 494afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar if (mOrientation == VERTICAL) { 495afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec); 496afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } else { 497afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar measureChildWithDecorationsAndMargin(view, maxMeasureSpec, spec); 498afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 499afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 500afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar } 501afa0494a97687b705feb3659385578f33f697ea9Yigit Boyar 502b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar result.mConsumed = maxSize; 503b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 5045e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar int left = 0, right = 0, top = 0, bottom = 0; 505b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (mOrientation == VERTICAL) { 506b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { 507b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar bottom = layoutState.mOffset; 508b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar top = bottom - maxSize; 509b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 510b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar top = layoutState.mOffset; 511b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar bottom = top + maxSize; 512b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 513b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 514b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { 515b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar right = layoutState.mOffset; 516b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar left = right - maxSize; 517b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 518b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar left = layoutState.mOffset; 519b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar right = left + maxSize; 520b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 521b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 522061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = 0; i < count; i++) { 523b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar View view = mSet[i]; 524b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar LayoutParams params = (LayoutParams) view.getLayoutParams(); 525b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (mOrientation == VERTICAL) { 5267e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko left = getPaddingLeft() + mCachedBorders[params.mSpanIndex]; 527b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); 528b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else { 5297e6965e8f2c055634ce869bf78a4e4b32e4b0c1fAlexey Vitenko top = getPaddingTop() + mCachedBorders[params.mSpanIndex]; 530b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); 531b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 532b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar // We calculate everything with View's bounding box (which includes decor and margins) 533b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar // To calculate correct layout position, we subtract margins. 534b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar layoutDecorated(view, left + params.leftMargin, top + params.topMargin, 535b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar right - params.rightMargin, bottom - params.bottomMargin); 536b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (DEBUG) { 537b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:" 538b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:" 539b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin) 5405e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar + ", span:" + params.mSpanIndex + ", spanSize:" + params.mSpanSize); 541b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 542b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar // Consume the available space if the view is not removed OR changed 543b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (params.isItemRemoved() || params.isItemChanged()) { 544b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar result.mIgnoreConsumed = true; 545b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 546b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar result.mFocusable |= view.isFocusable(); 547b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 548b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar Arrays.fill(mSet, null); 549b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 550b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 551061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private int getMainDirSpec(int dim) { 552061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (dim < 0) { 553061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return MAIN_DIR_SPEC; 554061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 555061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY); 556061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 557061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 558061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 559b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec) { 5605e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar calculateItemDecorationsForChild(child, mDecorInsets); 561b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams(); 5625e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mDecorInsets.left, 5635e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar lp.rightMargin + mDecorInsets.right); 5645e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mDecorInsets.top, 5655e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar lp.bottomMargin + mDecorInsets.bottom); 566b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar child.measure(widthSpec, heightSpec); 567b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 568b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 569b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private int updateSpecWithExtra(int spec, int startInset, int endInset) { 570b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (startInset == 0 && endInset == 0) { 571b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return spec; 572b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 573b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar final int mode = View.MeasureSpec.getMode(spec); 574b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) { 575b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return View.MeasureSpec.makeMeasureSpec( 576b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar View.MeasureSpec.getSize(spec) - startInset - endInset, mode); 577b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 578b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return spec; 579b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 580b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 5819ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar private void assignSpans(RecyclerView.Recycler recycler, RecyclerView.State state, int count, 582061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int consumedSpanCount, boolean layingOutInPrimaryDirection) { 5835e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar int span, spanDiff, start, end, diff; 5845e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar // make sure we traverse from min position to max position 5855e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar if (layingOutInPrimaryDirection) { 5865e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar start = 0; 5875e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar end = count; 5885e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar diff = 1; 5895e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } else { 5905e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar start = count - 1; 5915e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar end = -1; 5925e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar diff = -1; 5935e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } 5945e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar if (mOrientation == VERTICAL && isLayoutRTL()) { // start from last span 595871092be9f8b8b212a7bf16a9d1b735c3964ee9bYigit Boyar span = mSpanCount - 1; 5965e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar spanDiff = -1; 5975e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } else { 5985e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar span = 0; 5995e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar spanDiff = 1; 6005e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } 6015e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar for (int i = start; i != end; i += diff) { 6025e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar View view = mSet[i]; 6035e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar LayoutParams params = (LayoutParams) view.getLayoutParams(); 6049ace89f49ed497e649b127beb12b8a237e5d30e7Yigit Boyar params.mSpanSize = getSpanSize(recycler, state, getPosition(view)); 6055e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar if (spanDiff == -1 && params.mSpanSize > 1) { 6065e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar params.mSpanIndex = span - (params.mSpanSize - 1); 6075e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } else { 6085e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar params.mSpanIndex = span; 6095e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } 6105e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar span += spanDiff * params.mSpanSize; 6115e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } 6125e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar } 6135e79cc4e2c96b0dd1d4de6f3208f9da3bcb69d26Yigit Boyar 614b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 615b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Returns the number of spans laid out by this grid. 616b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 617b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @return The number of spans 618b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @see #setSpanCount(int) 619b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 620b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public int getSpanCount() { 621b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return mSpanCount; 622b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 623b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 624b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 625b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Sets the number of spans to be laid out. 626b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 627b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * If {@link #getOrientation()} is {@link #VERTICAL}, this is the number of columns. 628b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * If {@link #getOrientation()} is {@link #HORIZONTAL}, this is the number of rows. 629b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 630b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @param spanCount The total number of spans in the grid 631b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @see #getSpanCount() 632b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 633b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public void setSpanCount(int spanCount) { 634b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (spanCount == mSpanCount) { 635b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return; 636b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 637204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar mPendingSpanCountChange = true; 638b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (spanCount < 1) { 639b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar throw new IllegalArgumentException("Span count should be at least 1. Provided " 640b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar + spanCount); 641b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 642b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar mSpanCount = spanCount; 643061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanSizeLookup.invalidateSpanIndexCache(); 644b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 645b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 646b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 647b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * A helper class to provide the number of spans each item occupies. 648b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 649b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Default implementation sets each item to occupy exactly 1 span. 650b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 651b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @see GridLayoutManager#setSpanSizeLookup(SpanSizeLookup) 652b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 653b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public static abstract class SpanSizeLookup { 654061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 655061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final SparseIntArray mSpanIndexCache = new SparseIntArray(); 656061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 657061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar private boolean mCacheSpanIndices = false; 658061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 659b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 660b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Returns the number of span occupied by the item at <code>position</code>. 661b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 662b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @param position The adapter position of the item 663b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @return The number of spans occupied by the item at the provided position 664b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 665b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar abstract public int getSpanSize(int position); 666b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 667b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 668061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * Sets whether the results of {@link #getSpanIndex(int, int)} method should be cached or 669061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * not. By default these values are not cached. If you are not overriding 670061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * {@link #getSpanIndex(int, int)}, you should set this to true for better performance. 671061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * 672061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * @param cacheSpanIndices Whether results of getSpanIndex should be cached or not. 673061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar */ 674061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void setSpanIndexCacheEnabled(boolean cacheSpanIndices) { 675061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mCacheSpanIndices = cacheSpanIndices; 676061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 677061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 678061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar /** 679061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * Clears the span index cache. GridLayoutManager automatically calls this method when 680061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * adapter changes occur. 681061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar */ 682061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public void invalidateSpanIndexCache() { 683061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanIndexCache.clear(); 684061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 685061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 686061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar /** 687061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * Returns whether results of {@link #getSpanIndex(int, int)} method are cached or not. 688061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * 689061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * @return True if results of {@link #getSpanIndex(int, int)} are cached. 690061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar */ 691061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar public boolean isSpanIndexCacheEnabled() { 692061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return mCacheSpanIndices; 693061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 694061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 695061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int getCachedSpanIndex(int position, int spanCount) { 696061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (!mCacheSpanIndices) { 697061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return getSpanIndex(position, spanCount); 698061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 699061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int existing = mSpanIndexCache.get(position, -1); 700061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (existing != -1) { 701061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return existing; 702061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 703061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int value = getSpanIndex(position, spanCount); 704061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar mSpanIndexCache.put(position, value); 705061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return value; 706061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 707061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 708061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar /** 709b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Returns the final span index of the provided position. 710b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 711061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * If you have a faster way to calculate span index for your items, you should override 712061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * this method. Otherwise, you should enable span index cache 713061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * ({@link #setSpanIndexCacheEnabled(boolean)}) for better performance. When caching is 714061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * disabled, default implementation traverses all items from 0 to 715061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * <code>position</code>. When caching is enabled, it calculates from the closest cached 716061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * value before the <code>position</code>. 717061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * <p> 718061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * If you override this method, you need to make sure it is consistent with 719a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * {@link #getSpanSize(int)}. GridLayoutManager does not call this method for 720061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * each item. It is called only for the reference item and rest of the items 721061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * are assigned to spans based on the reference item. For example, you cannot assign a 722061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * position to span 2 while span 1 is empty. 723b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 724061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * Note that span offsets always start with 0 and are not affected by RTL. 725b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 726061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar * @param position The position of the item 727b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @param spanCount The total number of spans in the grid 728b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @return The final span position of the item. Should be between 0 (inclusive) and 729b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <code>spanCount</code>(exclusive) 730b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 731b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public int getSpanIndex(int position, int spanCount) { 732b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar int positionSpanSize = getSpanSize(position); 733b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (positionSpanSize == spanCount) { 734b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return 0; // quick return for full-span items 735b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 73673304eff156157f62075215e795e774803a6f96aYigit Boyar int span = 0; 737061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int startPos = 0; 738061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar // If caching is enabled, try to jump 739061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (mCacheSpanIndices && mSpanIndexCache.size() > 0) { 740061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int prevKey = findReferenceIndexFromCache(position); 741061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (prevKey >= 0) { 742061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar span = mSpanIndexCache.get(prevKey) + getSpanSize(prevKey); 743061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar startPos = prevKey + 1; 744061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 745061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 746061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar for (int i = startPos; i < position; i++) { 74773304eff156157f62075215e795e774803a6f96aYigit Boyar int size = getSpanSize(i); 748b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar span += size; 749b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (span == spanCount) { 750b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar span = 0; 751b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } else if (span > spanCount) { 752b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar // did not fit, moving to next row / column 753b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar span = size; 754b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 755b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 756b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar if (span + positionSpanSize <= spanCount) { 757b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return span; 758b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 759b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return 0; 760b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 761061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 762061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int findReferenceIndexFromCache(int position) { 763061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int lo = 0; 764061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int hi = mSpanIndexCache.size() - 1; 765061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 766061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar while (lo <= hi) { 767061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int mid = (lo + hi) >>> 1; 768061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar final int midVal = mSpanIndexCache.keyAt(mid); 769061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (midVal < position) { 770061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar lo = mid + 1; 771061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } else { 772061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar hi = mid - 1; 773061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 774061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 775061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar int index = lo - 1; 776061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar if (index >= 0 && index < mSpanIndexCache.size()) { 777061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return mSpanIndexCache.keyAt(index); 778061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 779061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar return -1; 780061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar } 781a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar 782a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar /** 783a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * Returns the index of the group this position belongs. 784a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * <p> 785a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * For example, if grid has 3 columns and each item occupies 1 span, span group index 786a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * for item 1 will be 0, item 5 will be 1. 787a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * 788a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * @param adapterPosition The position in adapter 789a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * @param spanCount The total number of spans in the grid 790a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar * @return The index of the span group including the item at the given adapter position 791a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar */ 792a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar public int getSpanGroupIndex(int adapterPosition, int spanCount) { 793a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar int span = 0; 794a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar int group = 0; 795a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar int positionSpanSize = getSpanSize(adapterPosition); 796a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar for (int i = 0; i < adapterPosition; i++) { 797a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar int size = getSpanSize(i); 798a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar span += size; 799a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (span == spanCount) { 800a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar span = 0; 801a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar group++; 802a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } else if (span > spanCount) { 803a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar // did not fit, moving to next row / column 804a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar span = size; 805a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar group++; 806a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 807a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 808a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar if (span + positionSpanSize > spanCount) { 809a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar group++; 810a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 811a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar return group; 812a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar } 813b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 814b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 815b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 816b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public boolean supportsPredictiveItemAnimations() { 817204f79ca6e0d6253c10a80da11056b03cb9d3fb0Yigit Boyar return mPendingSavedState == null && !mPendingSpanCountChange; 818b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 819b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 820b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 821b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Default implementation for {@link SpanSizeLookup}. Each item occupies 1 span. 822b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 823b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public static final class DefaultSpanSizeLookup extends SpanSizeLookup { 824061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar 825b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 826b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public int getSpanSize(int position) { 827b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return 1; 828b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 829b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 830b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar @Override 831b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public int getSpanIndex(int position, int spanCount) { 832b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return position % spanCount; 833b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 834b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 835b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 836b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 837b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * LayoutParams used by GridLayoutManager. 83842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * <p> 83942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the 84042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is 84142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar * expected to fill all of the space given to it. 842b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 843b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public static class LayoutParams extends RecyclerView.LayoutParams { 844b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 845b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 846b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Span Id for Views that are not laid out yet. 847b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 848b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public static final int INVALID_SPAN_ID = -1; 849b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 850b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private int mSpanIndex = INVALID_SPAN_ID; 851b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 852b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar private int mSpanSize = 0; 853b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 854b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public LayoutParams(Context c, AttributeSet attrs) { 855b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(c, attrs); 856b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 857b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 858b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public LayoutParams(int width, int height) { 859b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(width, height); 860b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 861b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 862b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public LayoutParams(ViewGroup.MarginLayoutParams source) { 863b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(source); 864b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 865b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 866b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public LayoutParams(ViewGroup.LayoutParams source) { 867b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(source); 868b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 869b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 870b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public LayoutParams(RecyclerView.LayoutParams source) { 871b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar super(source); 872b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 873b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 874b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 875b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Returns the current span index of this View. If the View is not laid out yet, the return 876b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * value is <code>undefined</code>. 877b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 878b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Note that span index may change by whether the RecyclerView is RTL or not. For 879b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * example, if the number of spans is 3 and layout is RTL, the rightmost item will have 880b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * span index of 2. If the layout changes back to LTR, span index for this view will be 0. 881b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * If the item was occupying 2 spans, span indices would be 1 and 0 respectively. 882b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * <p> 883b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * If the View occupies multiple spans, span with the minimum index is returned. 884b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 885b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @return The span index of the View. 886b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 887b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public int getSpanIndex() { 888b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return mSpanIndex; 889b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 890b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 891b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar /** 892b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * Returns the number of spans occupied by this View. If the View not laid out yet, the 893b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * return value is <code>undefined</code>. 894b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * 895b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar * @return The number of spans occupied by this View. 896b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar */ 897b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar public int getSpanSize() { 898b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar return mSpanSize; 899b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 900b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar } 901b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar 902b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar} 903