ListRowDataAdapter.java revision b3756c53c5be55e8c8a2f6e2cda264407be84881
1package android.support.v17.leanback.app;
2
3import android.support.v17.leanback.widget.DividerRow;
4import android.support.v17.leanback.widget.ListRow;
5import android.support.v17.leanback.widget.ObjectAdapter;
6import android.support.v17.leanback.widget.Row;
7
8/**
9 * Wrapper class for {@link ObjectAdapter} used by {@link BrowseFragment} to initialize
10 * {@link RowsFragment}. We use invisible rows to represent
11 * {@link android.support.v17.leanback.widget.DividerRow},
12 * {@link android.support.v17.leanback.widget.SectionRow} and
13 * {@link android.support.v17.leanback.widget.PageRow} in RowsFragment. In case we have an
14 * invisible row at the end of a RowsFragment, it creates a jumping effect as the layout manager
15 * thinks there are items even though they're invisible. This class takes care of filtering out
16 * the invisible rows at the end. In case the data inside the adapter changes, it adjusts the
17 * bounds to reflect the latest data.
18 */
19class ListRowDataAdapter extends ObjectAdapter {
20    private final ObjectAdapter mAdapter;
21    private int mLastVisibleRowIndex;
22
23    public ListRowDataAdapter(ObjectAdapter adapter) {
24        super(adapter.getPresenterSelector());
25        this.mAdapter = adapter;
26        initialize();
27        mAdapter.registerObserver(new DataObserver() {
28
29            @Override
30            public void onItemRangeChanged(int positionStart, int itemCount) {
31                initialize();
32                notifyItemRangeChanged(positionStart, itemCount);
33            }
34
35            @Override
36            public void onItemRangeInserted(int positionStart, int itemCount) {
37                Row item = (Row) mAdapter.get(mLastVisibleRowIndex);
38                boolean isLastRowNonVisible = (item instanceof DividerRow);
39                initialize();
40
41                boolean hasVisibleRow = hasVisibleRow(positionStart);
42                if (positionStart >= mLastVisibleRowIndex
43                        && isLastRowNonVisible
44                        && hasVisibleRow) {
45                    positionStart--;
46                    itemCount++;
47                }
48                notifyItemRangeInserted(positionStart, itemCount);
49            }
50
51            @Override
52            public void onItemRangeRemoved(int positionStart, int itemCount) {
53                Row item = (Row) mAdapter.get(mLastVisibleRowIndex);
54                boolean isLastRowNonVisible = (item instanceof DividerRow);
55                initialize();
56
57                if (positionStart + itemCount >= mLastVisibleRowIndex && isLastRowNonVisible) {
58                    itemCount--;
59                }
60                notifyItemRangeRemoved(positionStart, itemCount);
61            }
62
63            @Override
64            public void onChanged() {
65                initialize();
66                notifyChanged();
67            }
68        });
69    }
70
71    private boolean hasVisibleRow(int startIndex) {
72        for (int i = startIndex; i < Math.min(mLastVisibleRowIndex, mAdapter.size()); i++) {
73            Row item = (Row) mAdapter.get(i);
74            if (item instanceof ListRow) {
75                return true;
76            }
77        }
78        return false;
79    }
80
81    private void initialize() {
82        int i = 0;
83        while (i < mAdapter.size()) {
84            Row item = (Row) mAdapter.get(i);
85            if (item.isRenderedAsRowView()) {
86                break;
87            }
88            i++;
89        }
90
91        i = mAdapter.size() - 1;
92        while (i >= 0) {
93            Row item = (Row) mAdapter.get(i);
94            if (item.isRenderedAsRowView()) {
95                mLastVisibleRowIndex = i;
96                break;
97            }
98            i--;
99        }
100    }
101
102    @Override
103    public int size() {
104        return mLastVisibleRowIndex + 1;
105    }
106
107    @Override
108    public Object get(int index) {
109        return mAdapter.get(index);
110    }
111}