Eric Kok
12 years ago
15 changed files with 518 additions and 738 deletions
@ -1,481 +0,0 @@
@@ -1,481 +0,0 @@
|
||||
/*** |
||||
Copyright (c) 2008-2009 CommonsWare, LLC |
||||
Portions (c) 2009 Google, Inc. |
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may |
||||
not use this file except in compliance with the License. You may obtain |
||||
a copy of the License at |
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software |
||||
distributed under the License is distributed on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
See the License for the specific language governing permissions and |
||||
limitations under the License. |
||||
*/ |
||||
|
||||
package com.commonsware.cwac.merge; |
||||
|
||||
import android.database.DataSetObserver; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
import android.widget.ListAdapter; |
||||
import android.widget.SectionIndexer; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import com.commonsware.cwac.sacklist.SackOfViewsAdapter; |
||||
|
||||
/** |
||||
* Adapter that merges multiple child adapters and views |
||||
* into a single contiguous whole. |
||||
* |
||||
* Adapters used as pieces within MergeAdapter must have |
||||
* view type IDs monotonically increasing from 0. Ideally, |
||||
* adapters also have distinct ranges for their row ids, as |
||||
* returned by getItemId(). |
||||
* |
||||
*/ |
||||
public class MergeAdapter extends BaseAdapter implements SectionIndexer { |
||||
protected PieceStateRoster pieces=new PieceStateRoster(); |
||||
|
||||
/** |
||||
* Stock constructor, simply chaining to the superclass. |
||||
*/ |
||||
public MergeAdapter() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new adapter to the roster of things to appear in |
||||
* the aggregate list. |
||||
* |
||||
* @param adapter |
||||
* Source for row views for this section |
||||
*/ |
||||
public void addAdapter(ListAdapter adapter) { |
||||
pieces.add(adapter); |
||||
adapter.registerDataSetObserver(new CascadeDataSetObserver()); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new View to the roster of things to appear in |
||||
* the aggregate list. |
||||
* |
||||
* @param view |
||||
* Single view to add |
||||
*/ |
||||
public void addView(View view) { |
||||
addView(view, false); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new View to the roster of things to appear in |
||||
* the aggregate list. |
||||
* |
||||
* @param view |
||||
* Single view to add |
||||
* @param enabled |
||||
* false if views are disabled, true if enabled |
||||
*/ |
||||
public void addView(View view, boolean enabled) { |
||||
ArrayList<View> list=new ArrayList<View>(1); |
||||
|
||||
list.add(view); |
||||
|
||||
addViews(list, enabled); |
||||
} |
||||
|
||||
/** |
||||
* Adds a list of views to the roster of things to appear |
||||
* in the aggregate list. |
||||
* |
||||
* @param views |
||||
* List of views to add |
||||
*/ |
||||
public void addViews(List<View> views) { |
||||
addViews(views, false); |
||||
} |
||||
|
||||
/** |
||||
* Adds a list of views to the roster of things to appear |
||||
* in the aggregate list. |
||||
* |
||||
* @param views |
||||
* List of views to add |
||||
* @param enabled |
||||
* false if views are disabled, true if enabled |
||||
*/ |
||||
public void addViews(List<View> views, boolean enabled) { |
||||
if (enabled) { |
||||
addAdapter(new EnabledSackAdapter(views)); |
||||
} |
||||
else { |
||||
addAdapter(new SackOfViewsAdapter(views)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Get the data item associated with the specified |
||||
* position in the data set. |
||||
* |
||||
* @param position |
||||
* Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public Object getItem(int position) { |
||||
for (ListAdapter piece : getPieces()) { |
||||
int size=piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return(piece.getItem(position)); |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
return(null); |
||||
} |
||||
|
||||
/** |
||||
* Get the adapter associated with the specified position |
||||
* in the data set. |
||||
* |
||||
* @param position |
||||
* Position of the item whose adapter we want |
||||
*/ |
||||
public ListAdapter getAdapter(int position) { |
||||
for (ListAdapter piece : getPieces()) { |
||||
int size=piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return(piece); |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
return(null); |
||||
} |
||||
|
||||
/** |
||||
* How many items are in the data set represented by this |
||||
* Adapter. |
||||
*/ |
||||
@Override |
||||
public int getCount() { |
||||
int total=0; |
||||
|
||||
for (ListAdapter piece : getPieces()) { |
||||
total+=piece.getCount(); |
||||
} |
||||
|
||||
return(total); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of types of Views that will be |
||||
* created by getView(). |
||||
*/ |
||||
@Override |
||||
public int getViewTypeCount() { |
||||
int total=0; |
||||
|
||||
for (PieceState piece : pieces.getRawPieces()) { |
||||
total+=piece.adapter.getViewTypeCount(); |
||||
} |
||||
|
||||
return(Math.max(total, 1)); // needed for
|
||||
// setListAdapter() before
|
||||
// content add'
|
||||
} |
||||
|
||||
/** |
||||
* Get the type of View that will be created by getView() |
||||
* for the specified item. |
||||
* |
||||
* @param position |
||||
* Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public int getItemViewType(int position) { |
||||
int typeOffset=0; |
||||
int result=-1; |
||||
|
||||
for (PieceState piece : pieces.getRawPieces()) { |
||||
if (piece.isActive) { |
||||
int size=piece.adapter.getCount(); |
||||
|
||||
if (position < size) { |
||||
result=typeOffset + piece.adapter.getItemViewType(position); |
||||
break; |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
typeOffset+=piece.adapter.getViewTypeCount(); |
||||
} |
||||
|
||||
return(result); |
||||
} |
||||
|
||||
/** |
||||
* Are all items in this ListAdapter enabled? If yes it |
||||
* means all items are selectable and clickable. |
||||
*/ |
||||
@Override |
||||
public boolean areAllItemsEnabled() { |
||||
return(false); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the item at the specified position is |
||||
* not a separator. |
||||
* |
||||
* @param position |
||||
* Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public boolean isEnabled(int position) { |
||||
for (ListAdapter piece : getPieces()) { |
||||
int size=piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return(piece.isEnabled(position)); |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
return(false); |
||||
} |
||||
|
||||
/** |
||||
* Get a View that displays the data at the specified |
||||
* position in the data set. |
||||
* |
||||
* @param position |
||||
* Position of the item whose data we want |
||||
* @param convertView |
||||
* View to recycle, if not null |
||||
* @param parent |
||||
* ViewGroup containing the returned View |
||||
*/ |
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
for (ListAdapter piece : getPieces()) { |
||||
int size=piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
|
||||
return(piece.getView(position, convertView, parent)); |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
return(null); |
||||
} |
||||
|
||||
/** |
||||
* Get the row id associated with the specified position |
||||
* in the list. |
||||
* |
||||
* @param position |
||||
* Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public long getItemId(int position) { |
||||
for (ListAdapter piece : getPieces()) { |
||||
int size=piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return(piece.getItemId(position)); |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
return(-1); |
||||
} |
||||
|
||||
@Override |
||||
public int getPositionForSection(int section) { |
||||
int position=0; |
||||
|
||||
for (ListAdapter piece : getPieces()) { |
||||
if (piece instanceof SectionIndexer) { |
||||
Object[] sections=((SectionIndexer)piece).getSections(); |
||||
int numSections=0; |
||||
|
||||
if (sections != null) { |
||||
numSections=sections.length; |
||||
} |
||||
|
||||
if (section < numSections) { |
||||
return(position + ((SectionIndexer)piece).getPositionForSection(section)); |
||||
} |
||||
else if (sections != null) { |
||||
section-=numSections; |
||||
} |
||||
} |
||||
|
||||
position+=piece.getCount(); |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
|
||||
@Override |
||||
public int getSectionForPosition(int position) { |
||||
int section=0; |
||||
|
||||
for (ListAdapter piece : getPieces()) { |
||||
int size=piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
if (piece instanceof SectionIndexer) { |
||||
return(section + ((SectionIndexer)piece).getSectionForPosition(position)); |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
else { |
||||
if (piece instanceof SectionIndexer) { |
||||
Object[] sections=((SectionIndexer)piece).getSections(); |
||||
|
||||
if (sections != null) { |
||||
section+=sections.length; |
||||
} |
||||
} |
||||
} |
||||
|
||||
position-=size; |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
|
||||
@Override |
||||
public Object[] getSections() { |
||||
ArrayList<Object> sections=new ArrayList<Object>(); |
||||
|
||||
for (ListAdapter piece : getPieces()) { |
||||
if (piece instanceof SectionIndexer) { |
||||
Object[] curSections=((SectionIndexer)piece).getSections(); |
||||
|
||||
if (curSections != null) { |
||||
for (Object section : curSections) { |
||||
sections.add(section); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (sections.size() == 0) { |
||||
return(new String[0]); |
||||
} |
||||
|
||||
return(sections.toArray(new Object[0])); |
||||
} |
||||
|
||||
public void setActive(ListAdapter adapter, boolean isActive) { |
||||
pieces.setActive(adapter, isActive); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
public void setActive(View v, boolean isActive) { |
||||
pieces.setActive(v, isActive); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
protected List<ListAdapter> getPieces() { |
||||
return(pieces.getPieces()); |
||||
} |
||||
|
||||
private static class PieceState { |
||||
ListAdapter adapter; |
||||
boolean isActive=true; |
||||
|
||||
PieceState(ListAdapter adapter, boolean isActive) { |
||||
this.adapter=adapter; |
||||
this.isActive=isActive; |
||||
} |
||||
} |
||||
|
||||
private static class PieceStateRoster { |
||||
protected ArrayList<PieceState> pieces=new ArrayList<PieceState>(); |
||||
protected ArrayList<ListAdapter> active=null; |
||||
|
||||
void add(ListAdapter adapter) { |
||||
pieces.add(new PieceState(adapter, true)); |
||||
} |
||||
|
||||
void setActive(ListAdapter adapter, boolean isActive) { |
||||
for (PieceState state : pieces) { |
||||
if (state.adapter==adapter) { |
||||
state.isActive=isActive; |
||||
active=null; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void setActive(View v, boolean isActive) { |
||||
for (PieceState state : pieces) { |
||||
if (state.adapter instanceof SackOfViewsAdapter && |
||||
((SackOfViewsAdapter)state.adapter).hasView(v)) { |
||||
state.isActive=isActive; |
||||
active=null; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
List<PieceState> getRawPieces() { |
||||
return(pieces); |
||||
} |
||||
|
||||
List<ListAdapter> getPieces() { |
||||
if (active == null) { |
||||
active=new ArrayList<ListAdapter>(); |
||||
|
||||
for (PieceState state : pieces) { |
||||
if (state.isActive) { |
||||
active.add(state.adapter); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return(active); |
||||
} |
||||
} |
||||
|
||||
private static class EnabledSackAdapter extends SackOfViewsAdapter { |
||||
public EnabledSackAdapter(List<View> views) { |
||||
super(views); |
||||
} |
||||
|
||||
@Override |
||||
public boolean areAllItemsEnabled() { |
||||
return(true); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEnabled(int position) { |
||||
return(true); |
||||
} |
||||
} |
||||
|
||||
private class CascadeDataSetObserver extends DataSetObserver { |
||||
@Override |
||||
public void onChanged() { |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public void onInvalidated() { |
||||
notifyDataSetInvalidated(); |
||||
} |
||||
} |
||||
} |
@ -1,177 +0,0 @@
@@ -1,177 +0,0 @@
|
||||
/*** |
||||
Copyright (c) 2008-2009 CommonsWare, LLC |
||||
Portions (c) 2009 Google, Inc. |
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may |
||||
not use this file except in compliance with the License. You may obtain |
||||
a copy of the License at |
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software |
||||
distributed under the License is distributed on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
See the License for the specific language governing permissions and |
||||
limitations under the License. |
||||
*/ |
||||
|
||||
package com.commonsware.cwac.sacklist; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
|
||||
/** |
||||
* Adapter that simply returns row views from a list. |
||||
* |
||||
* If you supply a size, you must implement newView(), to |
||||
* create a required view. The adapter will then cache these |
||||
* views. |
||||
* |
||||
* If you supply a list of views in the constructor, that |
||||
* list will be used directly. If any elements in the list |
||||
* are null, then newView() will be called just for those |
||||
* slots. |
||||
* |
||||
* Subclasses may also wish to override areAllItemsEnabled() |
||||
* (default: false) and isEnabled() (default: false), if some |
||||
* of their rows should be selectable. |
||||
* |
||||
* It is assumed each view is unique, and therefore will not |
||||
* get recycled. |
||||
* |
||||
* Note that this adapter is not designed for long lists. It |
||||
* is more for screens that should behave like a list. This |
||||
* is particularly useful if you combine this with other |
||||
* adapters (e.g., SectionedAdapter) that might have an |
||||
* arbitrary number of rows, so it all appears seamless. |
||||
*/ |
||||
public class SackOfViewsAdapter extends BaseAdapter { |
||||
private List<View> views=null; |
||||
|
||||
/** |
||||
* Constructor creating an empty list of views, but with |
||||
* a specified count. Subclasses must override newView(). |
||||
*/ |
||||
public SackOfViewsAdapter(int count) { |
||||
super(); |
||||
|
||||
views=new ArrayList<View>(count); |
||||
|
||||
for (int i=0;i<count;i++) { |
||||
views.add(null); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructor wrapping a supplied list of views. |
||||
* Subclasses must override newView() if any of the elements |
||||
* in the list are null. |
||||
*/ |
||||
public SackOfViewsAdapter(List<View> views) { |
||||
super(); |
||||
|
||||
this.views=views; |
||||
} |
||||
|
||||
/** |
||||
* Get the data item associated with the specified |
||||
* position in the data set. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public Object getItem(int position) { |
||||
return(views.get(position)); |
||||
} |
||||
|
||||
/** |
||||
* How many items are in the data set represented by this |
||||
* Adapter. |
||||
*/ |
||||
@Override |
||||
public int getCount() { |
||||
return(views.size()); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of types of Views that will be |
||||
* created by getView(). |
||||
*/ |
||||
@Override |
||||
public int getViewTypeCount() { |
||||
return(getCount()); |
||||
} |
||||
|
||||
/** |
||||
* Get the type of View that will be created by getView() |
||||
* for the specified item. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public int getItemViewType(int position) { |
||||
return(position); |
||||
} |
||||
|
||||
/** |
||||
* Are all items in this ListAdapter enabled? If yes it |
||||
* means all items are selectable and clickable. |
||||
*/ |
||||
@Override |
||||
public boolean areAllItemsEnabled() { |
||||
return(false); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the item at the specified position is |
||||
* not a separator. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public boolean isEnabled(int position) { |
||||
return(false); |
||||
} |
||||
|
||||
/** |
||||
* Get a View that displays the data at the specified |
||||
* position in the data set. |
||||
* @param position Position of the item whose data we want |
||||
* @param convertView View to recycle, if not null |
||||
* @param parent ViewGroup containing the returned View |
||||
*/ |
||||
@Override |
||||
public View getView(int position, View convertView, |
||||
ViewGroup parent) { |
||||
View result=views.get(position); |
||||
|
||||
if (result==null) { |
||||
result=newView(position, parent); |
||||
views.set(position, result); |
||||
} |
||||
|
||||
return(result); |
||||
} |
||||
|
||||
/** |
||||
* Get the row id associated with the specified position |
||||
* in the list. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public long getItemId(int position) { |
||||
return(position); |
||||
} |
||||
|
||||
public boolean hasView(View v) { |
||||
return(views.contains(v)); |
||||
} |
||||
|
||||
/** |
||||
* Create a new View to go into the list at the specified |
||||
* position. |
||||
* @param position Position of the item whose data we want |
||||
* @param parent ViewGroup containing the returned View |
||||
*/ |
||||
protected View newView(int position, ViewGroup parent) { |
||||
throw new RuntimeException("You must override newView()!"); |
||||
} |
||||
} |
@ -0,0 +1,298 @@
@@ -0,0 +1,298 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import java.util.ArrayList; |
||||
|
||||
import android.database.DataSetObserver; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.Adapter; |
||||
import android.widget.BaseAdapter; |
||||
import android.widget.ListAdapter; |
||||
import android.widget.SectionIndexer; |
||||
import android.widget.TextView; |
||||
|
||||
/** |
||||
* An adapter that can contain many other adapters and shows them in sequence. Taken from |
||||
* http://stackoverflow.com/questions/7964259/android-attaching-multiple-adapters-to-one-adapter and based on the Apache
|
||||
* 2-licensed CommonsWare MergeAdapter. |
||||
* @author Eric Kok |
||||
* @author Alex Amiryan |
||||
* @author Mark Murphy |
||||
*/ |
||||
public class MergeAdapter extends BaseAdapter implements SectionIndexer { |
||||
|
||||
protected ArrayList<ListAdapter> pieces = new ArrayList<ListAdapter>(); |
||||
protected String noItemsText; |
||||
|
||||
/** |
||||
* Stock constructor, simply chaining to the superclass. |
||||
*/ |
||||
public MergeAdapter() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new adapter to the roster of things to appear in the aggregate list. |
||||
* @param adapter Source for row views for this section |
||||
*/ |
||||
public void addAdapter(ListAdapter adapter) { |
||||
pieces.add(adapter); |
||||
adapter.registerDataSetObserver(new CascadeDataSetObserver()); |
||||
} |
||||
|
||||
/** |
||||
* Get the data item associated with the specified position in the data set. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
public Object getItem(int position) { |
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return (piece.getItem(position)); |
||||
} |
||||
|
||||
position -= size; |
||||
} |
||||
|
||||
return (null); |
||||
} |
||||
|
||||
public void setNoItemsText(String text) { |
||||
noItemsText = text; |
||||
} |
||||
|
||||
/** |
||||
* Get the adapter associated with the specified position in the data set. |
||||
* @param position Position of the item whose adapter we want |
||||
*/ |
||||
public ListAdapter getAdapter(int position) { |
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return (piece); |
||||
} |
||||
|
||||
position -= size; |
||||
} |
||||
|
||||
return (null); |
||||
} |
||||
|
||||
/** |
||||
* How many items are in the data set represented by this {@link Adapter}. |
||||
*/ |
||||
public int getCount() { |
||||
int total = 0; |
||||
|
||||
for (ListAdapter piece : pieces) { |
||||
total += piece.getCount(); |
||||
} |
||||
|
||||
if (total == 0 && noItemsText != null) { |
||||
total = 1; |
||||
} |
||||
|
||||
return (total); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of types of {@link View}s that will be created by {@link #getView(int, View, ViewGroup)}. |
||||
*/ |
||||
@Override |
||||
public int getViewTypeCount() { |
||||
int total = 0; |
||||
|
||||
for (ListAdapter piece : pieces) { |
||||
total += piece.getViewTypeCount(); |
||||
} |
||||
|
||||
return (Math.max(total, 1)); // needed for setListAdapter() before
|
||||
// content add'
|
||||
} |
||||
|
||||
/** |
||||
* Get the type of {@link View} that will be created by {@link #getView(int, View, ViewGroup)} for the specified item. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public int getItemViewType(int position) { |
||||
int typeOffset = 0; |
||||
int result = -1; |
||||
|
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
result = typeOffset + piece.getItemViewType(position); |
||||
break; |
||||
} |
||||
|
||||
position -= size; |
||||
typeOffset += piece.getViewTypeCount(); |
||||
} |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
/** |
||||
* Are all items in this {@link ListAdapter} enabled? If yes it means all items are selectable and clickable. |
||||
*/ |
||||
@Override |
||||
public boolean areAllItemsEnabled() { |
||||
return (false); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the item at the specified position is not a separator. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
@Override |
||||
public boolean isEnabled(int position) { |
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return (piece.isEnabled(position)); |
||||
} |
||||
|
||||
position -= size; |
||||
} |
||||
|
||||
return (false); |
||||
} |
||||
|
||||
/** |
||||
* Get a {@link View} that displays the data at the specified position in the data set. |
||||
* @param position Position of the item whose data we want |
||||
* @param convertView View to recycle, if not null |
||||
* @param parent ViewGroup containing the returned View |
||||
*/ |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
|
||||
return (piece.getView(position, convertView, parent)); |
||||
} |
||||
|
||||
position -= size; |
||||
} |
||||
|
||||
if (noItemsText != null) { |
||||
TextView text = new TextView(parent.getContext()); |
||||
text.setText(noItemsText); |
||||
return text; |
||||
} |
||||
|
||||
return (null); |
||||
} |
||||
|
||||
/** |
||||
* Get the row id associated with the specified position in the list. |
||||
* @param position Position of the item whose data we want |
||||
*/ |
||||
public long getItemId(int position) { |
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
return (piece.getItemId(position)); |
||||
} |
||||
|
||||
position -= size; |
||||
} |
||||
|
||||
return (-1); |
||||
} |
||||
|
||||
public final int getPositionForSection(int section) { |
||||
int position = 0; |
||||
|
||||
for (ListAdapter piece : pieces) { |
||||
if (piece instanceof SectionIndexer) { |
||||
Object[] sections = ((SectionIndexer) piece).getSections(); |
||||
int numSections = 0; |
||||
|
||||
if (sections != null) { |
||||
numSections = sections.length; |
||||
} |
||||
|
||||
if (section < numSections) { |
||||
return (position + ((SectionIndexer) piece).getPositionForSection(section)); |
||||
} else if (sections != null) { |
||||
section -= numSections; |
||||
} |
||||
} |
||||
|
||||
position += piece.getCount(); |
||||
} |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
public final int getSectionForPosition(int position) { |
||||
int section = 0; |
||||
|
||||
for (ListAdapter piece : pieces) { |
||||
int size = piece.getCount(); |
||||
|
||||
if (position < size) { |
||||
if (piece instanceof SectionIndexer) { |
||||
return (section + ((SectionIndexer) piece).getSectionForPosition(position)); |
||||
} |
||||
|
||||
return (0); |
||||
} else { |
||||
if (piece instanceof SectionIndexer) { |
||||
Object[] sections = ((SectionIndexer) piece).getSections(); |
||||
|
||||
if (sections != null) { |
||||
section += sections.length; |
||||
} |
||||
} |
||||
} |
||||
|
||||
position -= size; |
||||
} |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
public final Object[] getSections() { |
||||
ArrayList<Object> sections = new ArrayList<Object>(); |
||||
|
||||
for (ListAdapter piece : pieces) { |
||||
if (piece instanceof SectionIndexer) { |
||||
Object[] curSections = ((SectionIndexer) piece).getSections(); |
||||
|
||||
if (curSections != null) { |
||||
for (Object section : curSections) { |
||||
sections.add(section); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (sections.size() == 0) { |
||||
return (null); |
||||
} |
||||
|
||||
return (sections.toArray(new Object[0])); |
||||
} |
||||
|
||||
private class CascadeDataSetObserver extends DataSetObserver { |
||||
@Override |
||||
public void onChanged() { |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public void onInvalidated() { |
||||
notifyDataSetInvalidated(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
import android.widget.ListView; |
||||
|
||||
/** |
||||
* A simple wrapper adapter around a single view, typically for use in a {@link MergeAdapter}. Notably, this adapter |
||||
* handles the proper showing or hiding of the view according to the contained view's visibility if |
||||
* {@link #setViewVisibility(int)} is used on this adapter rather than setting the visibility of the view directly on |
||||
* the view object. This is required since otherwise the adapter's consumer (i.e. a {@link ListView}) does not update |
||||
* the list row accordingly. Use {@link #setViewEnabled(boolean)} to enable or disable this contained view for user |
||||
* interaction. |
||||
* @author Eric Kok |
||||
*/ |
||||
public class ViewHolderAdapter extends BaseAdapter { |
||||
|
||||
private final View view; |
||||
|
||||
/** |
||||
* Instantiates this wrapper adapter with the one and only view to show. It can not be updated and view visibility |
||||
* should be set directly on this adapter using {@link #setViewVisibility(int)}. Use |
||||
* {@link #setViewEnabled(boolean)} to enable or disable this contained view for user interaction. |
||||
* @param view The view that will be wrapper in an adapter to show in a list view |
||||
*/ |
||||
public ViewHolderAdapter(View view) { |
||||
this.view = view; |
||||
} |
||||
|
||||
/** |
||||
* Sets the visibility on the contained view and notifies consumers of this adapter (i.e. a {@link ListView}) |
||||
* accordingly. Use {@link View#GONE} to hide this adapter's view altogether. |
||||
* @param visibility The visibility to set on the contained view |
||||
*/ |
||||
public void setViewVisibility(int visibility) { |
||||
view.setVisibility(visibility); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
/** |
||||
* Sets whether the contained view should be enabled and notifies consumers of this adapter (i.e. a {@link ListView} |
||||
* ) accordingly. A contained enabled view allows user interaction (clicks, focus), while a disabled view does not. |
||||
* @param enabled Whether the contained view should be enabled |
||||
*/ |
||||
public void setViewEnabled(boolean enabled) { |
||||
view.setEnabled(enabled); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
/** |
||||
* Returns 1 if the contained view is {@link View#VISIBLE} or {@link View#INVISIBLE}, return 0 if {@link View#GONE}. |
||||
*/ |
||||
@Override |
||||
public int getCount() { |
||||
return view.getVisibility() == View.VISIBLE ? 1 : 0; |
||||
} |
||||
|
||||
/** |
||||
* Always directly returns the single contained view instance. |
||||
*/ |
||||
@Override |
||||
public Object getItem(int position) { |
||||
return view; |
||||
} |
||||
|
||||
/** |
||||
* Always returns the position directly as item id. |
||||
*/ |
||||
@Override |
||||
public long getItemId(int position) { |
||||
return position; |
||||
} |
||||
|
||||
/** |
||||
* Always directly returns the single contained view instance. |
||||
*/ |
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
return view; |
||||
} |
||||
|
||||
/** |
||||
* Always returns true, as there is only one contained item and it is never changed. |
||||
*/ |
||||
@Override |
||||
public boolean hasStableIds() { |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Returns false, as the contained view can still be enabled and disabled. |
||||
*/ |
||||
@Override |
||||
public boolean areAllItemsEnabled() { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the contained view is enabled, returns false otherwise. |
||||
*/ |
||||
@Override |
||||
public boolean isEnabled(int position) { |
||||
return view.isEnabled(); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue