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