StaggeredGridDefault.java revision e0e66a21916f94ebbced0d1ffe3dc652c9c7a15e
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 toLimit) { 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 endmost row edge (.high is biggest, or .low is smallest in reversed flow) 40 int edgeRowIndex = mReversedFlow ? 41 (mLocations.size() > 0 ? getMinLowRowIndex() : -1) : 42 (mLocations.size() > 0 ? getMaxHighRowIndex() : -1); 43 int edge = mReversedFlow ? 44 (edgeRowIndex != -1 ? mRows[edgeRowIndex].low : Integer.MAX_VALUE) : 45 (edgeRowIndex != -1 ? mRows[edgeRowIndex].high : Integer.MIN_VALUE); 46 // fill from current row till last row so that each row will grow longer than 47 // the previous highest row. 48 for (; rowIndex < mNumRows; rowIndex++) { 49 // fill one item to a row 50 if (itemIndex == count) { 51 break top_loop; 52 } 53 appendItemToRow(itemIndex++, rowIndex); 54 // fill more item to the row to make sure this row is longer than 55 // the previous highest row. 56 if (edgeRowIndex == -1) { 57 edgeRowIndex = mReversedFlow ? getMinLowRowIndex() : getMaxHighRowIndex(); 58 edge = mReversedFlow ? 59 mRows[edgeRowIndex].low : 60 mRows[edgeRowIndex].high; 61 } else if (rowIndex != edgeRowIndex) { 62 while (mReversedFlow ? 63 mRows[rowIndex].low > edge : 64 mRows[rowIndex].high < edge) { 65 if (itemIndex == count) { 66 break top_loop; 67 } 68 appendItemToRow(itemIndex++, rowIndex); 69 } 70 } 71 } 72 if (mReversedFlow ? 73 mRows[getMaxLowRowIndex()].low <= toLimit : 74 mRows[getMinHighRowIndex()].high >= toLimit) { 75 break; 76 } 77 // start fill from row 0 again 78 rowIndex = 0; 79 } 80 } 81 82 @Override 83 public void prependItems(int toLimit) { 84 if (mProvider.getCount() <= 0) return; 85 int itemIndex; 86 int rowIndex; 87 if (mLocations.size() > 0) { 88 itemIndex = getFirstIndex() - 1; 89 rowIndex = mLocations.getFirst().row; 90 if (rowIndex == 0) { 91 rowIndex = mNumRows - 1; 92 } else { 93 rowIndex--; 94 } 95 } else { 96 itemIndex = mStartIndex != START_DEFAULT ? mStartIndex : 0; 97 rowIndex = mStartRow != START_DEFAULT ? mStartRow : itemIndex % mNumRows; 98 } 99 100 top_loop: 101 while (true) { 102 // find startmost row edge (.low is smallest, or .high is biggest in reversed flow) 103 int edgeRowIndex = mReversedFlow ? 104 (mLocations.size() > 0 ? getMaxHighRowIndex() : -1) : 105 (mLocations.size() > 0 ? getMinLowRowIndex() : -1); 106 int edge = mReversedFlow ? 107 (edgeRowIndex != -1 ? mRows[edgeRowIndex].high : Integer.MIN_VALUE) : 108 (edgeRowIndex != -1 ? mRows[edgeRowIndex].low : Integer.MAX_VALUE); 109 for (; rowIndex >=0 ; rowIndex--) { 110 if (itemIndex < 0) { 111 break top_loop; 112 } 113 prependItemToRow(itemIndex--, rowIndex); 114 if (edgeRowIndex == -1) { 115 edgeRowIndex = mReversedFlow ? getMaxHighRowIndex() : getMinLowRowIndex(); 116 edge = mReversedFlow ? 117 mRows[edgeRowIndex].high : 118 mRows[edgeRowIndex].low; 119 } else if (rowIndex != edgeRowIndex) { 120 while (mReversedFlow ? 121 mRows[rowIndex].high < edge : 122 mRows[rowIndex].low > edge) { 123 if (itemIndex < 0) { 124 break top_loop; 125 } 126 prependItemToRow(itemIndex--, rowIndex); 127 } 128 } 129 } 130 if (mReversedFlow ? 131 mRows[getMinHighRowIndex()].high >= toLimit : 132 mRows[getMaxLowRowIndex()].low <= toLimit) { 133 break; 134 } 135 rowIndex = mNumRows - 1; 136 } 137 } 138 139 @Override 140 public final void stripDownTo(int itemIndex) { 141 // because we layout the items in the order that next item is either same row 142 // or next row, so we can easily find the row range by searching items forward and 143 // backward until we see the row is 0 or mNumRow - 1 144 Location loc = getLocation(itemIndex); 145 if (loc == null) { 146 return; 147 } 148 int firstIndex = getFirstIndex(); 149 int lastIndex = getLastIndex(); 150 int row = loc.row; 151 152 int endIndex = itemIndex; 153 int endRow = row; 154 while (endRow < mNumRows - 1 && endIndex < lastIndex) { 155 endIndex++; 156 endRow = getLocation(endIndex).row; 157 } 158 159 int startIndex = itemIndex; 160 int startRow = row; 161 while (startRow > 0 && startIndex > firstIndex) { 162 startIndex--; 163 startRow = getLocation(startIndex).row; 164 } 165 // trim information 166 for (int i = firstIndex; i < startIndex; i++) { 167 removeFirst(); 168 } 169 for (int i = endIndex; i < lastIndex; i++) { 170 removeLast(); 171 } 172 } 173} 174