StaggeredGridDefault.java revision 8b068ddbbf22a246eab49ec25a2f7c3abfbdca51
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16/**
17 * A default implementation of {@link StaggeredGrid}.
18 *
19 * This implementation tries to fill items in consecutive row order. The next
20 * item is always in same row or in the next row.
21 */
22final class StaggeredGridDefault extends StaggeredGrid {
23
24    @Override
25    public void appendItems(int upTo) {
26        int count = mProvider.getCount();
27        int itemIndex;
28        int rowIndex;
29        if (mLocations.size() > 0) {
30            itemIndex = getLastIndex() + 1;
31            rowIndex = (mLocations.getLast().row + 1) % mNumRows;
32        } else {
33            itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0;
34            rowIndex = mStartRow != START_DEFAULT ? mStartRow : itemIndex % mNumRows;
35        }
36
37    top_loop:
38        while (true) {
39            // find highest row (.high is biggest)
40            int maxHighRowIndex = mLocations.size() > 0 ? getMaxHighRowIndex() : -1;
41            int maxHigh = maxHighRowIndex != -1 ? mRows[maxHighRowIndex].high : Integer.MIN_VALUE;
42            // fill from current row till last row so that each row will grow longer than
43            // the previous highest row.
44            for (; rowIndex < mNumRows; rowIndex++) {
45                // fill one item to a row
46                if (itemIndex == count) {
47                    break top_loop;
48                }
49                appendItemToRow(itemIndex++, rowIndex);
50                // fill more item to the row to make sure this row is longer than
51                // the previous highest row.
52                if (maxHighRowIndex == -1) {
53                    maxHighRowIndex = getMaxHighRowIndex();
54                    maxHigh = mRows[maxHighRowIndex].high;
55                } else  if (rowIndex != maxHighRowIndex) {
56                    while (mRows[rowIndex].high < maxHigh) {
57                        if (itemIndex == count) {
58                            break top_loop;
59                        }
60                        appendItemToRow(itemIndex++, rowIndex);
61                    }
62                }
63            }
64            if (mRows[getMinHighRowIndex()].high >= upTo) {
65                break;
66            }
67            // start fill from row 0 again
68            rowIndex = 0;
69        }
70    }
71
72    @Override
73    public void prependItems(int downTo) {
74        if (mProvider.getCount() <= 0) return;
75        int itemIndex;
76        int rowIndex;
77        if (mLocations.size() > 0) {
78            itemIndex = getFirstIndex() - 1;
79            rowIndex = mLocations.getFirst().row;
80            if (rowIndex == 0) {
81                rowIndex = mNumRows - 1;
82            } else {
83                rowIndex--;
84            }
85        } else {
86            itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0;
87            rowIndex = mStartRow != START_DEFAULT ? mStartRow : itemIndex % mNumRows;
88        }
89
90    top_loop:
91        while (true) {
92            int minLowRowIndex = mLocations.size() > 0 ? getMinLowRowIndex() : -1;
93            int minLow = minLowRowIndex != -1 ? mRows[minLowRowIndex].low : Integer.MAX_VALUE;
94            for (; rowIndex >=0 ; rowIndex--) {
95                if (itemIndex < 0) {
96                    break top_loop;
97                }
98                prependItemToRow(itemIndex--, rowIndex);
99                if (minLowRowIndex == -1) {
100                    minLowRowIndex = getMinLowRowIndex();
101                    minLow = mRows[minLowRowIndex].low;
102                } else if (rowIndex != minLowRowIndex) {
103                    while (mRows[rowIndex].low > minLow) {
104                        if (itemIndex < 0) {
105                            break top_loop;
106                        }
107                        prependItemToRow(itemIndex--, rowIndex);
108                    }
109                }
110            }
111            if (mRows[getMaxLowRowIndex()].low <= downTo) {
112                break;
113            }
114            rowIndex = mNumRows - 1;
115        }
116    }
117
118    @Override
119    public final void stripDownTo(int itemIndex) {
120        // because we layout the items in the order that next item is either same row
121        // or next row,  so we can easily find the row range by searching items forward and
122        // backward until we see the row is 0 or mNumRow - 1
123        Location loc = getLocation(itemIndex);
124        if (loc == null) {
125            return;
126        }
127        int firstIndex = getFirstIndex();
128        int lastIndex = getLastIndex();
129        int row = loc.row;
130
131        int endIndex = itemIndex;
132        int endRow = row;
133        while (endRow < mNumRows - 1 && endIndex < lastIndex) {
134            endIndex++;
135            endRow = getLocation(endIndex).row;
136        }
137
138        int startIndex = itemIndex;
139        int startRow = row;
140        while (startRow > 0 && startIndex > firstIndex) {
141            startIndex--;
142            startRow = getLocation(startIndex).row;
143        }
144        // trim information
145        for (int i = firstIndex; i < startIndex; i++) {
146            removeFirst();
147        }
148        for (int i = endIndex; i < lastIndex; i++) {
149            removeLast();
150        }
151    }
152}
153