1668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar/* 2668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 3668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 4668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * you may not use this file except in compliance with the License. 6668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * You may obtain a copy of the License at 7668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 8668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 10668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * See the License for the specific language governing permissions and 14668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * limitations under the License. 15668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 16668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 17668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarpackage android.support.v7.widget; 18668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 19668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarimport android.util.Log; 20668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarimport android.view.View; 21668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarimport android.view.ViewGroup; 22668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 23668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarimport java.util.ArrayList; 24668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarimport java.util.List; 25668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 26668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar/** 27668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Helper class to manage children. 28668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * <p> 29668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * It wraps a RecyclerView and adds ability to hide some children. There are two sets of methods 30668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * provided by this class. <b>Regular</b> methods are the ones that replicate ViewGroup methods 31668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * like getChildAt, getChildCount etc. These methods ignore hidden children. 32668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * <p> 33668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * When RecyclerView needs direct access to the view group children, it can call unfiltered 34668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * methods like get getUnfilteredChildCount or getUnfilteredChildAt. 35668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 36668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyarclass ChildHelper { 37668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 38668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private static final boolean DEBUG = false; 39668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 40668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private static final String TAG = "ChildrenHelper"; 41668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 42668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final Callback mCallback; 43668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 44668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final Bucket mBucket; 45668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 46668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final List<View> mHiddenViews; 47668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 48668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ChildHelper(Callback callback) { 49668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mCallback = callback; 50668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket = new Bucket(); 51668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mHiddenViews = new ArrayList<View>(); 52668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 53668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 54668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 55344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev * Marks a child view as hidden 56344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev * 57344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev * @param child View to hide. 58344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev */ 59344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev private void hideViewInternal(View child) { 60344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mHiddenViews.add(child); 61344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mCallback.onEnteredHiddenState(child); 62344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 63344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 64344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev /** 65344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev * Unmarks a child view as hidden. 66344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev * 67344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev * @param child View to hide. 68344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev */ 69344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev private boolean unhideViewInternal(View child) { 70344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev if (mHiddenViews.remove(child)) { 71344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mCallback.onLeftHiddenState(child); 72344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev return true; 73344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } else { 74344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev return false; 75344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 76344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 77344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 78344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev /** 79668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Adds a view to the ViewGroup 80668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 81668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param child View to add. 82668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param hidden If set to true, this item will be invisible from regular methods. 83668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 84668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void addView(View child, boolean hidden) { 85668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar addView(child, -1, hidden); 86668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 87668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 88668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 89668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Add a view to the ViewGroup at an index 90668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 91668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param child View to add. 92668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param index Index of the child from the regular perspective (excluding hidden views). 93668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * ChildHelper offsets this index to actual ViewGroup index. 94668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param hidden If set to true, this item will be invisible from regular methods. 95668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 96668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void addView(View child, int index, boolean hidden) { 97668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int offset; 98668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index < 0) { 99668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar offset = mCallback.getChildCount(); 100668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 101668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar offset = getOffset(index); 102668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 103668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket.insert(offset, hidden); 104668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (hidden) { 105344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev hideViewInternal(child); 106668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 107de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.addView(child, offset); 108668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 109668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "addViewAt " + index + ",h:" + hidden + ", " + this); 110668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 111668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 112668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 113668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private int getOffset(int index) { 1149bdc605f26da69e3aff157cf3746b767d77988f0Yigit Boyar if (index < 0) { 1159bdc605f26da69e3aff157cf3746b767d77988f0Yigit Boyar return -1; //anything below 0 won't work as diff will be undefined. 1169bdc605f26da69e3aff157cf3746b767d77988f0Yigit Boyar } 117668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int limit = mCallback.getChildCount(); 118668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int offset = index; 119668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar while (offset < limit) { 120668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int removedBefore = mBucket.countOnesBefore(offset); 121668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int diff = index - (offset - removedBefore); 122668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (diff == 0) { 123668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar while (mBucket.get(offset)) { // ensure this offset is not hidden 124668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar offset ++; 125668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 126668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return offset; 127668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 128668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar offset += diff; 129668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 130668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 131668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return -1; 132668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 133668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 134668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 135668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Removes the provided View from underlying RecyclerView. 136668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 137668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param view The view to remove. 138668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 139668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void removeView(View view) { 140668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int index = mCallback.indexOfChild(view); 141668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index < 0) { 142668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return; 143668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 144668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (mBucket.remove(index)) { 145344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev unhideViewInternal(view); 146668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 147de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.removeViewAt(index); 148668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 149668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "remove View off:" + index + "," + this); 150668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 151668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 152668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 153668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 154668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Removes the view at the provided index from RecyclerView. 155668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 156668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param index Index of the child from the regular perspective (excluding hidden views). 157668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * ChildHelper offsets this index to actual ViewGroup index. 158668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 159668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void removeViewAt(int index) { 160668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int offset = getOffset(index); 161668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final View view = mCallback.getChildAt(offset); 162668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (view == null) { 163668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return; 164668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 165668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (mBucket.remove(offset)) { 166344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev unhideViewInternal(view); 167668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 168de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.removeViewAt(offset); 169668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 170668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "removeViewAt " + index + ", off:" + offset + ", " + this); 171668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 172668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 173668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 174668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 175668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Returns the child at provided index. 176668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 177668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param index Index of the child to return in regular perspective. 178668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 179668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar View getChildAt(int index) { 180668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int offset = getOffset(index); 181668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return mCallback.getChildAt(offset); 182668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 183668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 184668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 185668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Removes all views from the ViewGroup including the hidden ones. 186668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 187668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void removeAllViewsUnfiltered() { 188668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket.reset(); 189344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev for (int i = mHiddenViews.size() - 1; i >= 0; i--) { 190344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mCallback.onLeftHiddenState(mHiddenViews.get(i)); 191344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev mHiddenViews.remove(i); 192344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev } 193de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.removeAllViews(); 194668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 195668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "removeAllViewsUnfiltered"); 196668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 197668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 198668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 199668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 200668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * This can be used to find a disappearing view by position. 201668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 202668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param position The adapter position of the item. 203668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param type View type, can be {@link RecyclerView#INVALID_TYPE}. 204668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @return A hidden view with a valid ViewHolder that matches the position and type. 205668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 206668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar View findHiddenNonRemovedView(int position, int type) { 207668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int count = mHiddenViews.size(); 208668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar for (int i = 0; i < count; i++) { 209668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final View view = mHiddenViews.get(i); 210668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view); 2115031b30272a0178845f88d06adddb204dd833779Yigit Boyar if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved() 2125031b30272a0178845f88d06adddb204dd833779Yigit Boyar && (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) { 213668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return view; 214668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 215668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 216668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return null; 217668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 218668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 219668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 220668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Attaches the provided view to the underlying ViewGroup. 221668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 222668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param child Child to attach. 223668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param index Index of the child to attach in regular perspective. 224668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param layoutParams LayoutParams for the child. 225668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param hidden If set to true, this item will be invisible to the regular methods. 226668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 227668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams, 228668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar boolean hidden) { 229668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int offset; 230668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index < 0) { 231668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar offset = mCallback.getChildCount(); 232668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 233668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar offset = getOffset(index); 234668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 235668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket.insert(offset, hidden); 23690ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar if (hidden) { 237344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev hideViewInternal(child); 23890ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar } 239de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.attachViewToParent(child, offset, layoutParams); 240668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 241668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "attach view to parent index:" + index + ",off:" + offset + "," + 242668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar "h:" + hidden + ", " + this); 243668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 244668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 245668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 246668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 247668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Returns the number of children that are not hidden. 248668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 249668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @return Number of children that are not hidden. 250668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @see #getChildAt(int) 251668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 252668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int getChildCount() { 253668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return mCallback.getChildCount() - mHiddenViews.size(); 254668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 255668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 256668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 257668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Returns the total number of children. 258668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 259668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @return The total number of children including the hidden views. 260668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @see #getUnfilteredChildAt(int) 261668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 262668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int getUnfilteredChildCount() { 263668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return mCallback.getChildCount(); 264668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 265668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 266668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 267668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Returns a child by ViewGroup offset. ChildHelper won't offset this index. 268668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 269668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param index ViewGroup index of the child to return. 270668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @return The view in the provided index. 271668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 272668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar View getUnfilteredChildAt(int index) { 273668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return mCallback.getChildAt(index); 274668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 275668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 276668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 277668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Detaches the view at the provided index. 278668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 279668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param index Index of the child to return in regular perspective. 280668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 281668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void detachViewFromParent(int index) { 282668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int offset = getOffset(index); 283668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket.remove(offset); 284de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.detachViewFromParent(offset); 285668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 286668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "detach view from parent " + index + ", off:" + offset); 287668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 288668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 289668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 290668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 291668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Returns the index of the child in regular perspective. 292668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 293668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param child The child whose index will be returned. 294668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @return The regular perspective index of the child or -1 if it does not exists. 295668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 296668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int indexOfChild(View child) { 297668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int index = mCallback.indexOfChild(child); 298668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index == -1) { 299668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return -1; 300668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 301668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (mBucket.get(index)) { 302668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 303668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar throw new IllegalArgumentException("cannot get index of a hidden child"); 304668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 305668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return -1; 306668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 307668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 308668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar // reverse the index 309668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return index - mBucket.countOnesBefore(index); 310668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 311668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 312668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 313a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar * Returns whether a View is visible to LayoutManager or not. 314a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar * 315a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar * @param view The child view to check. Should be a child of the Callback. 316a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar * @return True if the View is not visible to LayoutManager 317a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar */ 318a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar boolean isHidden(View view) { 319a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar return mHiddenViews.contains(view); 320a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar } 321a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar 322a5dc6f3eb86aacd2b287f6ea588aa1d900f6702aYigit Boyar /** 323668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Marks a child view as hidden. 324668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 325668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param view The view to hide. 326668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 327668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void hide(View view) { 328668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int offset = mCallback.indexOfChild(view); 329668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (offset < 0) { 330668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar throw new IllegalArgumentException("view is not a child, cannot hide " + view); 331668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 33218ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar if (DEBUG && mBucket.get(offset)) { 33318ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar throw new RuntimeException("trying to hide same view twice, how come ? " + view); 33418ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar } 335668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket.set(offset); 336344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev hideViewInternal(view); 337668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (DEBUG) { 338668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Log.d(TAG, "hiding child " + view + " at offset " + offset+ ", " + this); 339668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 340668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 341668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 3429051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar /** 3439051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar * Moves a child view from hidden list to regular list. 3449051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar * Calling this method should probably be followed by a detach, otherwise, it will suddenly 3459051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar * show up in LayoutManager's children list. 3469051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar * 3479051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar * @param view The hidden View to unhide 3489051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar */ 3499051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar void unhide(View view) { 3509051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar final int offset = mCallback.indexOfChild(view); 3519051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar if (offset < 0) { 3529051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar throw new IllegalArgumentException("view is not a child, cannot hide " + view); 3539051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3549051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar if (!mBucket.get(offset)) { 3559051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar throw new RuntimeException("trying to unhide a view that was not hidden" + view); 3569051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3579051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar mBucket.clear(offset); 3589051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar unhideViewInternal(view); 3599051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar } 3609051a368c00c40f8679ae67147b9f5af6f93638dYigit Boyar 361668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar @Override 362668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar public String toString() { 36390ca3086dbf66ad6bb8840e46ec8524a705e1c18Yigit Boyar return mBucket.toString() + ", hidden list:" + mHiddenViews.size(); 364668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 365668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 366668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 367668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Removes a view from the ViewGroup if it is hidden. 368668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * 369668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @param view The view to remove. 370668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * @return True if the View is found and it is hidden. False otherwise. 371668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 372668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar boolean removeViewIfHidden(View view) { 373668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final int index = mCallback.indexOfChild(view); 374504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar if (index == -1) { 375344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev if (unhideViewInternal(view) && DEBUG) { 376504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar throw new IllegalStateException("view is in hidden list but not in view group"); 377668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 378668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return true; 379668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 380668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (mBucket.get(index)) { 381668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mBucket.remove(index); 382344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev if (!unhideViewInternal(view) && DEBUG) { 383668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar throw new IllegalStateException( 384668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar "removed a hidden view but it is not in hidden views list"); 385668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 386de5f54783555fa2e778c4ed6760472a002b2589bYigit Boyar mCallback.removeViewAt(index); 387668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return true; 388668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 389668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return false; 390668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 391668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 392668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar /** 393668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar * Bitset implementation that provides methods to offset indices. 394668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar */ 395668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar static class Bucket { 396668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 397668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final static int BITS_PER_WORD = Long.SIZE; 398668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 399668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final static long LAST_BIT = 1L << (Long.SIZE - 1); 400668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 401668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar long mData = 0; 402668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 403668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar Bucket next; 404668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 405668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void set(int index) { 406668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index >= BITS_PER_WORD) { 407668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ensureNext(); 408668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next.set(index - BITS_PER_WORD); 409668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 410668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mData |= 1L << index; 411668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 412668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 413668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 414668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar private void ensureNext() { 415668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (next == null) { 416668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next = new Bucket(); 417668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 418668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 419668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 420668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void clear(int index) { 421668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index >= BITS_PER_WORD) { 422668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (next != null) { 423668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next.clear(index - BITS_PER_WORD); 424668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 425668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 426668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mData &= ~(1L << index); 427668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 428668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 429668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 430668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 431668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar boolean get(int index) { 432668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index >= BITS_PER_WORD) { 433668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ensureNext(); 434668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return next.get(index - BITS_PER_WORD); 435668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 436668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return (mData & (1L << index)) != 0; 437668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 438668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 439668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 440668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void reset() { 441668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mData = 0; 442668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (next != null) { 443668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next.reset(); 444668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 445668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 446668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 447668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void insert(int index, boolean value) { 448668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index >= BITS_PER_WORD) { 449668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ensureNext(); 450668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next.insert(index - BITS_PER_WORD, value); 451668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 452668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final boolean lastBit = (mData & LAST_BIT) != 0; 453668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar long mask = (1L << index) - 1; 454668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final long before = mData & mask; 455668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final long after = ((mData & ~mask)) << 1; 456668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mData = before | after; 457668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (value) { 458668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar set(index); 459668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 460668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar clear(index); 461668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 462668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (lastBit || next != null) { 463668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ensureNext(); 464668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next.insert(0, lastBit); 465668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 466668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 467668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 468668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 469668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar boolean remove(int index) { 470668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index >= BITS_PER_WORD) { 471668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar ensureNext(); 472668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return next.remove(index - BITS_PER_WORD); 473668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 474668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar long mask = (1L << index); 475668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final boolean value = (mData & mask) != 0; 476668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mData &= ~mask; 477668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mask = mask - 1; 478668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final long before = mData & mask; 479668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar // cannot use >> because it adds one. 480668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar final long after = Long.rotateRight(mData & ~mask, 1); 481668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar mData = before | after; 482668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (next != null) { 483668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (next.get(0)) { 484668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar set(BITS_PER_WORD - 1); 485668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 486668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar next.remove(0); 487668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 488668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return value; 489668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 490668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 491668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 492668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int countOnesBefore(int index) { 493668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (next == null) { 494668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index >= BITS_PER_WORD) { 495668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return Long.bitCount(mData); 496668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 497668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return Long.bitCount(mData & ((1L << index) - 1)); 498668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 499668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar if (index < BITS_PER_WORD) { 500668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return Long.bitCount(mData & ((1L << index) - 1)); 501668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } else { 502668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return next.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData); 503668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 504668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 505668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 506668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar @Override 507668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar public String toString() { 508668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar return next == null ? Long.toBinaryString(mData) 509668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar : next.toString() + "xx" + Long.toBinaryString(mData); 510668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 511668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 512668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 513668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar static interface Callback { 514668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 515668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int getChildCount(); 516668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 517668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void addView(View child, int index); 518668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 519668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar int indexOfChild(View view); 520668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 521668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void removeViewAt(int index); 522668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 523668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar View getChildAt(int offset); 524668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 525668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void removeAllViews(); 526668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 527668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar RecyclerView.ViewHolder getChildViewHolder(View view); 528668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 529668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams); 530668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar 531668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar void detachViewFromParent(int offset); 532344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 533344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev void onEnteredHiddenState(View child); 534344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev 535344e49fcc92aba485da10a983fe916e2e4750a77Vadim Tryshev void onLeftHiddenState(View child); 536668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar } 537668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar} 538