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
1852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport com.example.android.supportv7.R;
19413444125c69c7071767b1bac60d4d857097abccYigit Boyar
20413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.animation.Animator;
21413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.animation.ValueAnimator;
22413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.annotation.TargetApi;
2352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.app.Activity;
2452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.content.Context;
25413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.os.Build;
2652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.os.Bundle;
27413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.support.v4.util.ArrayMap;
2852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.support.v4.view.MenuItemCompat;
29413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.support.v4.view.ViewCompat;
30413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.support.v4.view.ViewPropertyAnimatorListener;
31413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.support.v7.widget.DefaultItemAnimator;
3252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.support.v7.widget.RecyclerView;
3352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.util.DisplayMetrics;
3452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.util.TypedValue;
3552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.Menu;
3652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.MenuItem;
3752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.View;
3852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.view.ViewGroup;
3952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.widget.CheckBox;
40413444125c69c7071767b1bac60d4d857097abccYigit Boyarimport android.widget.CompoundButton;
4152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport android.widget.TextView;
4252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport java.util.ArrayList;
4452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haaseimport java.util.List;
4552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haasepublic class AnimatedRecyclerView extends Activity {
4752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
4852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private static final int SCROLL_DISTANCE = 80; // dp
4952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
5052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private RecyclerView mRecyclerView;
5152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
5252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private int mNumItemsAdded = 0;
5352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    ArrayList<String> mItems = new ArrayList<String>();
5452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    MyAdapter mAdapter;
5552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
5652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    boolean mAnimationsEnabled = true;
57e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase    boolean mPredictiveAnimationsEnabled = true;
58ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    RecyclerView.ItemAnimator mCachedAnimator = null;
59413444125c69c7071767b1bac60d4d857097abccYigit Boyar    boolean mEnableInPlaceChange = true;
6052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
6152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    @Override
6252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    protected void onCreate(Bundle savedInstanceState) {
6352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        super.onCreate(savedInstanceState);
6452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        setContentView(R.layout.animated_recycler_view);
6552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
6652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        ViewGroup container = (ViewGroup) findViewById(R.id.container);
6752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView = new RecyclerView(this);
68413444125c69c7071767b1bac60d4d857097abccYigit Boyar        mCachedAnimator = createAnimator();
69413444125c69c7071767b1bac60d4d857097abccYigit Boyar        mCachedAnimator.setChangeDuration(2000);
70413444125c69c7071767b1bac60d4d857097abccYigit Boyar        mRecyclerView.setItemAnimator(mCachedAnimator);
7152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setLayoutManager(new MyLayoutManager(this));
7252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setHasFixedSize(true);
7352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
7452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                ViewGroup.LayoutParams.MATCH_PARENT));
7552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        for (int i = 0; i < 6; ++i) {
7652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mItems.add("Item #" + i);
7752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
7852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter = new MyAdapter(mItems);
7952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.setAdapter(mAdapter);
8052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        container.addView(mRecyclerView);
8152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
8252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        CheckBox enableAnimations = (CheckBox) findViewById(R.id.enableAnimations);
8352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        enableAnimations.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
8452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            @Override
8552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
86ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                if (isChecked && mRecyclerView.getItemAnimator() == null) {
87ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                    mRecyclerView.setItemAnimator(mCachedAnimator);
88ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                } else if (!isChecked && mRecyclerView.getItemAnimator() != null) {
89ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                    mRecyclerView.setItemAnimator(null);
90ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                }
9152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mAnimationsEnabled = isChecked;
9252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
9352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        });
94e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase
95e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        CheckBox enablePredictiveAnimations =
96e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                (CheckBox) findViewById(R.id.enablePredictiveAnimations);
97e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        enablePredictiveAnimations.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
98e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            @Override
99e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
100e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                mPredictiveAnimationsEnabled = isChecked;
101e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            }
102e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        });
103ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase
104413444125c69c7071767b1bac60d4d857097abccYigit Boyar        CheckBox enableInPlaceChange = (CheckBox) findViewById(R.id.enableInPlaceChange);
105413444125c69c7071767b1bac60d4d857097abccYigit Boyar        enableInPlaceChange.setChecked(mEnableInPlaceChange);
106413444125c69c7071767b1bac60d4d857097abccYigit Boyar        enableInPlaceChange.setOnCheckedChangeListener(
107413444125c69c7071767b1bac60d4d857097abccYigit Boyar                new CompoundButton.OnCheckedChangeListener() {
108413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    @Override
109413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
110413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        mEnableInPlaceChange = isChecked;
111413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    }
112413444125c69c7071767b1bac60d4d857097abccYigit Boyar                });
113413444125c69c7071767b1bac60d4d857097abccYigit Boyar    }
114413444125c69c7071767b1bac60d4d857097abccYigit Boyar
115413444125c69c7071767b1bac60d4d857097abccYigit Boyar    private RecyclerView.ItemAnimator createAnimator() {
116413444125c69c7071767b1bac60d4d857097abccYigit Boyar        return new DefaultItemAnimator() {
117413444125c69c7071767b1bac60d4d857097abccYigit Boyar            List<ItemChangeAnimator> mPendingChangeAnimations = new ArrayList<>();
118413444125c69c7071767b1bac60d4d857097abccYigit Boyar            ArrayMap<RecyclerView.ViewHolder, ItemChangeAnimator> mRunningAnimations
119413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    = new ArrayMap<>();
120413444125c69c7071767b1bac60d4d857097abccYigit Boyar            ArrayMap<MyViewHolder, Long> mPendingSettleList = new ArrayMap<>();
121413444125c69c7071767b1bac60d4d857097abccYigit Boyar
122ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            @Override
123413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public void runPendingAnimations() {
124413444125c69c7071767b1bac60d4d857097abccYigit Boyar                super.runPendingAnimations();
125413444125c69c7071767b1bac60d4d857097abccYigit Boyar                for (ItemChangeAnimator anim : mPendingChangeAnimations) {
126413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    anim.start();
127413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    mRunningAnimations.put(anim.mViewHolder, anim);
128413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
129413444125c69c7071767b1bac60d4d857097abccYigit Boyar                mPendingChangeAnimations.clear();
130413444125c69c7071767b1bac60d4d857097abccYigit Boyar                for (int i = mPendingSettleList.size() - 1; i >=0; i--) {
131413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    final MyViewHolder vh = mPendingSettleList.keyAt(i);
132413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    final long duration = mPendingSettleList.valueAt(i);
133413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    ViewCompat.animate(vh.textView).translationX(0f).alpha(1f)
134413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            .setDuration(duration).setListener(
135413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            new ViewPropertyAnimatorListener() {
136413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                @Override
137413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                public void onAnimationStart(View view) {
138413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                    dispatchAnimationStarted(vh);
139413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                }
140413444125c69c7071767b1bac60d4d857097abccYigit Boyar
141413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                @Override
142413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                public void onAnimationEnd(View view) {
143413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                    ViewCompat.setTranslationX(vh.textView, 0f);
144413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                    ViewCompat.setAlpha(vh.textView, 1f);
145413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                    dispatchAnimationFinished(vh);
146413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                }
147413444125c69c7071767b1bac60d4d857097abccYigit Boyar
148413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                @Override
149413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                public void onAnimationCancel(View view) {
150413444125c69c7071767b1bac60d4d857097abccYigit Boyar
151413444125c69c7071767b1bac60d4d857097abccYigit Boyar                                }
152413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            }).start();
153413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
154413444125c69c7071767b1bac60d4d857097abccYigit Boyar                mPendingSettleList.clear();
155ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            }
156413444125c69c7071767b1bac60d4d857097abccYigit Boyar
157413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @Override
158413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public ItemHolderInfo recordPreLayoutInformation(RecyclerView.State state,
159413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    RecyclerView.ViewHolder viewHolder,
160413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    @AdapterChanges int changeFlags, List<Object> payloads) {
161413444125c69c7071767b1bac60d4d857097abccYigit Boyar                MyItemInfo info = (MyItemInfo) super
162413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        .recordPreLayoutInformation(state, viewHolder, changeFlags, payloads);
163413444125c69c7071767b1bac60d4d857097abccYigit Boyar                info.text = ((MyViewHolder) viewHolder).textView.getText();
164413444125c69c7071767b1bac60d4d857097abccYigit Boyar                return info;
165413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
166413444125c69c7071767b1bac60d4d857097abccYigit Boyar
167413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @Override
168413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public ItemHolderInfo recordPostLayoutInformation(RecyclerView.State state,
169413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    RecyclerView.ViewHolder viewHolder) {
170413444125c69c7071767b1bac60d4d857097abccYigit Boyar                MyItemInfo info = (MyItemInfo) super.recordPostLayoutInformation(state, viewHolder);
171413444125c69c7071767b1bac60d4d857097abccYigit Boyar                info.text = ((MyViewHolder) viewHolder).textView.getText();
172413444125c69c7071767b1bac60d4d857097abccYigit Boyar                return info;
173413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
174413444125c69c7071767b1bac60d4d857097abccYigit Boyar
175413444125c69c7071767b1bac60d4d857097abccYigit Boyar
176413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @Override
177413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
178413444125c69c7071767b1bac60d4d857097abccYigit Boyar                return mEnableInPlaceChange;
179413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
180413444125c69c7071767b1bac60d4d857097abccYigit Boyar
181413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @Override
182413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public void endAnimation(RecyclerView.ViewHolder item) {
183413444125c69c7071767b1bac60d4d857097abccYigit Boyar                super.endAnimation(item);
184413444125c69c7071767b1bac60d4d857097abccYigit Boyar                for (int i = mPendingChangeAnimations.size() - 1; i >= 0; i--) {
185413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    ItemChangeAnimator anim = mPendingChangeAnimations.get(i);
186413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    if (anim.mViewHolder == item) {
187413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        mPendingChangeAnimations.remove(i);
188413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        anim.setFraction(1f);
189413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        dispatchChangeFinished(item, true);
190413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    }
191413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
192413444125c69c7071767b1bac60d4d857097abccYigit Boyar                for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
193413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    ItemChangeAnimator animator = mRunningAnimations.get(item);
194413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    if (animator != null) {
195413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        animator.end();
196413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        mRunningAnimations.removeAt(i);
197413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    }
198413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
199413444125c69c7071767b1bac60d4d857097abccYigit Boyar                for (int  i = mPendingSettleList.size() - 1; i >= 0; i--) {
200413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    final MyViewHolder vh = mPendingSettleList.keyAt(i);
201413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    if (vh == item) {
202413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        mPendingSettleList.removeAt(i);
203413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        dispatchChangeFinished(item, true);
204413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    }
205413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
206413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
207413444125c69c7071767b1bac60d4d857097abccYigit Boyar
208413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @Override
209413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public boolean animateChange(RecyclerView.ViewHolder oldHolder,
210413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    RecyclerView.ViewHolder newHolder, ItemHolderInfo preInfo,
211413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    ItemHolderInfo postInfo) {
212413444125c69c7071767b1bac60d4d857097abccYigit Boyar                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1
213413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        || oldHolder != newHolder) {
214413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
215413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
216413444125c69c7071767b1bac60d4d857097abccYigit Boyar                return animateChangeApiHoneycombMr1(oldHolder, newHolder, preInfo, postInfo);
217413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
218413444125c69c7071767b1bac60d4d857097abccYigit Boyar
219413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
220413444125c69c7071767b1bac60d4d857097abccYigit Boyar            private boolean animateChangeApiHoneycombMr1(RecyclerView.ViewHolder oldHolder,
221413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    RecyclerView.ViewHolder newHolder,
222413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    ItemHolderInfo preInfo, ItemHolderInfo postInfo) {
223413444125c69c7071767b1bac60d4d857097abccYigit Boyar                endAnimation(oldHolder);
224413444125c69c7071767b1bac60d4d857097abccYigit Boyar                MyItemInfo pre = (MyItemInfo) preInfo;
225413444125c69c7071767b1bac60d4d857097abccYigit Boyar                MyItemInfo post = (MyItemInfo) postInfo;
226413444125c69c7071767b1bac60d4d857097abccYigit Boyar                MyViewHolder vh = (MyViewHolder) oldHolder;
227413444125c69c7071767b1bac60d4d857097abccYigit Boyar
228413444125c69c7071767b1bac60d4d857097abccYigit Boyar                CharSequence finalText = post.text;
229413444125c69c7071767b1bac60d4d857097abccYigit Boyar
230413444125c69c7071767b1bac60d4d857097abccYigit Boyar                if (pre.text.equals(post.text)) {
231413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    // same content. Just translate back to 0
232413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    final long duration = (long) (getChangeDuration()
233413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            * (ViewCompat.getTranslationX(vh.textView) / vh.textView.getWidth()));
234413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    mPendingSettleList.put(vh, duration);
235413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    // we set it here because previous endAnimation would set it to other value.
236413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    vh.textView.setText(finalText);
237413444125c69c7071767b1bac60d4d857097abccYigit Boyar                } else {
238413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    // different content, get out and come back.
239413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    vh.textView.setText(pre.text);
240413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    final ItemChangeAnimator anim = new ItemChangeAnimator(vh, finalText,
241413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            getChangeDuration()) {
242413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        @Override
243413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        public void onAnimationEnd(Animator animation) {
244413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            setFraction(1f);
245413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            dispatchChangeFinished(mViewHolder, true);
246413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        }
247413444125c69c7071767b1bac60d4d857097abccYigit Boyar
248413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        @Override
249413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        public void onAnimationStart(Animator animation) {
250413444125c69c7071767b1bac60d4d857097abccYigit Boyar                            dispatchChangeStarting(mViewHolder, true);
251413444125c69c7071767b1bac60d4d857097abccYigit Boyar                        }
252413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    };
253413444125c69c7071767b1bac60d4d857097abccYigit Boyar                    mPendingChangeAnimations.add(anim);
254413444125c69c7071767b1bac60d4d857097abccYigit Boyar                }
255413444125c69c7071767b1bac60d4d857097abccYigit Boyar                return true;
256413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
257413444125c69c7071767b1bac60d4d857097abccYigit Boyar
258413444125c69c7071767b1bac60d4d857097abccYigit Boyar            @Override
259413444125c69c7071767b1bac60d4d857097abccYigit Boyar            public ItemHolderInfo obtainHolderInfo() {
260413444125c69c7071767b1bac60d4d857097abccYigit Boyar                return new MyItemInfo();
261413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
262413444125c69c7071767b1bac60d4d857097abccYigit Boyar        };
263413444125c69c7071767b1bac60d4d857097abccYigit Boyar    }
264413444125c69c7071767b1bac60d4d857097abccYigit Boyar
265413444125c69c7071767b1bac60d4d857097abccYigit Boyar
266413444125c69c7071767b1bac60d4d857097abccYigit Boyar    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
267413444125c69c7071767b1bac60d4d857097abccYigit Boyar    abstract private static class ItemChangeAnimator implements
268413444125c69c7071767b1bac60d4d857097abccYigit Boyar            ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
269413444125c69c7071767b1bac60d4d857097abccYigit Boyar        CharSequence mFinalText;
270413444125c69c7071767b1bac60d4d857097abccYigit Boyar        ValueAnimator mValueAnimator;
271413444125c69c7071767b1bac60d4d857097abccYigit Boyar        MyViewHolder mViewHolder;
272413444125c69c7071767b1bac60d4d857097abccYigit Boyar        final float mMaxX;
273413444125c69c7071767b1bac60d4d857097abccYigit Boyar        final float mStartRatio;
274413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public ItemChangeAnimator(MyViewHolder viewHolder, CharSequence finalText, long duration) {
275413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mViewHolder = viewHolder;
276413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mMaxX = mViewHolder.itemView.getWidth();
277413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mStartRatio = ViewCompat.getTranslationX(mViewHolder.textView) / mMaxX;
278413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mFinalText = finalText;
279413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator = ValueAnimator.ofFloat(0f, 1f);
280413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator.addUpdateListener(this);
281413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator.addListener(this);
282413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator.setDuration(duration);
283413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator.setTarget(mViewHolder.itemView);
284413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
285413444125c69c7071767b1bac60d4d857097abccYigit Boyar
286413444125c69c7071767b1bac60d4d857097abccYigit Boyar        void setFraction(float fraction) {
287413444125c69c7071767b1bac60d4d857097abccYigit Boyar            fraction = mStartRatio + (1f - mStartRatio) * fraction;
288413444125c69c7071767b1bac60d4d857097abccYigit Boyar            if (fraction < .5f) {
289413444125c69c7071767b1bac60d4d857097abccYigit Boyar                ViewCompat.setTranslationX(mViewHolder.textView, fraction * mMaxX);
290413444125c69c7071767b1bac60d4d857097abccYigit Boyar                ViewCompat.setAlpha(mViewHolder.textView, 1f - fraction);
291413444125c69c7071767b1bac60d4d857097abccYigit Boyar            } else {
292413444125c69c7071767b1bac60d4d857097abccYigit Boyar                ViewCompat.setTranslationX(mViewHolder.textView, (1f - fraction) * mMaxX);
293413444125c69c7071767b1bac60d4d857097abccYigit Boyar                ViewCompat.setAlpha(mViewHolder.textView, fraction);
294413444125c69c7071767b1bac60d4d857097abccYigit Boyar                maybeSetFinalText();
295413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
296413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
297413444125c69c7071767b1bac60d4d857097abccYigit Boyar
298413444125c69c7071767b1bac60d4d857097abccYigit Boyar        @Override
299413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void onAnimationUpdate(ValueAnimator valueAnimator) {
300413444125c69c7071767b1bac60d4d857097abccYigit Boyar            setFraction(valueAnimator.getAnimatedFraction());
301413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
302413444125c69c7071767b1bac60d4d857097abccYigit Boyar
303413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void start() {
304413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator.start();
305413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
306413444125c69c7071767b1bac60d4d857097abccYigit Boyar
307413444125c69c7071767b1bac60d4d857097abccYigit Boyar        @Override
308413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void onAnimationEnd(Animator animation) {
309413444125c69c7071767b1bac60d4d857097abccYigit Boyar            maybeSetFinalText();
310413444125c69c7071767b1bac60d4d857097abccYigit Boyar            ViewCompat.setAlpha(mViewHolder.textView, 1f);
311413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
312413444125c69c7071767b1bac60d4d857097abccYigit Boyar
313413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void maybeSetFinalText() {
314413444125c69c7071767b1bac60d4d857097abccYigit Boyar            if (mFinalText != null) {
315413444125c69c7071767b1bac60d4d857097abccYigit Boyar                mViewHolder.textView.setText(mFinalText);
316413444125c69c7071767b1bac60d4d857097abccYigit Boyar                mFinalText = null;
317413444125c69c7071767b1bac60d4d857097abccYigit Boyar            }
318413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
319413444125c69c7071767b1bac60d4d857097abccYigit Boyar
320413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void end() {
321413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mValueAnimator.cancel();
322413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
323413444125c69c7071767b1bac60d4d857097abccYigit Boyar
324413444125c69c7071767b1bac60d4d857097abccYigit Boyar        @Override
325413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void onAnimationStart(Animator animation) {
326413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
327413444125c69c7071767b1bac60d4d857097abccYigit Boyar
328413444125c69c7071767b1bac60d4d857097abccYigit Boyar        @Override
329413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void onAnimationCancel(Animator animation) {
330413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
331413444125c69c7071767b1bac60d4d857097abccYigit Boyar
332413444125c69c7071767b1bac60d4d857097abccYigit Boyar        @Override
333413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public void onAnimationRepeat(Animator animation) {
334413444125c69c7071767b1bac60d4d857097abccYigit Boyar        }
335413444125c69c7071767b1bac60d4d857097abccYigit Boyar    }
336413444125c69c7071767b1bac60d4d857097abccYigit Boyar
337413444125c69c7071767b1bac60d4d857097abccYigit Boyar    private static class MyItemInfo extends DefaultItemAnimator.ItemHolderInfo {
338413444125c69c7071767b1bac60d4d857097abccYigit Boyar        CharSequence text;
33952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
34052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
34152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    @Override
34252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public boolean onCreateOptionsMenu(Menu menu) {
34352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        super.onCreateOptionsMenu(menu);
34452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        MenuItemCompat.setShowAsAction(menu.add("Layout"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
34552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        return true;
34652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
34752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
34852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    @Override
34952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public boolean onOptionsItemSelected(MenuItem item) {
35052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mRecyclerView.requestLayout();
35152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        return super.onOptionsItemSelected(item);
35252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
35352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
354413444125c69c7071767b1bac60d4d857097abccYigit Boyar    @SuppressWarnings("unused")
35552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void checkboxClicked(View view) {
35652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        ViewGroup parent = (ViewGroup) view.getParent();
35752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        boolean selected = ((CheckBox) view).isChecked();
3582a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar        MyViewHolder holder = (MyViewHolder) mRecyclerView.getChildViewHolder(parent);
35952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.selectItem(holder, selected);
36052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
36152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
362413444125c69c7071767b1bac60d4d857097abccYigit Boyar    @SuppressWarnings("unused")
363ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    public void itemClicked(View view) {
364ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        ViewGroup parent = (ViewGroup) view;
365ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        MyViewHolder holder = (MyViewHolder) mRecyclerView.getChildViewHolder(parent);
3664fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar        final int position = holder.getAdapterPosition();
3674fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar        if (position == RecyclerView.NO_POSITION) {
3684fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar            return;
3694fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar        }
370ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        mAdapter.toggleExpanded(holder);
3714fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar        mAdapter.notifyItemChanged(position);
372ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    }
373ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase
3741e6f1f0dadd12895867b321ee3362378c20bf5a9Vadim Tryshev    public void deleteSelectedItems(View view) {
37552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        int numItems = mItems.size();
37652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        if (numItems > 0) {
37752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = numItems - 1; i >= 0; --i) {
37852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                final String itemText = mItems.get(i);
37952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                boolean selected = mAdapter.mSelected.get(itemText);
38052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                if (selected) {
38152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    removeAtPosition(i);
38252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
38352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
38452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
38552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
38652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
38752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private String generateNewText() {
38852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        return "Added Item #" + mNumItemsAdded++;
38952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
39052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
39152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void d1a2d3(View view) {
39252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        removeAtPosition(1);
39352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addAtPosition(2, "Added Item #" + mNumItemsAdded++);
39452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        removeAtPosition(3);
39552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
39652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
39752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private void removeAtPosition(int position) {
39879eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev        if(position < mItems.size()) {
39979eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev            mItems.remove(position);
40079eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev            mAdapter.notifyItemRemoved(position);
40179eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev        }
40252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
40352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
40452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    private void addAtPosition(int position, String text) {
40579eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev        if (position > mItems.size()) {
40679eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev            position = mItems.size();
40779eeb170db865990bab3e35e2a7abc73b2a37d83Vadim Tryshev        }
40852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mItems.add(position, text);
40952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.mSelected.put(text, Boolean.FALSE);
410ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        mAdapter.mExpanded.put(text, Boolean.FALSE);
41152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        mAdapter.notifyItemInserted(position);
41252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
41352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
41452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void addDeleteItem(View view) {
41552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addItem(view);
4161e6f1f0dadd12895867b321ee3362378c20bf5a9Vadim Tryshev        deleteSelectedItems(view);
41752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
41852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
41952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void deleteAddItem(View view) {
4201e6f1f0dadd12895867b321ee3362378c20bf5a9Vadim Tryshev        deleteSelectedItems(view);
42152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addItem(view);
42252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
42352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
42452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    public void addItem(View view) {
42552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        addAtPosition(3, "Added Item #" + mNumItemsAdded++);
42652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
42752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
42852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    /**
42952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase     * A basic ListView-style LayoutManager.
43052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase     */
43152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    class MyLayoutManager extends RecyclerView.LayoutManager {
43252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private static final String TAG = "MyLayoutManager";
43352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private int mFirstPosition;
43452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private final int mScrollDistance;
43552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
43652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public MyLayoutManager(Context c) {
43752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final DisplayMetrics dm = c.getResources().getDisplayMetrics();
43852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mScrollDistance = (int) (SCROLL_DISTANCE * dm.density + 0.5f);
43952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
44052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
44152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
442e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase        public boolean supportsPredictiveItemAnimations() {
443e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase            return mPredictiveAnimationsEnabled;
44452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
44552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
44652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
4472a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
44852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int parentBottom = getHeight() - getPaddingBottom();
44952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
45052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final View oldTopView = getChildCount() > 0 ? getChildAt(0) : null;
45152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int oldTop = getPaddingTop();
45252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (oldTopView != null) {
45352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                oldTop = Math.min(oldTopView.getTop(), oldTop);
45452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
45552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
45652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            // Note that we add everything to the scrap, but we do not clean it up;
45752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            // that is handled by the RecyclerView after this method returns
45852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            detachAndScrapAttachedViews(recycler);
45952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
46052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int top = oldTop;
46152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int bottom = top;
46252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int left = getPaddingLeft();
46352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int right = getWidth() - getPaddingRight();
46452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
46552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int count = state.getItemCount();
46652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = 0; mFirstPosition + i < count && top < parentBottom; i++, top = bottom) {
4672a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                View v = recycler.getViewForPosition(mFirstPosition + i);
46852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
46952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) v.getLayoutParams();
470d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                addView(v);
47152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                measureChild(v, 0, 0);
47252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                bottom = top + v.getMeasuredHeight();
47352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                v.layout(left, top, right, bottom);
474e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                if (mPredictiveAnimationsEnabled && params.isItemRemoved()) {
47552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    parentBottom += v.getHeight();
47652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
47752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
47852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
479d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar            if (mAnimationsEnabled && mPredictiveAnimationsEnabled && !state.isPreLayout()) {
480e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // Now that we've run a full layout, figure out which views were not used
481e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // (cached in previousViews). For each of these views, position it where
482e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // it would go, according to its position relative to the visible
483e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // positions in the list. This information will be used by RecyclerView to
484e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // record post-layout positions of these items for the purposes of animating them
485e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                // out of view
486e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase
487e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                View lastVisibleView = getChildAt(getChildCount() - 1);
488e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                if (lastVisibleView != null) {
489e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    RecyclerView.LayoutParams lastParams =
490e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                            (RecyclerView.LayoutParams) lastVisibleView.getLayoutParams();
4914fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar                    int lastPosition = lastParams.getViewLayoutPosition();
492e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    final List<RecyclerView.ViewHolder> previousViews = recycler.getScrapList();
493e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    count = previousViews.size();
494e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                    for (int i = 0; i < count; ++i) {
495e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        View view = previousViews.get(i).itemView;
496e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        RecyclerView.LayoutParams params =
497e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                                (RecyclerView.LayoutParams) view.getLayoutParams();
498d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                        if (params.isItemRemoved()) {
499d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                            continue;
500d552f7f491a503efcd1d71c2830a6214a7235c82Yigit Boyar                        }
5014fa1fe35a2e2f6aa8973bbb698f5191b7acc8d95Yigit Boyar                        int position = params.getViewLayoutPosition();
502e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        int newTop;
503e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        if (position < mFirstPosition) {
504e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                            newTop = view.getHeight() * (position - mFirstPosition);
505e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        } else {
506e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                            newTop = lastVisibleView.getTop() + view.getHeight() *
507e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                                    (position - lastPosition);
508e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        }
509e67b22350aaf5884e84d3e08e76f50a145731ff7Chet Haase                        view.offsetTopAndBottom(newTop - view.getTop());
51052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
51152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
51252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
51352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
51452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
51552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
51652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
51752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
51852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    ViewGroup.LayoutParams.WRAP_CONTENT);
51952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
52052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
52152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
52252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public boolean canScrollVertically() {
52352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return true;
52452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
52552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
52652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
5272a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
5282a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                RecyclerView.State state) {
52952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (getChildCount() == 0) {
53052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                return 0;
53152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
53252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
53352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int scrolled = 0;
53452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int left = getPaddingLeft();
53552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int right = getWidth() - getPaddingRight();
53652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (dy < 0) {
53752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                while (scrolled > dy) {
53852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final View topView = getChildAt(0);
53952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int hangingTop = Math.max(-topView.getTop(), 0);
54052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int scrollBy = Math.min(scrolled - dy, hangingTop);
54152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    scrolled -= scrollBy;
54252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    offsetChildrenVertical(scrollBy);
54352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (mFirstPosition > 0 && scrolled > dy) {
54452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        mFirstPosition--;
5452a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                        View v = recycler.getViewForPosition(mFirstPosition);
54652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        addView(v, 0);
54752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        measureChild(v, 0, 0);
54852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int bottom = topView.getTop(); // TODO decorated top?
54952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int top = bottom - v.getMeasuredHeight();
55052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        v.layout(left, top, right, bottom);
55152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    } else {
55252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
55352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
55452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
55552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            } else if (dy > 0) {
55652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                final int parentHeight = getHeight();
55752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                while (scrolled < dy) {
55852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final View bottomView = getChildAt(getChildCount() - 1);
55952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int hangingBottom = Math.max(bottomView.getBottom() - parentHeight, 0);
56052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int scrollBy = -Math.min(dy - scrolled, hangingBottom);
56152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    scrolled -= scrollBy;
56252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    offsetChildrenVertical(scrollBy);
5638b38db9f287670f670f631a0ec4b95882cdd0705Yigit Boyar                    if (scrolled < dy && state.getItemCount() > mFirstPosition + getChildCount()) {
5642a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                        View v = recycler.getViewForPosition(mFirstPosition + getChildCount());
56552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int top = getChildAt(getChildCount() - 1).getBottom();
56652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        addView(v);
56752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        measureChild(v, 0, 0);
56852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        final int bottom = top + v.getMeasuredHeight();
56952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        v.layout(left, top, right, bottom);
57052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    } else {
57152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
57252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
57352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
57452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
57552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            recycleViewsOutOfBounds(recycler);
57652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return scrolled;
57752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
57852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
57952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
58052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public View onFocusSearchFailed(View focused, int direction,
5812a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                RecyclerView.Recycler recycler, RecyclerView.State state) {
58252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int oldCount = getChildCount();
58352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
58452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (oldCount == 0) {
58552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                return null;
58652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
58752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
58852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int left = getPaddingLeft();
58952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int right = getWidth() - getPaddingRight();
59052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
59152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            View toFocus = null;
59252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int newViewsHeight = 0;
59352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (direction == View.FOCUS_UP || direction == View.FOCUS_BACKWARD) {
59452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                while (mFirstPosition > 0 && newViewsHeight < mScrollDistance) {
59552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    mFirstPosition--;
5962a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                    View v = recycler.getViewForPosition(mFirstPosition);
59752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int bottom = getChildAt(0).getTop(); // TODO decorated top?
59852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    addView(v, 0);
59952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    measureChild(v, 0, 0);
60052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int top = bottom - v.getMeasuredHeight();
60152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    v.layout(left, top, right, bottom);
60252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (v.isFocusable()) {
60352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        toFocus = v;
60452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
60552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
60652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
60752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
60852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (direction == View.FOCUS_DOWN || direction == View.FOCUS_FORWARD) {
6098b38db9f287670f670f631a0ec4b95882cdd0705Yigit Boyar                while (mFirstPosition + getChildCount() < state.getItemCount() &&
61052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        newViewsHeight < mScrollDistance) {
6112a1ade8a82653e53f3d5b16c7e9d0ed9cb734101Yigit Boyar                    View v = recycler.getViewForPosition(mFirstPosition + getChildCount());
61252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int top = getChildAt(getChildCount() - 1).getBottom();
61352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    addView(v);
61452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    measureChild(v, 0, 0);
61552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    final int bottom = top + v.getMeasuredHeight();
61652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    v.layout(left, top, right, bottom);
61752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (v.isFocusable()) {
61852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        toFocus = v;
61952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        break;
62052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
62152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
62252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
62352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
62452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return toFocus;
62552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
62652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
62752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void recycleViewsOutOfBounds(RecyclerView.Recycler recycler) {
62852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int childCount = getChildCount();
62952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int parentWidth = getWidth();
63052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            final int parentHeight = getHeight();
63152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            boolean foundFirst = false;
63252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int first = 0;
63352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            int last = 0;
63452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = 0; i < childCount; i++) {
63552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                final View v = getChildAt(i);
63652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                if (v.hasFocus() || (v.getRight() >= 0 && v.getLeft() <= parentWidth &&
63752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        v.getBottom() >= 0 && v.getTop() <= parentHeight)) {
63852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    if (!foundFirst) {
63952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        first = i;
64052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                        foundFirst = true;
64152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    }
64252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    last = i;
64352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                }
64452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
64552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = childCount - 1; i > last; i--) {
64652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                removeAndRecycleViewAt(i, recycler);
64752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
64852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (int i = first - 1; i >= 0; i--) {
64952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                removeAndRecycleViewAt(i, recycler);
65052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
65152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (getChildCount() == 0) {
65252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition = 0;
65352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            } else {
65452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition += first;
65552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
65652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
65752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
65852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
65952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
66052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (positionStart < mFirstPosition) {
66152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition += itemCount;
66252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
66352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
66452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
66552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
66652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
66752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (positionStart < mFirstPosition) {
66852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mFirstPosition -= itemCount;
66952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
67052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
67152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
67252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
67352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    class MyAdapter extends RecyclerView.Adapter {
67452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        private int mBackground;
67552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        List<String> mData;
676ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        ArrayMap<String, Boolean> mSelected = new ArrayMap<String, Boolean>();
677ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        ArrayMap<String, Boolean> mExpanded = new ArrayMap<String, Boolean>();
67852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
67952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public MyAdapter(List<String> data) {
68052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            TypedValue val = new TypedValue();
68152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            AnimatedRecyclerView.this.getTheme().resolveAttribute(
68252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    R.attr.selectableItemBackground, val, true);
68352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mBackground = val.resourceId;
68452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            mData = data;
68552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            for (String itemText : mData) {
68652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                mSelected.put(itemText, Boolean.FALSE);
687ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase                mExpanded.put(itemText, Boolean.FALSE);
68852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
68952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
69052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
69152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
69252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
69352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            MyViewHolder h = new MyViewHolder(getLayoutInflater().inflate(R.layout.selectable_item,
69452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                    null));
69552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            h.textView.setMinimumHeight(128);
69652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            h.textView.setFocusable(true);
69752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            h.textView.setBackgroundResource(mBackground);
69852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return h;
69952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
70052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
70152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
70252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
70352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            String itemText = mData.get(position);
704413444125c69c7071767b1bac60d4d857097abccYigit Boyar            MyViewHolder myViewHolder = (MyViewHolder) holder;
705413444125c69c7071767b1bac60d4d857097abccYigit Boyar            myViewHolder.boundText = itemText;
706413444125c69c7071767b1bac60d4d857097abccYigit Boyar            myViewHolder.textView.setText(itemText);
70752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            boolean selected = false;
70852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            if (mSelected.get(itemText) != null) {
70952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase                selected = mSelected.get(itemText);
71052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            }
711413444125c69c7071767b1bac60d4d857097abccYigit Boyar            myViewHolder.checkBox.setChecked(selected);
712ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            Boolean expanded = mExpanded.get(itemText);
713413444125c69c7071767b1bac60d4d857097abccYigit Boyar            if (Boolean.TRUE.equals(expanded)) {
714413444125c69c7071767b1bac60d4d857097abccYigit Boyar                myViewHolder.textView.setText("More text for the expanded version");
715ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            } else {
716413444125c69c7071767b1bac60d4d857097abccYigit Boyar                myViewHolder.textView.setText(itemText);
717ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase            }
71852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
71952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
72052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
72152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public int getItemCount() {
72252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return mData.size();
72352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
72452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
72552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public void selectItem(MyViewHolder holder, boolean selected) {
726413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mSelected.put(holder.boundText, selected);
72752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
728ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase
729ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        public void toggleExpanded(MyViewHolder holder) {
730413444125c69c7071767b1bac60d4d857097abccYigit Boyar            mExpanded.put(holder.boundText, !mExpanded.get(holder.boundText));
731ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase        }
73252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    }
73352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
73452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase    static class MyViewHolder extends RecyclerView.ViewHolder {
73552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public TextView textView;
73652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public CheckBox checkBox;
737413444125c69c7071767b1bac60d4d857097abccYigit Boyar        public String boundText;
73852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
73952d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public MyViewHolder(View v) {
74052d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            super(v);
74152d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            textView = (TextView) v.findViewById(R.id.text);
74252d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            checkBox = (CheckBox) v.findViewById(R.id.selected);
74352d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
74452d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase
74552d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        @Override
74652d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        public String toString() {
74752d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase            return super.toString() + " \"" + textView.getText() + "\"";
74852d8a6f82df928065a30c4c77ffb95e27ca381beChet Haase        }
749ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase    }
750ececfb5898bf10c086da91bca807ac73d5bbfb22Chet Haase}
751