1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.car.widget;
18 
19 import androidx.recyclerview.widget.GridLayoutManager;
20 import androidx.recyclerview.widget.RecyclerView;
21 import android.view.View;
22 
23 /**
24  * Utility class that helps navigating in GridLayoutManager.
25  *
26  * <p>Assumes parameter {@code RecyclerView} uses {@link GridLayoutManager}.
27  *
28  * <p>Assumes the orientation of {@code GridLayoutManager} is vertical.
29  */
30 class GridLayoutManagerUtils {
GridLayoutManagerUtils()31     private GridLayoutManagerUtils() {}
32 
33     /**
34      * @param parent RecyclerView that uses GridLayoutManager as LayoutManager.
35      * @return number of items in the first row in {@code RecyclerView}.
36      */
getFirstRowItemCount(RecyclerView parent)37     public static int getFirstRowItemCount(RecyclerView parent) {
38         GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();
39         int itemCount = parent.getAdapter().getItemCount();
40         int spanCount = manager.getSpanCount();
41 
42         int spanSum = 0;
43         int pos = 0;
44         while (pos < itemCount && spanSum < spanCount) {
45             spanSum += manager.getSpanSizeLookup().getSpanSize(pos);
46             pos += 1;
47         }
48         // pos will be either the first item in second row, or item count when items not fill
49         // the first row.
50         return pos;
51     }
52 
53     /**
54      * Returns the span index of an item.
55      */
getSpanIndex(View item)56     public static int getSpanIndex(View item) {
57         GridLayoutManager.LayoutParams layoutParams =
58                 ((GridLayoutManager.LayoutParams) item.getLayoutParams());
59         return layoutParams.getSpanIndex();
60     }
61 
62     /**
63      * Returns the span size of an item. {@code item} must be already laid out.
64      */
getSpanSize(View item)65     public static int getSpanSize(View item) {
66         GridLayoutManager.LayoutParams layoutParams =
67                 ((GridLayoutManager.LayoutParams) item.getLayoutParams());
68         return layoutParams.getSpanSize();
69     }
70 
71     /**
72      * Returns the index of the last item that is on the same row as {@code index}.
73      *
74      * @param index index of child {@code View} in {@code parent}.
75      * @param parent {@link RecyclerView} that contains the View {@code index} points to.
76      */
getLastIndexOnSameRow(int index, RecyclerView parent)77     public static int getLastIndexOnSameRow(int index, RecyclerView parent) {
78         int spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
79         int spanSum = GridLayoutManagerUtils.getSpanIndex(parent.getChildAt(index));
80         for (int i = index; i < parent.getChildCount(); i++) {
81             spanSum += GridLayoutManagerUtils.getSpanSize(parent.getChildAt(i));
82             if (spanSum > spanCount) {
83                 // We have reached next row.
84 
85                 // Implicit constraint by grid layout manager:
86                 // Initial spanSum + spanSize would not exceed spanCount, so it's safe to
87                 // subtract 1.
88                 return i - 1;
89             }
90         }
91         // Still have not reached row end. Assuming the list only scrolls vertically, we are at
92         // the last row.
93         return parent.getChildCount() - 1;
94     }
95 }
96