RecyclerViewActivity.java revision 549b58504ef397f4c1524ec370bbd0569027e315
1f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell/*
2f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * Copyright (C) 2013 The Android Open Source Project
3f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell *
4f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * you may not use this file except in compliance with the License.
6f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * You may obtain a copy of the License at
7f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell *
8f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell *
10f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * Unless required by applicable law or agreed to in writing, software
11f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * See the License for the specific language governing permissions and
14f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell * limitations under the License.
15f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell */
16f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
17f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
18f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellpackage com.example.android.supportv7.widget;
19f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
20f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.R;
21f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.app.Activity;
22f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.content.Context;
23f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.graphics.Rect;
24f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.os.Bundle;
25f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.support.v4.view.MenuItemCompat;
26f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.support.v7.widget.RecyclerView;
27f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.util.DisplayMetrics;
28f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.util.TypedValue;
29f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.view.Menu;
30f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.view.MenuItem;
31f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.view.View;
32f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.view.ViewGroup;
33f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.view.View.MeasureSpec;
34f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellimport android.widget.TextView;
35549b58504ef397f4c1524ec370bbd0569027e315Adam Powellimport com.example.android.supportv7.Cheeses;
36549b58504ef397f4c1524ec370bbd0569027e315Adam Powell
37549b58504ef397f4c1524ec370bbd0569027e315Adam Powellimport java.util.ArrayList;
38549b58504ef397f4c1524ec370bbd0569027e315Adam Powellimport java.util.Collections;
39f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
40f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powellpublic class RecyclerViewActivity extends Activity {
41f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    private RecyclerView mRecyclerView;
42f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
43f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    @Override
44f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    protected void onCreate(Bundle savedInstanceState) {
45f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        super.onCreate(savedInstanceState);
46f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
47f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        final RecyclerView rv = new RecyclerView(this);
48f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        rv.setLayoutManager(new MyLayoutManager(this));
49f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        rv.setHasFixedSize(true);
50f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        rv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
51f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                ViewGroup.LayoutParams.MATCH_PARENT));
52549b58504ef397f4c1524ec370bbd0569027e315Adam Powell        rv.setAdapter(new MyAdapter(Cheeses.sCheeseStrings));
53f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        setContentView(rv);
54f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
55f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        mRecyclerView = rv;
56f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    }
57f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
58f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    @Override
59f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    public boolean onCreateOptionsMenu(Menu menu) {
60f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        super.onCreateOptionsMenu(menu);
61f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        MenuItemCompat.setShowAsAction(menu.add("Layout"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
62f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        return true;
63f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    }
64f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
65f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    @Override
66f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    public boolean onOptionsItemSelected(MenuItem item) {
67f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        mRecyclerView.requestLayout();
68f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        return super.onOptionsItemSelected(item);
69f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    }
70f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
71f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    private static final int SCROLL_DISTANCE = 80; // dp
72f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
73f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    /**
74f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell     * A basic ListView-style LayoutManager.
75f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell     */
76f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    class MyLayoutManager extends RecyclerView.LayoutManager {
77f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        private static final String TAG = "MyLayoutManager";
78f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        private int mFirstPosition;
79f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        private final int mScrollDistance;
80f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
81f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public MyLayoutManager(Context c) {
82f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final DisplayMetrics dm = c.getResources().getDisplayMetrics();
83f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            mScrollDistance = (int) (SCROLL_DISTANCE * dm.density + 0.5f);
84f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
85f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
86f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
87f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public void layoutChildren(RecyclerView.Adapter adapter, RecyclerView.Recycler recycler) {
88f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final RecyclerView parent = getRecyclerView();
89f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
90f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
91549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            final View oldTopView = parent.getChildCount() > 0 ? parent.getChildAt(0) : null;
92549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            int oldTop = parent.getPaddingTop();
93549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            if (oldTopView != null) {
94549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                oldTop = oldTopView.getTop();
95549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            }
96549b58504ef397f4c1524ec370bbd0569027e315Adam Powell
97f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            recycler.scrapAllViewsAttached();
98f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
99549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            int top = oldTop;
100f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            int bottom;
101f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int left = parent.getPaddingLeft();
102f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int right = parent.getWidth() - parent.getPaddingRight();
103f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
104f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int count = adapter.getItemCount();
105f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            for (int i = 0; mFirstPosition + i < count && top < parentBottom; i++, top = bottom) {
106f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                View v = recycler.getViewForPosition(mFirstPosition + i);
107f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                addView(v, i);
108f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                v.measure(MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY),
109f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
110f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                bottom = top + v.getMeasuredHeight();
111f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                v.layout(left, top, right, bottom);
112f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
113f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
114f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            recycler.detachDirtyScrapViews();
115f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
116f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
117f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
118f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
119f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
120f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    ViewGroup.LayoutParams.WRAP_CONTENT);
121f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
122f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
123f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
124f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public boolean canScrollVertically() {
125f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            return true;
126f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
127f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
128f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
129f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler) {
130f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final RecyclerView parent = getRecyclerView();
131f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            if (parent.getChildCount() == 0) {
132f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                return 0;
133f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
134f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
135f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            int scrolled = 0;
136f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int left = parent.getPaddingLeft();
137f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int right = parent.getWidth() - parent.getPaddingRight();
138f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            if (dy < 0) {
139f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                while (scrolled > dy) {
140f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final View topView = parent.getChildAt(0);
141f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int hangingTop = Math.max(-topView.getTop(), 0);
142f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int scrollBy = Math.min(scrolled - dy, hangingTop);
143f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    scrolled -= scrollBy;
144f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    parent.offsetChildrenVertical(scrollBy);
145f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    if (mFirstPosition > 0 && scrolled > dy) {
146f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        mFirstPosition--;
147f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        View v = recycler.getViewForPosition(mFirstPosition);
148f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        addView(v, 0);
149f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        v.measure(MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY),
150f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
151f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        final int bottom = topView.getTop(); // TODO decorated top?
152f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        final int top = bottom - v.getMeasuredHeight();
153f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        v.layout(left, top, right, bottom);
154f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    } else {
155f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        break;
156f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    }
157f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                }
158f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            } else if (dy > 0) {
159f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                final int parentHeight = parent.getHeight();
160f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                while (scrolled < dy) {
161f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final View bottomView = parent.getChildAt(parent.getChildCount() - 1);
162f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int hangingBottom = Math.max(bottomView.getBottom() - parentHeight, 0);
163f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int scrollBy = -Math.min(dy - scrolled, hangingBottom);
164f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    scrolled -= scrollBy;
165f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    parent.offsetChildrenVertical(scrollBy);
166f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    if (scrolled < dy &&
167f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                            parent.getAdapter().getItemCount() > mFirstPosition + parent.getChildCount()) {
168f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        View v = recycler.getViewForPosition(
169f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                                mFirstPosition + parent.getChildCount());
170f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        final int top = parent.getChildAt(parent.getChildCount() - 1).getBottom();
171f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        addView(v);
172f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        v.measure(MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY),
173f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
174f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        final int bottom = top + v.getMeasuredHeight();
175f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        v.layout(left, top, right, bottom);
176f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    } else {
177f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        break;
178f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    }
179f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                }
180f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
181f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            detachAndScrapViewsOutOfBounds(recycler);
182f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            return scrolled;
183f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
184f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
185f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
186f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public View onFocusSearchFailed(View focused, int direction,
187f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                RecyclerView.Recycler recycler) {
188f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final RecyclerView rv = getRecyclerView();
189f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int oldFirstPosition = mFirstPosition;
190f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int oldCount = rv.getChildCount();
191f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
192f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            if (oldCount == 0) {
193f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                return null;
194f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
195f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
196f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int left = rv.getPaddingLeft();
197f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int right = rv.getWidth() - rv.getPaddingRight();
198f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
199f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            View toFocus = null;
200f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            int newViewsHeight = 0;
201f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            if (direction == View.FOCUS_UP || direction == View.FOCUS_BACKWARD) {
202f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                while (mFirstPosition > 0 && newViewsHeight < mScrollDistance) {
203f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    mFirstPosition--;
204f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    View v = recycler.getViewForPosition(mFirstPosition);
205f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int bottom = rv.getChildAt(0).getTop(); // TODO decorated top?
206f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    addView(v, 0);
207f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    v.measure(MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY),
208f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
209f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int top = bottom - v.getMeasuredHeight();
210f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    v.layout(left, top, right, bottom);
211f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    if (v.isFocusable()) {
212f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        toFocus = v;
213f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        break;
214f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    }
215f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                }
216f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
217f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            if (direction == View.FOCUS_DOWN || direction == View.FOCUS_FORWARD) {
218f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                while (mFirstPosition + rv.getChildCount() < rv.getAdapter().getItemCount() &&
219f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        newViewsHeight < mScrollDistance) {
220f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    View v = recycler.getViewForPosition(mFirstPosition + rv.getChildCount());
221f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int top = rv.getChildAt(rv.getChildCount() - 1).getBottom();
222f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    addView(v);
223f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    v.measure(MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY),
224f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
225f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    final int bottom = top + v.getMeasuredHeight();
226f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    v.layout(left, top, right, bottom);
227f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    if (v.isFocusable()) {
228f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        toFocus = v;
229f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        break;
230f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    }
231f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                }
232f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
233f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
234f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            return toFocus;
235f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
236f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
237f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public void detachAndScrapViewsOutOfBounds(RecyclerView.Recycler recycler) {
238f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final RecyclerView parent = getRecyclerView();
239f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int childCount = parent.getChildCount();
240f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int parentWidth = parent.getWidth();
241f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            final int parentHeight = parent.getHeight();
242f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            boolean foundFirst = false;
243f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            int first = 0;
244f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            int last = 0;
245f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            for (int i = 0; i < childCount; i++) {
246f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                final View v = parent.getChildAt(i);
247f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                if (v.hasFocus() || (v.getRight() >= 0 && v.getLeft() <= parentWidth &&
248f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        v.getBottom() >= 0 && v.getTop() <= parentHeight)) {
249f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    if (!foundFirst) {
250f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        first = i;
251f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                        foundFirst = true;
252f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    }
253f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    last = i;
254f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                }
255f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
256f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            for (int i = childCount - 1; i > last; i--) {
257f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                recycler.detachAndScrapView(parent.getChildAt(i));
258f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
259f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            for (int i = 0; i < first; i++) {
260f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                recycler.detachAndScrapView(parent.getChildAt(i));
261f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
262f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            if (parent.getChildCount() == 0) {
263f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                mFirstPosition = 0;
264f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            } else {
265f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                mFirstPosition += first;
266f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            }
267f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
268f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    }
269f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
270f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    class MyAdapter extends RecyclerView.Adapter {
271f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        private int mBackground;
272549b58504ef397f4c1524ec370bbd0569027e315Adam Powell        private ArrayList<String> mValues;
273f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
274549b58504ef397f4c1524ec370bbd0569027e315Adam Powell        public MyAdapter(String[] strings) {
275f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            TypedValue val = new TypedValue();
276f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            RecyclerViewActivity.this.getTheme().resolveAttribute(
277f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell                    R.attr.selectableItemBackground, val, true);
278f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            mBackground = val.resourceId;
279549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            mValues = new ArrayList();
280549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            Collections.addAll(mValues, strings);
281f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
282f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
283f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
284f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public RecyclerView.ViewHolder createViewHolder(ViewGroup parent, int viewType) {
285549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            final ViewHolder h = new ViewHolder(new TextView(RecyclerViewActivity.this));
286f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            h.textView.setMinimumHeight(128);
287f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            h.textView.setFocusable(true);
288f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            h.textView.setBackgroundResource(mBackground);
289549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            h.textView.setOnClickListener(new View.OnClickListener() {
290549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                @Override
291549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                public void onClick(View v) {
292549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                    final int pos = h.getPosition();
293549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                    if (mValues.size() > pos + 1) {
294549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                        final String t = mValues.get(pos);
295549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                        mValues.set(pos, mValues.get(pos + 1));
296549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                        mValues.set(pos + 1, t);
297549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                        notifyDataSetChanged();
298549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                    }
299549b58504ef397f4c1524ec370bbd0569027e315Adam Powell                }
300549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            });
301f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            return h;
302f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
303f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
304f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
305f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public void bindViewHolder(RecyclerView.ViewHolder holder, int position) {
306549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            ((ViewHolder) holder).textView.setText(mValues.get(position));
307f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
308f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
309f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        @Override
310f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public int getItemCount() {
311549b58504ef397f4c1524ec370bbd0569027e315Adam Powell            return mValues.size();
312f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
313f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    }
314f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
315f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    static class ViewHolder extends RecyclerView.ViewHolder {
316f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public TextView textView;
317f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell
318f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        public ViewHolder(TextView v) {
319f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            super(v);
320f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell            textView = v;
321f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell        }
322f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell    }
323f6c36bb9b61083b25397a6cff82ddbb102cacfbdAdam Powell}
324