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