下面列出了android.util.SparseBooleanArray#size ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
@SuppressWarnings("unchecked")
public void onClick(View v) {
if (adaptee != null) {
SparseBooleanArray checkedItemPositions = choicesList.getCheckedItemPositions();
List<T> selectedItems = new ArrayList<>(checkedItemPositions.size());
List<Integer> selectedPositions = new ArrayList<>(checkedItemPositions.size());
ListAdapter adapter = choicesList.getAdapter();
for (int index = 0; index < adapter.getCount(); index++) {
if (checkedItemPositions.get(index)) {
selectedPositions.add(index);
selectedItems.add((T) adapter.getItem(index));
}
}
adaptee.onItemsSelected(selectedPositions, selectedItems);
}
dismiss();
}
private void updateSectionItemRangeSelectionState(int sectionIndex, int fromPosition, int delta) {
SectionSelectionState sectionSelectionState = getSectionSelectionState(sectionIndex);
SparseBooleanArray itemState = sectionSelectionState.items.clone();
sectionSelectionState.items.clear();
for (int i = 0, n = itemState.size(); i < n; i++) {
int pos = itemState.keyAt(i);
if (delta < 0 && pos >= fromPosition && pos < fromPosition - delta) { // erasure
continue;
}
int newPos = pos;
if (pos >= fromPosition) {
newPos += delta;
}
if (itemState.get(pos)) {
sectionSelectionState.items.put(newPos, true);
}
}
}
/**
* Use this when an item has been deleted, to move the check state of all
* following items up one step. If you have a choiceMode which is not none,
* this method must be called when the order of items changes in an
* underlying adapter which does not have stable IDs (see
* {@link android.widget.ListAdapter#hasStableIds()}). This is because without IDs, the
* ListView has no way of knowing which items have moved where, and cannot
* update the check state accordingly.
*
* See also further comments on {@link #moveCheckState(int, int)}.
*
* @param position
*/
public void removeCheckState(int position) {
SparseBooleanArray cip = getCheckedItemPositions();
if (cip.size() == 0)
return;
int[] runStart = new int[cip.size()];
int[] runEnd = new int[cip.size()];
int rangeStart = position;
int rangeEnd = cip.keyAt(cip.size() - 1) + 1;
int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd);
for (int i = 0; i != runCount; i++) {
if (!(runStart[i] == position || (runEnd[i] < runStart[i] && runEnd[i] > position))) {
// Only set a new check mark in front of this run if it does
// not contain the deleted position. If it does, we only need
// to make it one check mark shorter at the end.
setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true);
}
setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false);
}
}
/**
* Use this when an item has been deleted, to move the check state of all
* following items up one step. If you have a choiceMode which is not none,
* this method must be called when the order of items changes in an
* underlying adapter which does not have stable IDs (see
* {@link android.widget.ListAdapter#hasStableIds()}). This is because without IDs, the
* ListView has no way of knowing which items have moved where, and cannot
* update the check state accordingly.
*
* See also further comments on {@link #moveCheckState(int, int)}.
*
* @param position
*/
public void removeCheckState(int position) {
SparseBooleanArray cip = getCheckedItemPositions();
if (cip.size() == 0)
return;
int[] runStart = new int[cip.size()];
int[] runEnd = new int[cip.size()];
int rangeStart = position;
int rangeEnd = cip.keyAt(cip.size() - 1) + 1;
int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd);
for (int i = 0; i != runCount; i++) {
if (!(runStart[i] == position || (runEnd[i] < runStart[i] && runEnd[i] > position))) {
// Only set a new check mark in front of this run if it does
// not contain the deleted position. If it does, we only need
// to make it one check mark shorter at the end.
setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true);
}
setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false);
}
}
/**
* Use this when an item has been deleted, to move the check state of all
* following items up one step. If you have a choiceMode which is not none,
* this method must be called when the order of items changes in an
* underlying adapter which does not have stable IDs (see
* {@link android.widget.ListAdapter#hasStableIds()}). This is because without IDs, the
* ListView has no way of knowing which items have moved where, and cannot
* update the check state accordingly.
*
* See also further comments on {@link #moveCheckState(int, int)}.
*
* @param position
*/
public void removeCheckState(int position) {
SparseBooleanArray cip = getCheckedItemPositions();
if (cip.size() == 0)
return;
int[] runStart = new int[cip.size()];
int[] runEnd = new int[cip.size()];
int rangeStart = position;
int rangeEnd = cip.keyAt(cip.size() - 1) + 1;
int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd);
for (int i = 0; i != runCount; i++) {
if (!(runStart[i] == position || (runEnd[i] < runStart[i] && runEnd[i] > position))) {
// Only set a new check mark in front of this run if it does
// not contain the deleted position. If it does, we only need
// to make it one check mark shorter at the end.
setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true);
}
setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false);
}
}
@Override
protected void onPause() {
SparseBooleanArray arr = mAppsView.getCheckedItemPositions();
List<AppInfo> apps = mAdapter.getAppList();
for (int i = 0; i < arr.size(); i++) {
if (i >= apps.size()) {
continue;
}
String name = apps.get(i).getPackageName();
if (arr.get(i)) {
mConfig.add(name);
} else {
mConfig.remove(name);
}
}
ConfigUtils.put(this, mConfig);
super.onPause();
}
private void deleteSelectedItems(){
ArrayAdapter adapter = (ArrayAdapter) lvItemList.getAdapter();
SparseBooleanArray checkedItemPositions = lvItemList.getCheckedItemPositions();
ArrayList<CheckListItem> temp = new ArrayList<>();
for (int i=0; i < checkedItemPositions.size(); i++) {
if(checkedItemPositions.valueAt(i)) {
temp.add((CheckListItem) adapter.getItem(checkedItemPositions.keyAt(i)));
}
}
if (temp.size() > 0) {
itemNamesList.removeAll(temp);
}
}
private static int insertionIndexForKey(SparseBooleanArray sba, int key) {
int low = 0;
int high = sba.size();
while (high - low > 0) {
int middle = (low + high) >> 1;
if (sba.keyAt(middle) < key)
low = middle + 1;
else
high = middle;
}
return low;
}
private void hidePopUpMenu(ViewHolder holder) {
SparseBooleanArray checkedItems = mListView.getCheckedItemPositions();
if (checkedItems.size() > 0) {
for (int i = 0; i < checkedItems.size(); i++) {
int key = checkedItems.keyAt(i);
if (checkedItems.get(key)) {
holder.popup.setVisibility(View.INVISIBLE);
}
}
} else {
holder.popup.setVisibility(View.VISIBLE);
}
}
private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) {
int size = sba.size();
int i = insertionIndexForKey(sba, rangeStart);
while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i))
i++;
if (i == size || sba.keyAt(i) >= rangeEnd)
return -1;
return i;
}
private static int insertionIndexForKey(SparseBooleanArray sba, int key) {
int low = 0;
int high = sba.size();
while (high - low > 0) {
int middle = (low + high) >> 1;
if (sba.keyAt(middle) < key)
low = middle + 1;
else
high = middle;
}
return low;
}
private void resetChoices() {
final SparseBooleanArray sba = this.mListView.getCheckedItemPositions();
for (int i = 0; i < sba.size(); i++) {
this.mCursorAdapter.setItemChecked(sba.keyAt(i), false);
}
this.mListView.clearChoices();
}
private static int insertionIndexForKey(SparseBooleanArray sba, int key) {
int low = 0;
int high = sba.size();
while (high - low > 0) {
int middle = (low + high) >> 1;
if (sba.keyAt(middle) < key)
low = middle + 1;
else
high = middle;
}
return low;
}
private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) {
int size = sba.size();
int i = insertionIndexForKey(sba, rangeStart);
while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i))
i++;
if (i == size || sba.keyAt(i) >= rangeEnd)
return -1;
return i;
}
protected void getSelected(){
SparseBooleanArray checked = friendList.getCheckedItemPositions();
Set<String> friendSet = new HashSet<String>();
for (int i = 0; i < checked.size(); i++) {
if (checked.valueAt(i)){
friendSet.add((String) friendList.getItemAtPosition(checked.keyAt(i)));
}
}
SharedPreferences.Editor editor = prefs.edit();
editor.putStringSet("add_friends", friendSet);
editor.commit();
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
final ArrayList<DocumentInfo> docs = new ArrayList<>();
final int size = checked.size();
for (int i = 0; i < size; i++) {
if (checked.valueAt(i)) {
final Cursor cursor = mAdapter.getItem(checked.keyAt(i));
if(null != cursor) {
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
docs.add(doc);
}
}
}
if(docs.isEmpty()){
return false;
}
final int id = item.getItemId();
switch (id) {
case R.id.menu_open:
BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
mode.finish();
return true;
case R.id.menu_share:
onShareDocuments(docs);
mode.finish();
return true;
case R.id.menu_copy:
moveDocument(docs, false);
mode.finish();
return true;
case R.id.menu_cut:
moveDocument(docs, true);
mode.finish();
return true;
case R.id.menu_delete:
deleteDocument(docs, id);
mode.finish();
return true;
case R.id.menu_stop:
stopDocument(docs, id);
mode.finish();
return true;
case R.id.menu_save:
case R.id.menu_compress:
new OperationTask(docs, id).execute();
mode.finish();
return true;
case R.id.menu_select_all:
int count = mAdapter.getCount();
for (int i = 0; i < count; i++) {
mCurrentView.setItemChecked(i, selectAll);
}
selectAll = !selectAll;
Bundle params = new Bundle();
params.putInt(FILE_COUNT, count);
AnalyticsManager.logEvent("select", params);
return true;
case R.id.menu_info:
infoDocument(docs.get(0));
mode.finish();
return true;
case R.id.menu_rename:
renameDocument(docs.get(0));
mode.finish();
return true;
default:
return false;
}
}
private static int buildRunList(SparseBooleanArray cip, int rangeStart,
int rangeEnd, int[] runStart, int[] runEnd) {
int runCount = 0;
int i = findFirstSetIndex(cip, rangeStart, rangeEnd);
if (i == -1)
return 0;
int position = cip.keyAt(i);
int currentRunStart = position;
int currentRunEnd = currentRunStart + 1;
for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) {
if (!cip.valueAt(i)) // not checked => not interesting
continue;
if (position == currentRunEnd) {
currentRunEnd++;
} else {
runStart[runCount] = currentRunStart;
runEnd[runCount] = currentRunEnd;
runCount++;
currentRunStart = position;
currentRunEnd = position + 1;
}
}
if (currentRunEnd == rangeEnd) {
// rangeStart and rangeEnd are equivalent positions so to be
// consistent we translate them to the same integer value. That way
// we can check whether a run covers the entire range by just
// checking if the start equals the end position.
currentRunEnd = rangeStart;
}
runStart[runCount] = currentRunStart;
runEnd[runCount] = currentRunEnd;
runCount++;
if (runCount > 1) {
if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) {
// The last run ends at the end of the range, and the first run
// starts at the beginning of the range. So they are actually
// part of the same run, except they wrap around the end of the
// range. To avoid adjacent runs, we need to merge them.
runStart[0] = runStart[runCount - 1];
runCount--;
}
}
return runCount;
}
public static boolean isEmpty(final SparseBooleanArray obj) {
return obj == null || obj.size() == 0;
}
private static int buildRunList(@NonNull SparseBooleanArray cip, int rangeStart,
int rangeEnd, int[] runStart, int[] runEnd) {
int runCount = 0;
int i = findFirstSetIndex(cip, rangeStart, rangeEnd);
if (i == -1)
return 0;
int position = cip.keyAt(i);
int currentRunStart = position;
int currentRunEnd = currentRunStart + 1;
for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) {
if (!cip.valueAt(i)) // not checked => not interesting
continue;
if (position == currentRunEnd) {
currentRunEnd++;
} else {
runStart[runCount] = currentRunStart;
runEnd[runCount] = currentRunEnd;
runCount++;
currentRunStart = position;
currentRunEnd = position + 1;
}
}
if (currentRunEnd == rangeEnd) {
// rangeStart and rangeEnd are equivalent positions so to be
// consistent we translate them to the same integer value. That way
// we can check whether a run covers the entire range by just
// checking if the start equals the end position.
currentRunEnd = rangeStart;
}
runStart[runCount] = currentRunStart;
runEnd[runCount] = currentRunEnd;
runCount++;
if (runCount > 1) {
if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) {
// The last run ends at the end of the range, and the first run
// starts at the beginning of the range. So they are actually
// part of the same run, except they wrap around the end of the
// range. To avoid adjacent runs, we need to merge them.
runStart[0] = runStart[runCount - 1];
runCount--;
}
}
return runCount;
}
/**
* Use this to move the check state of an item from one position to another
* in a drop operation. If you have a choiceMode which is not none, this
* method must be called when the order of items changes in an underlying
* adapter which does not have stable IDs (see
* {@link ListAdapter#hasStableIds()}). This is because without IDs, the
* ListView has no way of knowing which items have moved where, and cannot
* update the check state accordingly.
* <p>
* A word of warning about a "feature" in Android that you may run into when
* dealing with movable list items: for an adapter that <em>does</em> have
* stable IDs, ListView will attempt to locate each item based on its ID and
* move the check state from the item's old position to the new position —
* which is all fine and good (and removes the need for calling this
* function), except for the half-baked approach. Apparently to save time in
* the naive algorithm used, ListView will only search for an ID in the
* close neighborhood of the old position. If the user moves an item too far
* (specifically, more than 20 rows away), ListView will give up and just
* force the item to be unchecked. So if there is a reasonable chance that
* the user will move items more than 20 rows away from the original
* position, you may wish to use an adapter with unstable IDs and call this
* method manually instead.
*
* @param from
* @param to
*/
public void moveCheckState(int from, int to) {
// This method runs in O(n log n) time (n being the number of list
// items). The bottleneck is the call to AbsListView.setItemChecked,
// which is O(log n) because of the binary search involved in calling
// SparseBooleanArray.put().
//
// To improve on the average time, we minimize the number of calls to
// setItemChecked by only calling it for items that actually have a
// changed state. This is achieved by building a list containing the
// start and end of the "runs" of checked items, and then moving the
// runs. Note that moving an item from A to B is essentially a rotation
// of the range of items in [A, B]. Let's say we have
// . . U V X Y Z . .
// and move U after Z. This is equivalent to a rotation one step to the
// left within the range you are moving across:
// . . V X Y Z U . .
//
// So, to perform the move we enumerate all the runs within the move
// range, then rotate each run one step to the left or right (depending
// on move direction). For example, in the list:
// X X . X X X . X
// we have two runs. One begins at the last item of the list and wraps
// around to the beginning, ending at position 1. The second begins at
// position 3 and ends at position 5. To rotate a run, regardless of
// length, we only need to set a check mark at one end of the run, and
// clear a check mark at the other end:
// X . X X X . X X
SparseBooleanArray cip = getCheckedItemPositions();
int rangeStart = from;
int rangeEnd = to;
if (to < from) {
rangeStart = to;
rangeEnd = from;
}
rangeEnd += 1;
int[] runStart = new int[cip.size()];
int[] runEnd = new int[cip.size()];
int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd);
if (runCount == 1 && (runStart[0] == runEnd[0])) {
// Special case where all items are checked, we can never set any
// item to false like we do below.
return;
}
if (from < to) {
for (int i = 0; i != runCount; i++) {
setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true);
setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false);
}
} else {
for (int i = 0; i != runCount; i++) {
setItemChecked(runStart[i], false);
setItemChecked(runEnd[i], true);
}
}
}