18347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang/* 28347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Copyright (C) 2012 The Android Open Source Project 38347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 48347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Licensed under the Apache License, Version 2.0 (the "License"); 58347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * you may not use this file except in compliance with the License. 68347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * You may obtain a copy of the License at 78347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 88347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * http://www.apache.org/licenses/LICENSE-2.0 98347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Unless required by applicable law or agreed to in writing, software 118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * distributed under the License is distributed on an "AS IS" BASIS, 128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * See the License for the specific language governing permissions and 148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * limitations under the License. 158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangpackage com.android.ex.widget; 188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.content.Context; 208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.content.res.TypedArray; 218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.database.DataSetObserver; 228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.graphics.Canvas; 238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.os.Parcel; 248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.os.Parcelable; 258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.util.SparseArrayCompat; 268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.view.MotionEventCompat; 278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.view.VelocityTrackerCompat; 288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.view.ViewCompat; 298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.util.AttributeSet; 308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.util.Log; 318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.util.SparseArray; 328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.MotionEvent; 338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.VelocityTracker; 348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.View; 358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.ViewConfiguration; 368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.ViewGroup; 378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.widget.ListAdapter; 388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport java.util.ArrayList; 408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport java.util.Arrays; 418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang/** 438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * ListView and GridView just not complex enough? Try StaggeredGridView! 448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * <p>StaggeredGridView presents a multi-column grid with consistent column sizes 468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * but varying row sizes between the columns. Each successive item from a 478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * {@link android.widget.ListAdapter ListAdapter} will be arranged from top to bottom, 488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * left to right. The largest vertical gap is always filled first.</p> 498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * <p>Item views may span multiple columns as specified by their {@link LayoutParams}. 518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * The attribute <code>android:layout_span</code> may be used when inflating 528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * item views from xml.</p> 538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * <p>This class is still under development and is not fully functional yet.</p> 558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangpublic class StaggeredGridView extends ViewGroup { 578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final String TAG = "StaggeredGridView"; 588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final boolean DEBUG = false; 598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /* 618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * There are a few things you should know if you're going to make modifications 628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * to StaggeredGridView. 638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Like ListView, SGV populates from an adapter and recycles views that fall out 658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * of the visible boundaries of the grid. A few invariants always hold: 668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * - mFirstPosition is the adapter position of the View returned by getChildAt(0). 688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * - Any child index can be translated to an adapter position by adding mFirstPosition. 698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * - Any adapter position can be translated to a child index by subtracting mFirstPosition. 708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * - Views for items in the range [mFirstPosition, mFirstPosition + getChildCount()) are 718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * currently attached to the grid as children. All other adapter positions do not have 728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * active views. 738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * This means a few things thanks to the staggered grid's nature. Some views may stay attached 758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * long after they have scrolled offscreen if removing and recycling them would result in 768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * breaking one of the invariants above. 778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * LayoutRecords are used to track data about a particular item's layout after the associated 798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * view has been removed. These let positioning and the choice of column for an item 808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * remain consistent even though the rules for filling content up vs. filling down vary. 818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Whenever layout parameters for a known LayoutRecord change, other LayoutRecords before 838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * or after it may need to be invalidated. e.g. if the item's height or the number 848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * of columns it spans changes, all bets for other items in the same direction are off 858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * since the cached information no longer applies. 868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private ListAdapter mAdapter; 898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public static final int COLUMN_COUNT_AUTO = -1; 918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mColCountSetting = 2; 938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mColCount = 2; 948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mMinColWidth = 0; 958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mItemMargin; 968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int[] mItemTops; 988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int[] mItemBottoms; 998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean mFastChildLayout; 1018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean mPopulating; 1028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean mForcePopulateOnLayout; 1038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean mInLayout; 1048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mRestoreOffset; 1058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final RecycleBin mRecycler = new RecycleBin(); 1078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final AdapterDataSetObserver mObserver = new AdapterDataSetObserver(); 1098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean mDataChanged; 1118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mOldItemCount; 1128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mItemCount; 1138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean mHasStableIds; 1148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mFirstPosition; 1168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mTouchSlop; 1188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mMaximumVelocity; 1198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mFlingVelocity; 1208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private float mLastTouchY; 1218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private float mTouchRemainderY; 1228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mActivePointerId; 1238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final int TOUCH_MODE_IDLE = 0; 1258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final int TOUCH_MODE_DRAGGING = 1; 1268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final int TOUCH_MODE_FLINGING = 2; 1278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mTouchMode; 1298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); 1308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final ScrollerCompat mScroller; 1318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final EdgeEffectCompat mTopEdge; 1338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final EdgeEffectCompat mBottomEdge; 1348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final class LayoutRecord { 1368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public int column; 1378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public long id = -1; 1388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public int height; 1398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public int span; 1408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int[] mMargins; 1418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final void ensureMargins() { 1438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mMargins == null) { 1448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Don't need to confirm length; 1458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // all layoutrecords are purged when column count changes. 1468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mMargins = new int[span * 2]; 1478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public final int getMarginAbove(int col) { 1518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mMargins == null) { 1528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return 0; 1538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return mMargins[col * 2]; 1558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public final int getMarginBelow(int col) { 1588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mMargins == null) { 1598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return 0; 1608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return mMargins[col * 2 + 1]; 1628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public final void setMarginAbove(int col, int margin) { 1658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mMargins == null && margin == 0) { 1668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return; 1678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ensureMargins(); 1698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mMargins[col * 2] = margin; 1708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public final void setMarginBelow(int col, int margin) { 1738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mMargins == null && margin == 0) { 1748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return; 1758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ensureMargins(); 1778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mMargins[col * 2 + 1] = margin; 1788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 1818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public String toString() { 1828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang String result = "LayoutRecord{c=" + column + ", id=" + id + " h=" + height + 1838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang " s=" + span; 1848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mMargins != null) { 1858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang result += " margins[above, below]("; 1868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mMargins.length; i += 2) { 1878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang result += "[" + mMargins[i] + ", " + mMargins[i+1] + "]"; 1888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang result += ")"; 1908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return result + "}"; 1928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 1948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final SparseArrayCompat<LayoutRecord> mLayoutRecords = 1958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang new SparseArrayCompat<LayoutRecord>(); 1968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 1978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public StaggeredGridView(Context context) { 1988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this(context, null); 1998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public StaggeredGridView(Context context, AttributeSet attrs) { 2028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this(context, attrs, 0); 2038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public StaggeredGridView(Context context, AttributeSet attrs, int defStyle) { 2068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super(context, attrs, defStyle); 2078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final ViewConfiguration vc = ViewConfiguration.get(context); 2098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchSlop = vc.getScaledTouchSlop(); 2108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mMaximumVelocity = vc.getScaledMaximumFlingVelocity(); 2118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFlingVelocity = vc.getScaledMinimumFlingVelocity(); 2128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScroller = ScrollerCompat.from(context); 2138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTopEdge = new EdgeEffectCompat(context); 2158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mBottomEdge = new EdgeEffectCompat(context); 2168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang setWillNotDraw(false); 2178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang setClipToPadding(false); 2188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 2218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Set a fixed number of columns for this grid. Space will be divided evenly 2228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * among all columns, respecting the item margin between columns. 2238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * The default is 2. (If it were 1, perhaps you should be using a 2248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * {@link android.widget.ListView ListView}.) 2258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 2268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param colCount Number of columns to display. 2278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @see #setMinColumnWidth(int) 2288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 2298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void setColumnCount(int colCount) { 2308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (colCount < 1 && colCount != COLUMN_COUNT_AUTO) { 2318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang throw new IllegalArgumentException("Column count must be at least 1 - received " + 2328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang colCount); 2338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final boolean needsPopulate = colCount != mColCount; 2358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mColCount = mColCountSetting = colCount; 2368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (needsPopulate) { 2378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang populate(); 2388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public int getColumnCount() { 2428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return mColCount; 2438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 2468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Set a minimum column width for 2478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param minColWidth 2488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 2498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void setMinColumnWidth(int minColWidth) { 2508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mMinColWidth = minColWidth; 2518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang setColumnCount(COLUMN_COUNT_AUTO); 2528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 2558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Set the margin between items in pixels. This margin is applied 2568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * both vertically and horizontally. 2578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 2588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param marginPixels Spacing between items in pixels 2598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 2608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void setItemMargin(int marginPixels) { 2618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final boolean needsPopulate = marginPixels != mItemMargin; 2628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemMargin = marginPixels; 2638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (needsPopulate) { 2648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang populate(); 2658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 2698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Return the first adapter position with a view currently attached as 2708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * a child view of this grid. 2718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 2728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return the adapter position represented by the view at getChildAt(0). 2738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 2748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public int getFirstPosition() { 2758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return mFirstPosition; 2768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 2798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public boolean onInterceptTouchEvent(MotionEvent ev) { 2808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mVelocityTracker.addMovement(ev); 2818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 2828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang switch (action) { 2838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang case MotionEvent.ACTION_DOWN: 2848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mVelocityTracker.clear(); 2858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScroller.abortAnimation(); 2868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLastTouchY = ev.getY(); 2878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 2888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchRemainderY = 0; 2898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTouchMode == TOUCH_MODE_FLINGING) { 2908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Catch! 2918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_DRAGGING; 2928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return true; 2938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 2948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang break; 2958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 2968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang case MotionEvent.ACTION_MOVE: { 2978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 2988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (index < 0) { 2998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " + 3008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mActivePointerId + " - did StaggeredGridView receive an inconsistent " + 3018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "event stream?"); 3028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return false; 3038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final float y = MotionEventCompat.getY(ev, index); 3058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final float dy = y - mLastTouchY + mTouchRemainderY; 3068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int deltaY = (int) dy; 3078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchRemainderY = dy - deltaY; 3088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (Math.abs(dy) > mTouchSlop) { 3108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_DRAGGING; 3118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return true; 3128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return false; 3178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 3208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public boolean onTouchEvent(MotionEvent ev) { 3218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mVelocityTracker.addMovement(ev); 3228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; 3238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang switch (action) { 3248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang case MotionEvent.ACTION_DOWN: 3258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mVelocityTracker.clear(); 3268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScroller.abortAnimation(); 3278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLastTouchY = ev.getY(); 3288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 3298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchRemainderY = 0; 3308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang break; 3318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang case MotionEvent.ACTION_MOVE: { 3338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 3348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (index < 0) { 3358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " + 3368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mActivePointerId + " - did StaggeredGridView receive an inconsistent " + 3378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "event stream?"); 3388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return false; 3398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final float y = MotionEventCompat.getY(ev, index); 3418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final float dy = y - mLastTouchY + mTouchRemainderY; 3428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int deltaY = (int) dy; 3438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchRemainderY = dy - deltaY; 3448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (Math.abs(dy) > mTouchSlop) { 3468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_DRAGGING; 3478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTouchMode == TOUCH_MODE_DRAGGING) { 3508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLastTouchY = y; 3518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!trackMotionScroll(deltaY, true)) { 3538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Break fling velocity if we impacted an edge. 3548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mVelocityTracker.clear(); 3558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } break; 3588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang case MotionEvent.ACTION_CANCEL: 3608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_IDLE; 3618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang break; 3628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang case MotionEvent.ACTION_UP: { 3648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 3658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final float velocity = VelocityTrackerCompat.getYVelocity(mVelocityTracker, 3668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mActivePointerId); 3678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (Math.abs(velocity) > mFlingVelocity) { // TODO 3688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_FLINGING; 3698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScroller.fling(0, 0, 0, (int) velocity, 0, 0, 3708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Integer.MIN_VALUE, Integer.MAX_VALUE); 3718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLastTouchY = 0; 3728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ViewCompat.postInvalidateOnAnimation(this); 3738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 3748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_IDLE; 3758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } break; 3788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return true; 3808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 3818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 3838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 3848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param deltaY Pixels that content should move by 3858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return true if the movement completed, false if it was stopped prematurely. 3868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 3878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private boolean trackMotionScroll(int deltaY, boolean allowOverScroll) { 3888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final boolean contentFits = contentFits(); 3898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int allowOverhang = Math.abs(deltaY); 3908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 3918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int overScrolledBy; 3928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int movedBy; 3938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!contentFits) { 3948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int overhang; 3958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final boolean up; 3968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mPopulating = true; 3978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (deltaY > 0) { 3988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang overhang = fillUp(mFirstPosition - 1, allowOverhang); 3998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang up = true; 4008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 4018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang overhang = fillDown(mFirstPosition + getChildCount(), allowOverhang) + mItemMargin; 4028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang up = false; 4038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang movedBy = Math.min(overhang, allowOverhang); 4058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang offsetChildren(up ? movedBy : -movedBy); 4068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang recycleOffscreenViews(); 4078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mPopulating = false; 4088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang overScrolledBy = allowOverhang - overhang; 4098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 4108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang overScrolledBy = allowOverhang; 4118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang movedBy = 0; 4128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (allowOverScroll) { 4158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int overScrollMode = ViewCompat.getOverScrollMode(this); 4168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || 4188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits)) { 4198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (overScrolledBy > 0) { 4218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang EdgeEffectCompat edge = deltaY > 0 ? mTopEdge : mBottomEdge; 4228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang edge.onPull((float) Math.abs(deltaY) / getHeight()); 4238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ViewCompat.postInvalidateOnAnimation(this); 4248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return deltaY == 0 || movedBy != 0; 4298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private final boolean contentFits() { 4328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mFirstPosition != 0 || getChildCount() != mItemCount) { 4338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return false; 4348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int topmost = Integer.MAX_VALUE; 4378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int bottommost = Integer.MIN_VALUE; 4388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mColCount; i++) { 4398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemTops[i] < topmost) { 4408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang topmost = mItemTops[i]; 4418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemBottoms[i] > bottommost) { 4438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang bottommost = mItemBottoms[i]; 4448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return topmost >= getPaddingTop() && bottommost <= getHeight() - getPaddingBottom(); 4488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private void recycleAllViews() { 4518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < getChildCount(); i++) { 4528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.addScrap(getChildAt(i)); 4538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mInLayout) { 4568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeAllViewsInLayout(); 4578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 4588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeAllViews(); 4598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 4638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Important: this method will leave offscreen views attached if they 4648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * are required to maintain the invariant that child view with index i 4658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * is always the view corresponding to position mFirstPosition + i. 4668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 4678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private void recycleOffscreenViews() { 4688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int height = getHeight(); 4698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int clearAbove = -mItemMargin; 4708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int clearBelow = height + mItemMargin; 4718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = getChildCount() - 1; i >= 0; i--) { 4728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(i); 4738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (child.getTop() <= clearBelow) { 4748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // There may be other offscreen views, but we need to maintain 4758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // the invariant documented above. 4768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang break; 4778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mInLayout) { 4808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeViewsInLayout(i, 1); 4818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 4828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeViewAt(i); 4838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.addScrap(child); 4868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang while (getChildCount() > 0) { 4898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(0); 4908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (child.getBottom() >= clearAbove) { 4918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // There may be other offscreen views, but we need to maintain 4928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // the invariant documented above. 4938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang break; 4948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 4958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 4968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mInLayout) { 4978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeViewsInLayout(0, 1); 4988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 4998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeViewAt(0); 5008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.addScrap(child); 5038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFirstPosition++; 5048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childCount = getChildCount(); 5078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (childCount > 0) { 5088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Repair the top and bottom column boundaries from the views we still have 5098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemTops, Integer.MAX_VALUE); 5108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemBottoms, Integer.MIN_VALUE); 5118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < childCount; i++){ 5138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(i); 5148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 5158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int top = child.getTop() - mItemMargin; 5168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int bottom = child.getBottom(); 5178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutRecord rec = mLayoutRecords.get(mFirstPosition + i); 5188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colEnd = lp.column + Math.min(mColCount, lp.span); 5208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int col = lp.column; col < colEnd; col++) { 5218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colTop = top - rec.getMarginAbove(col - lp.column); 5228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colBottom = bottom + rec.getMarginBelow(col - lp.column); 5238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (colTop < mItemTops[col]) { 5248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemTops[col] = colTop; 5258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (colBottom > mItemBottoms[col]) { 5278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[col] = colBottom; 5288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int col = 0; col < mColCount; col++) { 5338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemTops[col] == Integer.MAX_VALUE) { 5348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // If one was untouched, both were. 5358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemTops[col] = 0; 5368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[col] = 0; 5378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void computeScroll() { 5438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mScroller.computeScrollOffset()) { 5448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int y = mScroller.getCurrY(); 5458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int dy = (int) (y - mLastTouchY); 5468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLastTouchY = y; 5478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final boolean stopped = !trackMotionScroll(dy, false); 5488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!stopped && !mScroller.isFinished()) { 5508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ViewCompat.postInvalidateOnAnimation(this); 5518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 5528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (stopped) { 5538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int overScrollMode = ViewCompat.getOverScrollMode(this); 5548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (overScrollMode != ViewCompat.OVER_SCROLL_NEVER) { 5558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final EdgeEffectCompat edge; 5568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (dy > 0) { 5578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang edge = mTopEdge; 5588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 5598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang edge = mBottomEdge; 5608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang edge.onAbsorb(Math.abs((int) mScroller.getCurrVelocity())); 5628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ViewCompat.postInvalidateOnAnimation(this); 5638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScroller.abortAnimation(); 5658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTouchMode = TOUCH_MODE_IDLE; 5678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 5728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void draw(Canvas canvas) { 5738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super.draw(canvas); 5748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTopEdge != null) { 5768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang boolean needsInvalidate = false; 5778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!mTopEdge.isFinished()) { 5788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTopEdge.draw(canvas); 5798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang needsInvalidate = true; 5808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!mBottomEdge.isFinished()) { 5828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int restoreCount = canvas.save(); 5838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int width = getWidth(); 5848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang canvas.translate(-width, getHeight()); 5858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang canvas.rotate(180, width, 0); 5868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mBottomEdge.draw(canvas); 5878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang canvas.restoreToCount(restoreCount); 5888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang needsInvalidate = true; 5898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (needsInvalidate) { 5928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ViewCompat.postInvalidateOnAnimation(this); 5938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 5968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 5978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void beginFastChildLayout() { 5988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFastChildLayout = true; 5998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void endFastChildLayout() { 6028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFastChildLayout = false; 6038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang populate(); 6048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 6078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void requestLayout() { 6088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!mPopulating && !mFastChildLayout) { 6098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super.requestLayout(); 6108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 6148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 6158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int widthMode = MeasureSpec.getMode(widthMeasureSpec); 6168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int heightMode = MeasureSpec.getMode(heightMeasureSpec); 6178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int widthSize = MeasureSpec.getSize(widthMeasureSpec); 6188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int heightSize = MeasureSpec.getSize(heightMeasureSpec); 6198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (widthMode != MeasureSpec.EXACTLY) { 6218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.e(TAG, "onMeasure: must have an exact width or match_parent! " + 6228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "Using fallback spec of EXACTLY " + widthSize); 6238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang widthMode = MeasureSpec.EXACTLY; 6248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (heightMode != MeasureSpec.EXACTLY) { 6268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.e(TAG, "onMeasure: must have an exact height or match_parent! " + 6278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "Using fallback spec of EXACTLY " + heightSize); 6288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightMode = MeasureSpec.EXACTLY; 6298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang setMeasuredDimension(widthSize, heightSize); 6328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mColCountSetting == COLUMN_COUNT_AUTO) { 6348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = widthSize / mMinColWidth; 6358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (colCount != mColCount) { 6368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mColCount = colCount; 6378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mForcePopulateOnLayout = true; 6388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 6438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang protected void onLayout(boolean changed, int l, int t, int r, int b) { 6448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mInLayout = true; 6458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang populate(); 6468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mInLayout = false; 6478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mForcePopulateOnLayout = false; 6488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int width = r - l; 6508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int height = b - t; 6518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTopEdge.setSize(width, height); 6528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mBottomEdge.setSize(width, height); 6538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private void populate() { 6568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (getWidth() == 0 || getHeight() == 0) { 6578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return; 6588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mColCount == COLUMN_COUNT_AUTO) { 6618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = getWidth() / mMinColWidth; 6628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (colCount != mColCount) { 6638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mColCount = colCount; 6648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 6688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemTops == null || mItemTops.length != colCount) { 6698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemTops = new int[colCount]; 6708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms = new int[colCount]; 6718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int top = getPaddingTop(); 6728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int offset = top + Math.min(mRestoreOffset, 0); 6738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemTops, offset); 6748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemBottoms, offset); 6758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.clear(); 6768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mInLayout) { 6778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeAllViewsInLayout(); 6788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 6798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeAllViews(); 6808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRestoreOffset = 0; 6828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mPopulating = true; 6858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang layoutChildren(mDataChanged); 6868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang fillDown(mFirstPosition + getChildCount(), 0); 6878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang fillUp(mFirstPosition - 1, 0); 6888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mPopulating = false; 6898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mDataChanged = false; 6908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 6918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 6928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private void dumpItemPositions() { 6938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childCount = getChildCount(); 6948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, "dumpItemPositions:"); 6958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, " => Tops:"); 6968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mColCount; i++) { 6978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, " => " + mItemTops[i]); 6988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang boolean found = false; 6998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int j = 0; j < childCount; j++) { 7008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(j); 7018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemTops[i] == child.getTop() - mItemMargin) { 7028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang found = true; 7038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!found) { 7068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, "!!! No top item found for column " + i + " value " + mItemTops[i]); 7078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, " => Bottoms:"); 7108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mColCount; i++) { 7118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, " => " + mItemBottoms[i]); 7128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang boolean found = false; 7138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int j = 0; j < childCount; j++) { 7148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(j); 7158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemBottoms[i] == child.getBottom()) { 7168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang found = true; 7178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!found) { 7208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.d(TAG, "!!! No bottom item found for column " + i + " value " + mItemBottoms[i]); 7218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final void offsetChildren(int offset) { 7268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childCount = getChildCount(); 7278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < childCount; i++) { 7288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(i); 7298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.layout(child.getLeft(), child.getTop() + offset, 7308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.getRight(), child.getBottom() + offset); 7318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 7348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < colCount; i++) { 7358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemTops[i] += offset; 7368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[i] += offset; 7378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 7418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Measure and layout all currently visible children. 7428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 7438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param queryAdapter true to requery the adapter for view data 7448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 7458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final void layoutChildren(boolean queryAdapter) { 7468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int paddingLeft = getPaddingLeft(); 7478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int paddingRight = getPaddingRight(); 7488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int itemMargin = mItemMargin; 7498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colWidth = 7508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount; 7518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int rebuildLayoutRecordsBefore = -1; 7528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int rebuildLayoutRecordsAfter = -1; 7538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemBottoms, Integer.MIN_VALUE); 7558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childCount = getChildCount(); 7578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < childCount; i++) { 7588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang View child = getChildAt(i); 7598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutParams lp = (LayoutParams) child.getLayoutParams(); 7608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int col = lp.column; 7618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int position = mFirstPosition + i; 7628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final boolean needsLayout = queryAdapter || child.isLayoutRequested(); 7638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (queryAdapter) { 7658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang View newView = obtainView(position, child); 7668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (newView != child) { 7678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeViewAt(i); 7688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang addView(newView, i); 7698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child = newView; 7708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp = (LayoutParams) child.getLayoutParams(); // Might have changed 7728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int span = Math.min(mColCount, lp.span); 7758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int widthSize = colWidth * span + itemMargin * (span - 1); 7768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (needsLayout) { 7788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); 7798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int heightSpec; 7818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (lp.height == LayoutParams.WRAP_CONTENT) { 7828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 7838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 7848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); 7858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.measure(widthSpec, heightSpec); 7888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 7908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int childTop = mItemBottoms[col] > Integer.MIN_VALUE ? 7918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[col] + mItemMargin : child.getTop(); 7928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (span > 1) { 7938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int lowest = childTop; 7948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int j = col + 1; j < col + span; j++) { 7958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int bottom = mItemBottoms[j] + mItemMargin; 7968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (bottom > lowest) { 7978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lowest = bottom; 7988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 7998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang childTop = lowest; 8018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childHeight = child.getMeasuredHeight(); 8038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childBottom = childTop + childHeight; 8048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childLeft = paddingLeft + col * (colWidth + itemMargin); 8058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childRight = childLeft + child.getMeasuredWidth(); 8068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.layout(childLeft, childTop, childRight, childBottom); 8078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int j = col; j < col + span; j++) { 8098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[j] = childBottom; 8108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutRecord rec = mLayoutRecords.get(position); 8138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec != null && rec.height != childHeight) { 8148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Invalidate our layout records for everything before this. 8158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.height = childHeight; 8168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rebuildLayoutRecordsBefore = position; 8178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec != null && rec.span != span) { 8208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Invalidate our layout records for everything after this. 8218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 8228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rebuildLayoutRecordsAfter = position; 8238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Update mItemBottoms for any empty columns 8278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mColCount; i++) { 8288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemBottoms[i] == Integer.MIN_VALUE) { 8298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[i] = mItemTops[i]; 8308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rebuildLayoutRecordsBefore >= 0 || rebuildLayoutRecordsAfter >= 0) { 8348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rebuildLayoutRecordsBefore >= 0) { 8358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang invalidateLayoutRecordsBeforePosition(rebuildLayoutRecordsBefore); 8368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rebuildLayoutRecordsAfter >= 0) { 8388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang invalidateLayoutRecordsAfterPosition(rebuildLayoutRecordsAfter); 8398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < childCount; i++) { 8418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int position = mFirstPosition + i; 8428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = getChildAt(i); 8438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 8448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutRecord rec = mLayoutRecords.get(position); 8458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec == null) { 8468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = new LayoutRecord(); 8478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.put(position, rec); 8488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = lp.column; 8508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.height = child.getHeight(); 8518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.id = lp.id; 8528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = Math.min(mColCount, lp.span); 8538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final void invalidateLayoutRecordsBeforePosition(int position) { 8588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int endAt = 0; 8598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang while (endAt < mLayoutRecords.size() && mLayoutRecords.keyAt(endAt) < position) { 8608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang endAt++; 8618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.removeAtRange(0, endAt); 8638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final void invalidateLayoutRecordsAfterPosition(int position) { 8668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int beginAt = mLayoutRecords.size() - 1; 8678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang while (beginAt >= 0 && mLayoutRecords.keyAt(beginAt) > position) { 8688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang beginAt--; 8698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang beginAt++; 8718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.removeAtRange(beginAt + 1, mLayoutRecords.size() - beginAt); 8728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 8738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 8758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Should be called with mPopulating set to true 8768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 8778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param fromPosition Position to start filling from 8788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param overhang the number of extra pixels to fill beyond the current top edge 8798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return the max overhang beyond the beginning of the view of any added items at the top 8808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 8818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int fillUp(int fromPosition, int overhang) { 8828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int paddingLeft = getPaddingLeft(); 8838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int paddingRight = getPaddingRight(); 8848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int itemMargin = mItemMargin; 8858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colWidth = 8868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount; 8878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int gridTop = getPaddingTop(); 8888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int fillTo = gridTop - overhang; 8898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int nextCol = getNextColumnUp(); 8908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int position = fromPosition; 8918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang while (nextCol >= 0 && mItemTops[nextCol] > fillTo && position >= 0) { 8938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = obtainView(position, null); 8948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutParams lp = (LayoutParams) child.getLayoutParams(); 8958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 8968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (child.getParent() != this) { 8978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mInLayout) { 8988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang addViewInLayout(child, 0, lp); 8998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 9008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang addView(child, 0); 9018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int span = Math.min(mColCount, lp.span); 9058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int widthSize = colWidth * span + itemMargin * (span - 1); 9068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); 9078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutRecord rec; 9098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (span > 1) { 9108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = getNextRecordUp(position, span); 9118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang nextCol = rec.column; 9128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 9138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = mLayoutRecords.get(position); 9148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang boolean invalidateBefore = false; 9178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec == null) { 9188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = new LayoutRecord(); 9198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.put(position, rec); 9208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = nextCol; 9218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 9228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else if (span != rec.span) { 9238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 9248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = nextCol; 9258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang invalidateBefore = true; 9268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 9278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang nextCol = rec.column; 9288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mHasStableIds) { 9318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final long id = mAdapter.getItemId(position); 9328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.id = id; 9338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp.id = id; 9348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp.column = nextCol; 9378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int heightSpec; 9398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (lp.height == LayoutParams.WRAP_CONTENT) { 9408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 9418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 9428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); 9438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.measure(widthSpec, heightSpec); 9458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childHeight = child.getMeasuredHeight(); 9478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (invalidateBefore || (childHeight != rec.height && rec.height > 0)) { 9488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang invalidateLayoutRecordsBeforePosition(position); 9498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.height = childHeight; 9518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int startFrom; 9538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (span > 1) { 9548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int highest = mItemTops[nextCol]; 9558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = nextCol + 1; i < nextCol + span; i++) { 9568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int top = mItemTops[i]; 9578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (top < highest) { 9588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang highest = top; 9598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang startFrom = highest; 9628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 9638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang startFrom = mItemTops[nextCol]; 9648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childBottom = startFrom; 9668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childTop = childBottom - childHeight; 9678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childLeft = paddingLeft + nextCol * (colWidth + itemMargin); 9688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childRight = childLeft + child.getMeasuredWidth(); 9698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.layout(childLeft, childTop, childRight, childBottom); 9708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = nextCol; i < nextCol + span; i++) { 9728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemTops[i] = childTop - rec.getMarginAbove(i - nextCol) - itemMargin; 9738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang nextCol = getNextColumnUp(); 9768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFirstPosition = position--; 9778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int highestView = getHeight(); 9808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mColCount; i++) { 9818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemTops[i] < highestView) { 9828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang highestView = mItemTops[i]; 9838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return gridTop - highestView; 9868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 9878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 9888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 9898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Should be called with mPopulating set to true 9908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 9918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param fromPosition Position to start filling from 9928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param overhang the number of extra pixels to fill beyond the current bottom edge 9938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return the max overhang beyond the end of the view of any added items at the bottom 9948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 9958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int fillDown(int fromPosition, int overhang) { 9968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int paddingLeft = getPaddingLeft(); 9978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int paddingRight = getPaddingRight(); 9988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int itemMargin = mItemMargin; 9998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colWidth = 10008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount; 10018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int gridBottom = getHeight() - getPaddingBottom(); 10028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int fillTo = gridBottom + overhang; 10038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int nextCol = getNextColumnDown(); 10048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int position = fromPosition; 10058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang while (nextCol >= 0 && mItemBottoms[nextCol] < fillTo && position < mItemCount) { 10078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View child = obtainView(position, null); 10088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutParams lp = (LayoutParams) child.getLayoutParams(); 10098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (child.getParent() != this) { 10118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mInLayout) { 10128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang addViewInLayout(child, -1, lp); 10138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 10148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang addView(child); 10158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int span = Math.min(mColCount, lp.span); 10198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int widthSize = colWidth * span + itemMargin * (span - 1); 10208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); 10218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutRecord rec; 10238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (span > 1) { 10248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = getNextRecordDown(position, span); 10258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang nextCol = rec.column; 10268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 10278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = mLayoutRecords.get(position); 10288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang boolean invalidateAfter = false; 10318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec == null) { 10328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = new LayoutRecord(); 10338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.put(position, rec); 10348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = nextCol; 10358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 10368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else if (span != rec.span) { 10378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 10388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = nextCol; 10398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang invalidateAfter = true; 10408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 10418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang nextCol = rec.column; 10428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mHasStableIds) { 10458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final long id = mAdapter.getItemId(position); 10468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.id = id; 10478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp.id = id; 10488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp.column = nextCol; 10518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int heightSpec; 10538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (lp.height == LayoutParams.WRAP_CONTENT) { 10548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 10558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 10568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); 10578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.measure(widthSpec, heightSpec); 10598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childHeight = child.getMeasuredHeight(); 10618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (invalidateAfter || (childHeight != rec.height && rec.height > 0)) { 10628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang invalidateLayoutRecordsAfterPosition(position); 10638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.height = childHeight; 10658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int startFrom; 10678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (span > 1) { 10688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int lowest = mItemBottoms[nextCol]; 10698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = nextCol + 1; i < nextCol + span; i++) { 10708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int bottom = mItemBottoms[i]; 10718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (bottom > lowest) { 10728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lowest = bottom; 10738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang startFrom = lowest; 10768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 10778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang startFrom = mItemBottoms[nextCol]; 10788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childTop = startFrom + itemMargin; 10808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childBottom = childTop + childHeight; 10818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childLeft = paddingLeft + nextCol * (colWidth + itemMargin); 10828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childRight = childLeft + child.getMeasuredWidth(); 10838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang child.layout(childLeft, childTop, childRight, childBottom); 10848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = nextCol; i < nextCol + span; i++) { 10868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[i] = childBottom + rec.getMarginBelow(i - nextCol); 10878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang nextCol = getNextColumnDown(); 10908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang position++; 10918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 10938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int lowestView = 0; 10948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < mColCount; i++) { 10958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemBottoms[i] > lowestView) { 10968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lowestView = mItemBottoms[i]; 10978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 10998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return lowestView - gridBottom; 11008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 11038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return column that the next view filling upwards should occupy. This is the bottom-most 11048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * position available for a single-column item. 11058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 11068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int getNextColumnUp() { 11078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int result = -1; 11088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int bottomMost = Integer.MIN_VALUE; 11098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 11118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = colCount - 1; i >= 0; i--) { 11128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int top = mItemTops[i]; 11138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (top > bottomMost) { 11148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang bottomMost = top; 11158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang result = i; 11168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return result; 11198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 11228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Return a LayoutRecord for the given position 11238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param position 11248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param span 11258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return 11268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 11278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutRecord getNextRecordUp(int position, int span) { 11288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutRecord rec = mLayoutRecords.get(position); 11298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec == null) { 11308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = new LayoutRecord(); 11318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 11328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.put(position, rec); 11338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else if (rec.span != span) { 11348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang throw new IllegalStateException("Invalid LayoutRecord! Record had span=" + rec.span + 11358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang " but caller requested span=" + span + " for position=" + position); 11368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int targetCol = -1; 11388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int bottomMost = Integer.MIN_VALUE; 11398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 11418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = colCount - span; i >= 0; i--) { 11428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int top = Integer.MAX_VALUE; 11438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int j = i; j < i + span; j++) { 11448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int singleTop = mItemTops[j]; 11458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (singleTop < top) { 11468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang top = singleTop; 11478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (top > bottomMost) { 11508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang bottomMost = top; 11518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang targetCol = i; 11528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = targetCol; 11568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < span; i++) { 11588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.setMarginBelow(i, mItemTops[i + targetCol] - bottomMost); 11598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return rec; 11628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 11658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return column that the next view filling downwards should occupy. This is the top-most 11668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * position available. 11678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 11688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int getNextColumnDown() { 11698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int result = -1; 11708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int topMost = Integer.MAX_VALUE; 11718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 11738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < colCount; i++) { 11748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int bottom = mItemBottoms[i]; 11758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (bottom < topMost) { 11768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang topMost = bottom; 11778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang result = i; 11788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return result; 11818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutRecord getNextRecordDown(int position, int span) { 11848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang LayoutRecord rec = mLayoutRecords.get(position); 11858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (rec == null) { 11868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec = new LayoutRecord(); 11878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.span = span; 11888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.put(position, rec); 11898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else if (rec.span != span) { 11908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang throw new IllegalStateException("Invalid LayoutRecord! Record had span=" + rec.span + 11918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang " but caller requested span=" + span + " for position=" + position); 11928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 11938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int targetCol = -1; 11948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int topMost = Integer.MAX_VALUE; 11958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 11968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 11978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i <= colCount - span; i++) { 11988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int bottom = Integer.MIN_VALUE; 11998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int j = i; j < i + span; j++) { 12008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int singleBottom = mItemBottoms[j]; 12018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (singleBottom > bottom) { 12028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang bottom = singleBottom; 12038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (bottom < topMost) { 12068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang topMost = bottom; 12078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang targetCol = i; 12088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.column = targetCol; 12128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < span; i++) { 12148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang rec.setMarginAbove(i, topMost - mItemBottoms[i + targetCol]); 12158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return rec; 12188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 12218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Obtain a populated view from the adapter. If optScrap is non-null and is not 12228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * reused it will be placed in the recycle bin. 12238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * 12248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param position position to get view for 12258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @param optScrap Optional scrap view; will be reused if possible 12268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * @return A new view, a recycled view from mRecycler, or optScrap 12278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 12288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View obtainView(int position, View optScrap) { 12298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang View view = mRecycler.getTransientStateView(position); 12308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (view != null) { 12318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return view; 12328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Reuse optScrap if it's of the right type (and not null) 12358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int optType = optScrap != null ? 12368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ((LayoutParams) optScrap.getLayoutParams()).viewType : -1; 12378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int positionViewType = mAdapter.getItemViewType(position); 12388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View scrap = optType == positionViewType ? 12398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang optScrap : mRecycler.getScrapView(positionViewType); 12408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang view = mAdapter.getView(position, scrap, this); 12428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (view != scrap && scrap != null) { 12448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // The adapter didn't use it; put it back. 12458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.addScrap(scrap); 12468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ViewGroup.LayoutParams lp = view.getLayoutParams(); 12498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (view.getParent() != this) { 12518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (lp == null) { 12528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp = generateDefaultLayoutParams(); 12538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else if (!checkLayoutParams(lp)) { 12548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang lp = generateLayoutParams(lp); 12558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutParams sglp = (LayoutParams) lp; 12598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang sglp.position = position; 12608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang sglp.viewType = positionViewType; 12618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return view; 12638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public ListAdapter getAdapter() { 12668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return mAdapter; 12678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void setAdapter(ListAdapter adapter) { 12708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mAdapter != null) { 12718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mAdapter.unregisterDataSetObserver(mObserver); 12728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // TODO: If the new adapter says that there are stable IDs, remove certain layout records 12748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // and onscreen views if they have changed instead of removing all of the state here. 12758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang clearAllState(); 12768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mAdapter = adapter; 12778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mDataChanged = true; 12788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mOldItemCount = mItemCount = adapter != null ? adapter.getCount() : 0; 12798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (adapter != null) { 12808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang adapter.registerDataSetObserver(mObserver); 12818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.setViewTypeCount(adapter.getViewTypeCount()); 12828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mHasStableIds = adapter.hasStableIds(); 12838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } else { 12848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mHasStableIds = false; 12858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang populate(); 12878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 12888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 12908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Clear all state because the grid will be used for a completely different set of data. 12918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 12928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private void clearAllState() { 12938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Clear all layout records and views 12948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.clear(); 12958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeAllViews(); 12968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 12978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Reset to the top of the grid 12988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang resetStateForGridTop(); 12998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Clear recycler because there could be different view types now 13018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.clear(); 13028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 13058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Reset all internal state to be at the top of the grid. 13068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 13078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private void resetStateForGridTop() { 13088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Reset mItemTops and mItemBottoms 13098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 13108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mItemTops == null || mItemTops.length != colCount) { 13118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemTops = new int[colCount]; 13128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms = new int[colCount]; 13138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int top = getPaddingTop(); 13158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemTops, top); 13168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Arrays.fill(mItemBottoms, top); 13178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Reset the first visible position in the grid to be item 0 13198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFirstPosition = 0; 13208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRestoreOffset = 0; 13218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 13248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Scroll the list so the first visible position in the grid is the first item in the adapter. 13258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 13268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void setSelectionToTop() { 13278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Clear out the views (but don't clear out the layout records or recycler because the data 13288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // has not changed) 13298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang removeAllViews(); 13308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Reset to top of grid 13328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang resetStateForGridTop(); 13338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Start populating again 13358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang populate(); 13368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 13398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang protected LayoutParams generateDefaultLayoutParams() { 13408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return new LayoutParams(LayoutParams.WRAP_CONTENT); 13418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 13448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 13458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return new LayoutParams(lp); 13468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 13498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang protected boolean checkLayoutParams(ViewGroup.LayoutParams lp) { 13508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return lp instanceof LayoutParams; 13518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 13548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 13558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return new LayoutParams(getContext(), attrs); 13568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 13598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public Parcelable onSaveInstanceState() { 13608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final Parcelable superState = super.onSaveInstanceState(); 13618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final SavedState ss = new SavedState(superState); 13628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int position = mFirstPosition; 13638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ss.position = position; 13648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (position >= 0 && mAdapter != null && position < mAdapter.getCount()) { 13658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ss.firstId = mAdapter.getItemId(position); 13668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (getChildCount() > 0) { 13688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ss.topOffset = getChildAt(0).getTop() - mItemMargin - getPaddingTop(); 13698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return ss; 13718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 13748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void onRestoreInstanceState(Parcelable state) { 13758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang SavedState ss = (SavedState) state; 13768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super.onRestoreInstanceState(ss.getSuperState()); 13778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mDataChanged = true; 13788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mFirstPosition = ss.position; 13798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRestoreOffset = ss.topOffset; 13808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang requestLayout(); 13818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 13828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public static class LayoutParams extends ViewGroup.LayoutParams { 13848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final int[] LAYOUT_ATTRS = new int[] { 13858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang android.R.attr.layout_span 13868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang }; 13878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private static final int SPAN_INDEX = 0; 13898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 13918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * The number of columns this item should span 13928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 13938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public int span = 1; 13948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 13958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 13968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Item position this view represents 13978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 13988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int position; 13998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 14018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Type of this view as reported by the adapter 14028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 14038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int viewType; 14048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 14068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * The column this view is occupying 14078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 14088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int column; 14098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang /** 14118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * The stable ID of the item this view displays 14128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */ 14138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang long id = -1; 14148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public LayoutParams(int height) { 14168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super(FILL_PARENT, height); 14178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (this.height == FILL_PARENT) { 14198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.w(TAG, "Constructing LayoutParams with height FILL_PARENT - " + 14208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "impossible! Falling back to WRAP_CONTENT"); 14218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this.height = WRAP_CONTENT; 14228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public LayoutParams(Context c, AttributeSet attrs) { 14268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super(c, attrs); 14278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (this.width != FILL_PARENT) { 14298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.w(TAG, "Inflation setting LayoutParams width to " + this.width + 14308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang " - must be MATCH_PARENT"); 14318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this.width = FILL_PARENT; 14328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (this.height == FILL_PARENT) { 14348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.w(TAG, "Inflation setting LayoutParams height to MATCH_PARENT - " + 14358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "impossible! Falling back to WRAP_CONTENT"); 14368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this.height = WRAP_CONTENT; 14378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS); 14408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang span = a.getInteger(SPAN_INDEX, 1); 14418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang a.recycle(); 14428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public LayoutParams(ViewGroup.LayoutParams other) { 14458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super(other); 14468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (this.width != FILL_PARENT) { 14488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.w(TAG, "Constructing LayoutParams with width " + this.width + 14498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang " - must be MATCH_PARENT"); 14508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this.width = FILL_PARENT; 14518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (this.height == FILL_PARENT) { 14538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " + 14548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang "impossible! Falling back to WRAP_CONTENT"); 14558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang this.height = WRAP_CONTENT; 14568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private class RecycleBin { 14618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private ArrayList<View>[] mScrapViews; 14628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mViewTypeCount; 14638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private int mMaxScrap; 14648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private SparseArray<View> mTransientStateViews; 14668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void setViewTypeCount(int viewTypeCount) { 14688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (viewTypeCount < 1) { 14698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang throw new IllegalArgumentException("Must have at least one view type (" + 14708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang viewTypeCount + " types reported)"); 14718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (viewTypeCount == mViewTypeCount) { 14738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return; 14748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount]; 14778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < viewTypeCount; i++) { 14788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang scrapViews[i] = new ArrayList<View>(); 14798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mViewTypeCount = viewTypeCount; 14818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScrapViews = scrapViews; 14828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void clear() { 14858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int typeCount = mViewTypeCount; 14868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < typeCount; i++) { 14878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mScrapViews[i].clear(); 14888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTransientStateViews != null) { 14908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTransientStateViews.clear(); 14918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 14948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void clearTransientViews() { 14958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTransientStateViews != null) { 14968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTransientStateViews.clear(); 14978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 14998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void addScrap(View v) { 15018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final LayoutParams lp = (LayoutParams) v.getLayoutParams(); 15028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (ViewCompat.hasTransientState(v)) { 15038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTransientStateViews == null) { 15048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTransientStateViews = new SparseArray<View>(); 15058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTransientStateViews.put(lp.position, v); 15078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return; 15088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int childCount = getChildCount(); 15118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (childCount > mMaxScrap) { 15128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mMaxScrap = childCount; 15138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ArrayList<View> scrap = mScrapViews[lp.viewType]; 15168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (scrap.size() < mMaxScrap) { 15178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang scrap.add(v); 15188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public View getTransientStateView(int position) { 15228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (mTransientStateViews == null) { 15238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return null; 15248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View result = mTransientStateViews.get(position); 15278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (result != null) { 15288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mTransientStateViews.remove(position); 15298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return result; 15318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public View getScrapView(int type) { 15348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang ArrayList<View> scrap = mScrapViews[type]; 15358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (scrap.isEmpty()) { 15368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return null; 15378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int index = scrap.size() - 1; 15408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final View result = scrap.get(index); 15418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang scrap.remove(index); 15428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return result; 15438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private class AdapterDataSetObserver extends DataSetObserver { 15478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 15488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void onChanged() { 15498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mDataChanged = true; 15508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mOldItemCount = mItemCount; 15518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemCount = mAdapter.getCount(); 15528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // TODO: Consider matching these back up if we have stable IDs. 15548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mRecycler.clearTransientViews(); 15558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang if (!mHasStableIds) { 15578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Clear all layout records and recycle the views 15588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mLayoutRecords.clear(); 15598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang recycleAllViews(); 15608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // Reset item bottoms to be equal to item tops 15628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang final int colCount = mColCount; 15638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang for (int i = 0; i < colCount; i++) { 15648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang mItemBottoms[i] = mItemTops[i]; 15658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // TODO: consider repopulating in a deferred runnable instead 15698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang // (so that successive changes may still be batched) 15708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang requestLayout(); 15718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 15748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void onInvalidated() { 15758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang static class SavedState extends BaseSavedState { 15798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang long firstId = -1; 15808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int position; 15818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang int topOffset; 15828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang SavedState(Parcelable superState) { 15848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super(superState); 15858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang private SavedState(Parcel in) { 15888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super(in); 15898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang firstId = in.readLong(); 15908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang position = in.readInt(); 15918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang topOffset = in.readInt(); 15928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 15938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 15948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 15958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public void writeToParcel(Parcel out, int flags) { 15968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang super.writeToParcel(out, flags); 15978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang out.writeLong(firstId); 15988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang out.writeInt(position); 15998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang out.writeInt(topOffset); 16008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 16018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 16028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang @Override 16038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public String toString() { 16048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return "StaggereGridView.SavedState{" 16058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang + Integer.toHexString(System.identityHashCode(this)) 16068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang + " firstId=" + firstId 16078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang + " position=" + position + "}"; 16088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 16098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 16108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public static final Parcelable.Creator<SavedState> CREATOR 16118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang = new Parcelable.Creator<SavedState>() { 16128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public SavedState createFromParcel(Parcel in) { 16138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return new SavedState(in); 16148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 16158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang 16168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang public SavedState[] newArray(int size) { 16178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang return new SavedState[size]; 16188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 16198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang }; 16208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang } 16218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang} 1622