AnimatedRecyclerView.java revision d552f7f491a503efcd1d71c2830a6214a7235c82
152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase/*
252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * Copyright (C) 2014 The Android Open Source Project
352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase *
452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * you may not use this file except in compliance with the License.
652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * You may obtain a copy of the License at
752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase *
852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase *
1052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * Unless required by applicable law or agreed to in writing, software
1152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
1252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * See the License for the specific language governing permissions and
1452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase * limitations under the License.
1552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase */
1652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haasepackage com.example.android.supportv7.widget;
1752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
18ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haaseimport android.support.v4.util.ArrayMap;
1952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.widget.CompoundButton;
2052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport com.example.android.supportv7.R;
2152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.app.Activity;
2252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.content.Context;
2352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.os.Bundle;
2452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.support.v4.view.MenuItemCompat;
2552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.support.v7.widget.RecyclerView;
2652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.util.DisplayMetrics;
2752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.util.TypedValue;
2852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.Menu;
2952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.MenuItem;
3052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.View;
3152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.ViewGroup;
3252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.widget.CheckBox;
3352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.widget.TextView;
3452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
3552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport java.util.ArrayList;
3652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport java.util.HashMap;
3752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport java.util.List;
3852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
3952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haasepublic class AnimatedRecyclerView extends Activity {
4052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private static final int SCROLL_DISTANCE = 80; // dp
4252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private RecyclerView mRecyclerView;
4452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private int mNumItemsAdded = 0;
4652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    ArrayList<String> mItems = new ArrayList<String>();
4752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    MyAdapter mAdapter;
4852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    boolean mAnimationsEnabled = true;
50e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase    boolean mPredictiveAnimationsEnabled = true;
51ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    RecyclerView.ItemAnimator mCachedAnimator = null;
5252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
5352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    @Override
5452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    protected void onCreate(Bundle savedInstanceState) {
5552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        super.onCreate(savedInstanceState);
5652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        setContentView(R.layout.animated_recycler_view);
5752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
5852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        ViewGroup container = (ViewGroup) findViewById(R.id.container);
5952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView = new RecyclerView(this);
60ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        mCachedAnimator = mRecyclerView.getItemAnimator();
6152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setLayoutManager(new MyLayoutManager(this));
6252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setHasFixedSize(true);
6352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
6452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                ViewGroup.LayoutParams.MATCH_PARENT));
6552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        for (int i = 0; i < 6; ++i) {
6652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mItems.add("Item #" + i);
6752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
6852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter = new MyAdapter(mItems);
6952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setAdapter(mAdapter);
7052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        container.addView(mRecyclerView);
7152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
7252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        CheckBox enableAnimations = (CheckBox) findViewById(R.id.enableAnimations);
7352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        enableAnimations.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
7452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            @Override
7552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
76ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                if (isChecked && mRecyclerView.getItemAnimator() == null) {
77ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                    mRecyclerView.setItemAnimator(mCachedAnimator);
78ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                } else if (!isChecked && mRecyclerView.getItemAnimator() != null) {
79ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                    mRecyclerView.setItemAnimator(null);
80ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                }
8152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mAnimationsEnabled = isChecked;
8252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
8352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        });
84e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase
85e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        CheckBox enablePredictiveAnimations =
86e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                (CheckBox) findViewById(R.id.enablePredictiveAnimations);
87e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        enablePredictiveAnimations.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
88e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            @Override
89e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
90e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                mPredictiveAnimationsEnabled = isChecked;
91e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            }
92e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        });
93ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase
94ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        CheckBox enableChangeAnimations =
95ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                (CheckBox) findViewById(R.id.enableChangeAnimations);
96ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        enableChangeAnimations.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
97ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            @Override
98ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
99ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                mCachedAnimator.setSupportsChangeAnimations(isChecked);
100ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            }
101ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        });
10252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
10352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
10452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    @Override
10552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public boolean onCreateOptionsMenu(Menu menu) {
10652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        super.onCreateOptionsMenu(menu);
10752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        MenuItemCompat.setShowAsAction(menu.add("Layout"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
10852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        return true;
10952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
11052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
11152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    @Override
11252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public boolean onOptionsItemSelected(MenuItem item) {
11352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.requestLayout();
11452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        return super.onOptionsItemSelected(item);
11552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
11652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
11752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void checkboxClicked(View view) {
11852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        ViewGroup parent = (ViewGroup) view.getParent();
11952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        boolean selected = ((CheckBox) view).isChecked();
1202a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar        MyViewHolder holder = (MyViewHolder) mRecyclerView.getChildViewHolder(parent);
12152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.selectItem(holder, selected);
12252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
12352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
124ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    public void itemClicked(View view) {
125ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        ViewGroup parent = (ViewGroup) view;
126ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        MyViewHolder holder = (MyViewHolder) mRecyclerView.getChildViewHolder(parent);
127ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        mAdapter.toggleExpanded(holder);
128ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        mAdapter.notifyItemChanged(holder.getPosition());
129ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    }
130ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase
13152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void deleteItem(View view) {
13252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        int numItems = mItems.size();
13352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        if (numItems > 0) {
13452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = numItems - 1; i >= 0; --i) {
13552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                final String itemText = mItems.get(i);
13652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                boolean selected = mAdapter.mSelected.get(itemText);
13752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                if (selected) {
13852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    removeAtPosition(i);
13952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
14052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
14152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
14252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
14352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
14452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private String generateNewText() {
14552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        return "Added Item #" + mNumItemsAdded++;
14652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
14752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
14852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void d1a2d3(View view) {
14952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        removeAtPosition(1);
15052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addAtPosition(2, "Added Item #" + mNumItemsAdded++);
15152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        removeAtPosition(3);
15252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
15352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
15452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private void removeAtPosition(int position) {
15552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mItems.remove(position);
15652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.notifyItemRemoved(position);
15752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
15852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
15952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private void addAtPosition(int position, String text) {
16052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mItems.add(position, text);
16152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.mSelected.put(text, Boolean.FALSE);
162ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        mAdapter.mExpanded.put(text, Boolean.FALSE);
16352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.notifyItemInserted(position);
16452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
16552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
16652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void addDeleteItem(View view) {
16752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addItem(view);
16852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        deleteItem(view);
16952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
17052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
17152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void deleteAddItem(View view) {
17252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        deleteItem(view);
17352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addItem(view);
17452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
17552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
17652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void addItem(View view) {
17752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addAtPosition(3, "Added Item #" + mNumItemsAdded++);
17852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
17952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
18052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    /**
18152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase     * A basic ListView-style LayoutManager.
18252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase     */
18352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    class MyLayoutManager extends RecyclerView.LayoutManager {
18452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private static final String TAG = "MyLayoutManager";
18552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private int mFirstPosition;
18652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private final int mScrollDistance;
18752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
18852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public MyLayoutManager(Context c) {
18952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final DisplayMetrics dm = c.getResources().getDisplayMetrics();
19052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mScrollDistance = (int) (SCROLL_DISTANCE * dm.density + 0.5f);
19152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
19252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
19352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
194e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        public boolean supportsPredictiveItemAnimations() {
195e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            return mPredictiveAnimationsEnabled;
19652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
19752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
19852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
1992a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
20052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int parentBottom = getHeight() - getPaddingBottom();
20152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
20252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final View oldTopView = getChildCount() > 0 ? getChildAt(0) : null;
20352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int oldTop = getPaddingTop();
20452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (oldTopView != null) {
20552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                oldTop = Math.min(oldTopView.getTop(), oldTop);
20652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
20752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
20852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            // Note that we add everything to the scrap, but we do not clean it up;
20952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            // that is handled by the RecyclerView after this method returns
21052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            detachAndScrapAttachedViews(recycler);
21152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
21252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int top = oldTop;
21352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int bottom = top;
21452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int left = getPaddingLeft();
21552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int right = getWidth() - getPaddingRight();
21652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
21752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int count = state.getItemCount();
21852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = 0; mFirstPosition + i < count && top < parentBottom; i++, top = bottom) {
2192a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                View v = recycler.getViewForPosition(mFirstPosition + i);
22052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
22152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) v.getLayoutParams();
222d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                addView(v);
22352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                measureChild(v, 0, 0);
22452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                bottom = top + v.getMeasuredHeight();
22552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                v.layout(left, top, right, bottom);
226e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                if (mPredictiveAnimationsEnabled && params.isItemRemoved()) {
22752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    parentBottom += v.getHeight();
22852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
22952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
23052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
231d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar            if (mAnimationsEnabled && mPredictiveAnimationsEnabled && !state.isPreLayout()) {
232e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // Now that we've run a full layout, figure out which views were not used
233e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // (cached in previousViews). For each of these views, position it where
234e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // it would go, according to its position relative to the visible
235e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // positions in the list. This information will be used by RecyclerView to
236e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // record post-layout positions of these items for the purposes of animating them
237e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // out of view
238e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase
239e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                View lastVisibleView = getChildAt(getChildCount() - 1);
240e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                if (lastVisibleView != null) {
241e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    RecyclerView.LayoutParams lastParams =
242e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                            (RecyclerView.LayoutParams) lastVisibleView.getLayoutParams();
243e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    int lastPosition = lastParams.getViewPosition();
244e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    final List<RecyclerView.ViewHolder> previousViews = recycler.getScrapList();
245e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    count = previousViews.size();
246e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    for (int i = 0; i < count; ++i) {
247e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        View view = previousViews.get(i).itemView;
248e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        RecyclerView.LayoutParams params =
249e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                                (RecyclerView.LayoutParams) view.getLayoutParams();
250d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                        if (params.isItemRemoved()) {
251d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                            continue;
252d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                        }
253e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        int position = params.getViewPosition();
254e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        int newTop;
255e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        if (position < mFirstPosition) {
256e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                            newTop = view.getHeight() * (position - mFirstPosition);
257e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        } else {
258e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                            newTop = lastVisibleView.getTop() + view.getHeight() *
259e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                                    (position - lastPosition);
260e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        }
261e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        view.offsetTopAndBottom(newTop - view.getTop());
26252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
26352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
26452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
26552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
26652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
26752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
26852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
26952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
27052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    ViewGroup.LayoutParams.WRAP_CONTENT);
27152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
27252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
27352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
27452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public boolean canScrollVertically() {
27552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return true;
27652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
27752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
27852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
2792a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
2802a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                RecyclerView.State state) {
28152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (getChildCount() == 0) {
28252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                return 0;
28352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
28452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
28552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int scrolled = 0;
28652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int left = getPaddingLeft();
28752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int right = getWidth() - getPaddingRight();
28852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (dy < 0) {
28952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                while (scrolled > dy) {
29052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final View topView = getChildAt(0);
29152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int hangingTop = Math.max(-topView.getTop(), 0);
29252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int scrollBy = Math.min(scrolled - dy, hangingTop);
29352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    scrolled -= scrollBy;
29452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    offsetChildrenVertical(scrollBy);
29552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (mFirstPosition > 0 && scrolled > dy) {
29652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        mFirstPosition--;
2972a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                        View v = recycler.getViewForPosition(mFirstPosition);
29852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        addView(v, 0);
29952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        measureChild(v, 0, 0);
30052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int bottom = topView.getTop(); // TODO decorated top?
30152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int top = bottom - v.getMeasuredHeight();
30252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        v.layout(left, top, right, bottom);
30352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    } else {
30452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
30552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
30652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
30752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            } else if (dy > 0) {
30852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                final int parentHeight = getHeight();
30952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                while (scrolled < dy) {
31052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final View bottomView = getChildAt(getChildCount() - 1);
31152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int hangingBottom = Math.max(bottomView.getBottom() - parentHeight, 0);
31252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int scrollBy = -Math.min(dy - scrolled, hangingBottom);
31352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    scrolled -= scrollBy;
31452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    offsetChildrenVertical(scrollBy);
3158b38db9f287670f670f631a0ec4b95882cdd0705Yigit Boyar                    if (scrolled < dy && state.getItemCount() > mFirstPosition + getChildCount()) {
3162a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                        View v = recycler.getViewForPosition(mFirstPosition + getChildCount());
31752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int top = getChildAt(getChildCount() - 1).getBottom();
31852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        addView(v);
31952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        measureChild(v, 0, 0);
32052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int bottom = top + v.getMeasuredHeight();
32152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        v.layout(left, top, right, bottom);
32252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    } else {
32352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
32452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
32552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
32652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
32752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            recycleViewsOutOfBounds(recycler);
32852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return scrolled;
32952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
33052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
33152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
33252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public View onFocusSearchFailed(View focused, int direction,
3332a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                RecyclerView.Recycler recycler, RecyclerView.State state) {
33452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int oldCount = getChildCount();
33552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
33652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (oldCount == 0) {
33752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                return null;
33852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
33952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
34052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int left = getPaddingLeft();
34152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int right = getWidth() - getPaddingRight();
34252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
34352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            View toFocus = null;
34452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int newViewsHeight = 0;
34552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (direction == View.FOCUS_UP || direction == View.FOCUS_BACKWARD) {
34652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                while (mFirstPosition > 0 && newViewsHeight < mScrollDistance) {
34752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    mFirstPosition--;
3482a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                    View v = recycler.getViewForPosition(mFirstPosition);
34952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int bottom = getChildAt(0).getTop(); // TODO decorated top?
35052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    addView(v, 0);
35152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    measureChild(v, 0, 0);
35252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int top = bottom - v.getMeasuredHeight();
35352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    v.layout(left, top, right, bottom);
35452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (v.isFocusable()) {
35552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        toFocus = v;
35652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
35752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
35852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
35952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
36052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (direction == View.FOCUS_DOWN || direction == View.FOCUS_FORWARD) {
3618b38db9f287670f670f631a0ec4b95882cdd0705Yigit Boyar                while (mFirstPosition + getChildCount() < state.getItemCount() &&
36252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        newViewsHeight < mScrollDistance) {
3632a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                    View v = recycler.getViewForPosition(mFirstPosition + getChildCount());
36452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int top = getChildAt(getChildCount() - 1).getBottom();
36552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    addView(v);
36652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    measureChild(v, 0, 0);
36752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int bottom = top + v.getMeasuredHeight();
36852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    v.layout(left, top, right, bottom);
36952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (v.isFocusable()) {
37052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        toFocus = v;
37152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
37252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
37352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
37452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
37552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
37652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return toFocus;
37752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
37852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
37952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void recycleViewsOutOfBounds(RecyclerView.Recycler recycler) {
38052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int childCount = getChildCount();
38152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int parentWidth = getWidth();
38252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int parentHeight = getHeight();
38352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            boolean foundFirst = false;
38452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int first = 0;
38552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int last = 0;
38652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = 0; i < childCount; i++) {
38752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                final View v = getChildAt(i);
38852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                if (v.hasFocus() || (v.getRight() >= 0 && v.getLeft() <= parentWidth &&
38952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        v.getBottom() >= 0 && v.getTop() <= parentHeight)) {
39052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (!foundFirst) {
39152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        first = i;
39252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        foundFirst = true;
39352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
39452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    last = i;
39552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
39652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
39752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = childCount - 1; i > last; i--) {
39852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                removeAndRecycleViewAt(i, recycler);
39952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
40052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = first - 1; i >= 0; i--) {
40152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                removeAndRecycleViewAt(i, recycler);
40252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
40352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (getChildCount() == 0) {
40452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition = 0;
40552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            } else {
40652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition += first;
40752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
40852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
40952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
41052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
41152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
41252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (positionStart < mFirstPosition) {
41352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition += itemCount;
41452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
41552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
41652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
41752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
41852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
41952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (positionStart < mFirstPosition) {
42052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition -= itemCount;
42152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
42252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
42352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
42452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
42552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    class MyAdapter extends RecyclerView.Adapter {
42652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private int mBackground;
42752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        List<String> mData;
428ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        ArrayMap<String, Boolean> mSelected = new ArrayMap<String, Boolean>();
429ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        ArrayMap<String, Boolean> mExpanded = new ArrayMap<String, Boolean>();
43052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
43152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public MyAdapter(List<String> data) {
43252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            TypedValue val = new TypedValue();
43352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            AnimatedRecyclerView.this.getTheme().resolveAttribute(
43452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    R.attr.selectableItemBackground, val, true);
43552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mBackground = val.resourceId;
43652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mData = data;
43752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (String itemText : mData) {
43852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mSelected.put(itemText, Boolean.FALSE);
439ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                mExpanded.put(itemText, Boolean.FALSE);
44052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
44152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
44252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
44352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
44452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
44552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            MyViewHolder h = new MyViewHolder(getLayoutInflater().inflate(R.layout.selectable_item,
44652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    null));
44752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            h.textView.setMinimumHeight(128);
44852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            h.textView.setFocusable(true);
44952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            h.textView.setBackgroundResource(mBackground);
45052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return h;
45152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
45252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
45352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
45452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
45552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            String itemText = mData.get(position);
45652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            ((MyViewHolder) holder).textView.setText(itemText);
457ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            ((MyViewHolder) holder).expandedText.setText("More text for the expanded version");
45852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            boolean selected = false;
45952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (mSelected.get(itemText) != null) {
46052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                selected = mSelected.get(itemText);
46152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
46252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            ((MyViewHolder) holder).checkBox.setChecked(selected);
463ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            Boolean expanded = mExpanded.get(itemText);
464ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            if (expanded != null && expanded) {
465ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                ((MyViewHolder) holder).expandedText.setVisibility(View.VISIBLE);
466ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                ((MyViewHolder) holder).textView.setVisibility(View.GONE);
467ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            } else {
468ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                ((MyViewHolder) holder).expandedText.setVisibility(View.GONE);
469ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                ((MyViewHolder) holder).textView.setVisibility(View.VISIBLE);
470ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            }
47152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
47252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
47352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
47452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public int getItemCount() {
47552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return mData.size();
47652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
47752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
47852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void selectItem(String itemText, boolean selected) {
47952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mSelected.put(itemText, selected);
48052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
48152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
48252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void selectItem(MyViewHolder holder, boolean selected) {
48352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mSelected.put((String) holder.textView.getText(), selected);
48452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
485ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase
486ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        public void toggleExpanded(MyViewHolder holder) {
487ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            String text = (String) holder.textView.getText();
488ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            mExpanded.put(text, !mExpanded.get(text));
489ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        }
49052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
49152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
49252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    static class MyViewHolder extends RecyclerView.ViewHolder {
493ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        public TextView expandedText;
49452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public TextView textView;
49552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public CheckBox checkBox;
49652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
49752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public MyViewHolder(View v) {
49852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            super(v);
499ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            expandedText = (TextView) v.findViewById(R.id.expandedText);
50052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            textView = (TextView) v.findViewById(R.id.text);
50152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            checkBox = (CheckBox) v.findViewById(R.id.selected);
50252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
50352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
50452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
50552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public String toString() {
50652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return super.toString() + " \"" + textView.getText() + "\"";
50752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
508ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    }
509ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase}
510