Sectioned GridView in android - android

I am following this https://github.com/madhu314/sectionedgridview for sectioned gridview.
In data_item.xml I have checkbox instead of imagebutton. I want to check multiple items and then send the checked item to another activity.
The problem that I am facing is, that when i scroll the listview up or down, the checkboxes that are checked get unchecked and different checkboxes are checked.
I need help regarding this. Any help will be greatly appreciated.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = null;
boolean isSectionheader = isSectionHeader(position);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (isSectionheader) {
v = inflater.inflate(R.layout.section_header, null);
} else {
LinearLayout ll = (LinearLayout) inflater.inflate(
R.layout.list_row, null);
v = ll;
ll = (LinearLayout) ll.findViewById(R.id.row_item);
// add childrenCount to this
for (int i = 0; i < numberOfChildrenInRow; i++) {
// add a child
View child = inflater.inflate(R.layout.data_item, null);
ll.addView(child, new LinearLayout.LayoutParams(
gridItemSize, gridItemSize));
if (i < numberOfChildrenInRow - 1) {
// now add space view
View spaceItem = new View(mContext);
ll.addView(spaceItem, new LinearLayout.LayoutParams(
childrenSpacing[i], ll.getHeight()));
}
}
}
} else {
v = convertView;
}
String sectionName = whichSection(position);
if (isSectionheader) {
TextView tv = (TextView) v;
tv.setText(sectionName);
} else {
LinearLayout ll = (LinearLayout) v;
LinearLayout rowPanel = (LinearLayout) ll.findViewById(R.id.row_item);
View divider = ll.findViewById(R.id.row_item_divider);
divider.setVisibility(View.VISIBLE);
// check if this position corresponds to last row
boolean isLastRowInSection = isLastRowInSection(position);
int positionInSection = positionInSection(position);
Cursor c = sectionCursors.get(sectionName);
// --
int cursorStartAt = numberOfChildrenInRow * positionInSection;
// set all children visible first
for (int i = 0; i < 2 * numberOfChildrenInRow - 1; i++) {
// we need to hide grid item and gap
View child = rowPanel.getChildAt(i);
child.setVisibility(View.VISIBLE);
// leave alternate
if (i % 2 == 0) {
// its not gap
if (c.moveToPosition(cursorStartAt)) {
String dataName = c.getString(0);
TextView tv = (TextView) child
.findViewById(R.id.data_item_text);
tv.setText(dataName);
}
// set listener on image button
checkbox = (CheckBox) child
.findViewById(R.id.data_item_image);
ButtonViewHolder holder = new ButtonViewHolder();
holder.sectionName = sectionName;
holder.positionInSection = cursorStartAt;
holder.parent = child;
holder.position = position;
checkbox.setTag(holder);
checkbox.setOnCheckedChangeListener(this);
cursorStartAt++;
}
}
checkbox.setChecked(mSparseBooleanArray.get(position));
if (isLastRowInSection) {
divider.setVisibility(View.INVISIBLE);
// check how many items needs to be hidden in last row
int sectionCount = sectionCursors.get(sectionName).getCount();
int childrenInLastRow = sectionCount % numberOfChildrenInRow;
if (childrenInLastRow > 0) {
int gaps = childrenInLastRow - 1;
for (int i = childrenInLastRow + gaps; i < rowPanel
.getChildCount(); i++) {
// we need to hide grid item and gap
View child = rowPanel.getChildAt(i);
child.setVisibility(View.INVISIBLE);
}
}
}
}
return v;
}

As per your question, you need to select the multiple images and after that you need to do an action (like coping selected images, delete / upload etc). So for that you need to hold the selection image positions as well as you need to change the selection color too..
For that i simply created an adapter, it having the multiple image selection and various methods to get the selected images and select all/ de select all options.. In this i controlled all the possibilities think so.. If it is the same means, change your adapter class like this..
Here is my adapter class:
public class LocalFilesUploadAdapter extends BaseAdapter
{
private final HashMap<Integer, Boolean> myChecked = new HashMap<Integer, Boolean>();
private final Activity _activity;
private ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>();
ArrayList<String> listPaths;
ArrayList<String> listNames;
private LayoutInflater inflater = null;
public LocalFilesUploadAdapter( Context context,
Activity activity,
ArrayList<String> filePaths,
ArrayList<String> fileNames,
ArrayList<Bitmap> bitmaps )
{
this._activity = activity;
this.listPaths = filePaths;
this.listNames = fileNames;
this.bitmaps = bitmaps;
inflater = LayoutInflater.from( context );
for( int i = 0; i < filePaths.size(); i++ )
{
myChecked.put( i,
false );
}
}
public void toggleChecked( int position )
{
if( myChecked.get( position ) )
{
myChecked.put( position,
false );
}
else
{
myChecked.put( position,
true );
}
notifyDataSetChanged();
}
public void selectAllItems( int position )
{
myChecked.put( position,
true );
notifyDataSetChanged();
}
public void deSelectAllItems( int position )
{
myChecked.put( position,
false );
notifyDataSetChanged();
}
public List<Integer> getCheckedItemPositions()
{
List<Integer> checkedItemPositions = new ArrayList<Integer>();
for( int i = 0; i < myChecked.size(); i++ )
{
if( myChecked.get( i ) )
{
( checkedItemPositions ).add( i );
}
}
return checkedItemPositions;
}
public ArrayList<String> getCheckedItems()
{
ArrayList<String> checkedItems = new ArrayList<String>();
// ArrayList<HashMap<String, String>> checkedItems = new ArrayList<HashMap<String, String>>();
for( int i = 0; i < myChecked.size(); i++ )
{
if( myChecked.get( i ) )
{
String pathName = listPaths.get( i );
( checkedItems ).add( pathName );
}
}
return checkedItems;
}
public ArrayList<String> getCheckedItemNames()
{
ArrayList<String> checkedItems = new ArrayList<String>();
// ArrayList<HashMap<String, String>> checkedItems = new ArrayList<HashMap<String, String>>();
for( int i = 0; i < myChecked.size(); i++ )
{
if( myChecked.get( i ) )
{
String imageName = listNames.get( i );
( checkedItems ).add( imageName );
}
}
return checkedItems;
}
public boolean selectAll()
{
for( int i = 0; i < listPaths.size(); i++ )
{
selectAllItems( i );
}
return false;
}
public boolean deSelectAll()
{
for( int i = 0; i < listPaths.size(); i++ )
{
deSelectAllItems( i );
}
return false;
}
#Override
public int getCount()
{
// TODO Auto-generated method stub
if( 0 == listPaths.size() )
{
return 0;
}
return this.listPaths.size();
}
#Override
public Object getItem( int position )
{
// TODO Auto-generated method stub
return this.listPaths.get( position );
}
#Override
public long getItemId( int position )
{
// TODO Auto-generated method stub
return position;
}
#Override
public View getView( final int position,
View convertView,
ViewGroup parent )
{
View row = convertView;
if( row == null )
{
row = inflater.inflate( R.layout.gridview_item,
null );
}
Log.d( "debug",
"position" + position );
ImageView imageView = (ImageView) row.findViewById( R.id.grid_image );
CheckBox checkbox = (CheckBox) row.findViewById( R.id.img_checkBox );
imageView.setImageBitmap( bitmaps.get( position ) );
checkbox.setOnClickListener( new OnClickListener()
{
#Override
public void onClick( View v )
{
// TODO Auto-generated method stub
toggleChecked( position );
}
} );
Boolean checked = myChecked.get( position );
if( checked != null )
{
checkbox.setChecked( checked );
}
imageView.setOnClickListener( new OnImageClickListener( position ) );
return row;
}
class OnImageClickListener implements OnClickListener
{
int _postion;
// constructor
public OnImageClickListener( int position )
{
this._postion = position;
}
#Override
public void onClick( View v )
{
// on selecting grid view image
// launch full screen activity
toggleChecked( _postion );
}
}
}
Hope it vll help's you

Related

How to fix "UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView"

I want to saveInstance when changing from portrait to landscape. But when I try to restoreInstance of my letter button's background and enable, it tells me this error.
The program went well when I comment out those codes.
This is letter class
public class Letter extends BaseAdapter {
private String[] letters;
private LayoutInflater letterInf;
public Letter(Context c){
letters = new String[26];
for(int a = 0; a < letters.length; a++){
letters[a] = ""+(char)(a+'A');
}
letterInf = LayoutInflater.from(c);
}
#Override
public int getCount() {
return letters.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Button btnLetter;
if(convertView == null){
btnLetter = (Button) letterInf.inflate(R.layout.letter, null, false);
}else{
btnLetter = (Button) convertView;
}
btnLetter.setText(letters[position]);
return btnLetter;
}
}
This is what I try to restore onRestoreInstance (the whole version)
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
currPart = savedInstanceState.getInt("currPart");
numChars = savedInstanceState.getInt("numChars");
numCorr = savedInstanceState.getInt("numCorr");
int[] savedBodyPartVisibility = savedInstanceState.getIntArray("bodyPartVisibility");
for(int i = 0; i<savedBodyPartVisibility.length; i++){
bodyParts[i].setVisibility(savedBodyPartVisibility[i]);
}
//saved word
currWord = savedInstanceState.getString("currWord");
hint = savedInstanceState.getString("hint");
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){//get orientation
tvHint.setText("Hint:"+hint);// if landscape, show hint
//Toast.makeText(getBaseContext(), "This is landscape!", Toast.LENGTH_SHORT).show();
}
charViews = new TextView[currWord.length()];
wordLayout.removeAllViews();
for(int c = 0; c<currWord.length(); c++){
charViews[c] = new TextView(this);
charViews[c].setText(""+currWord.charAt(c));
charViews[c].setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
charViews[c].setGravity(Gravity.CENTER);
charViews[c].setTextColor(Color.WHITE);
charViews[c].setBackgroundResource(R.drawable.letter_bg);
wordLayout.addView(charViews[c]);
}
//saved charView
int[] savedCharViewColor = savedInstanceState.getIntArray("charViewColor");
for(int i = 0; i< savedCharViewColor.length; i++){
charViews[i].setTextColor(savedCharViewColor[i]);
}
//int numLetters = savedInstanceState.getInt("numLetters");
//letter enable//letter button background color
boolean[] savedLetterEnable = savedInstanceState.getBooleanArray("letterEnable");
int[] savedLettersColor = savedInstanceState.getIntArray("lettersColor");
for(int i = 0; i<savedLetterEnable.length; i++){
letters.getChildAt(i).setEnabled(savedLetterEnable[i]);
//letters.getChildAt(i).setBackgroundColor(savedLettersColor[i]);
}
}
You cannot restore it this way because views are recycled in RecyclerView/ListView. It means that only some of them is rendered and when you scroll it reuses already rendered views.
So in most of the cases it will not have that many child views as items in datasource.
The proper approach is to store information about items' state inside adapter.
I have created simple example to give you an idea how could it look. Note that setOnSelectedListener(new OnSelectedListener(){...} is fake code and you should write proper listener (onClick, or if you want to use Checkboxes then onCheckedCHange or anything else based on your needs).
public class Letter extends BaseAdapter {
private String[] letters;
private LayoutInflater letterInf;
private Set<String> selectedLetters = new ArraySet();
public Letter(Context c){
letters = new String[26];
for(int a = 0; a < letters.length; a++){
letters[a] = ""+(char)(a+'A');
}
letterInf = LayoutInflater.from(c);
}
Set<String> getState() {
return selectedLetters;
}
void restoreState(Set<String> selectedLetters) {
this.selectedLetters = selectedLetters;
notifyDataSetInvalidated();
}
#Override
public int getCount() {
return letters.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Button btnLetter;
if(convertView == null){
btnLetter = (Button) letterInf.inflate(R.layout.letter, null, false);
}else{
btnLetter = (Button) convertView;
}
if(selectedLetters.contains(letters[position])) {
btnLetter.setSelected(true);
} else {
btnLetter.setSelected(false);
}
btnLetter.setOnSelectedListener(new OnSelectedListener() {
void onSelected(..., boolean isSelected) {
if(isSelected) {
selectedLetters.add(letters[position]);
} else {
selectedLetters.remove(letters[position]);
}
}
});
btnLetter.setText(letters[position]);
return btnLetter;
}
}
Then whenever you save state, you get it from adapter getState and put it in savedInstanceState.
Whenever you restore state you get it from savedState and put in adapter restoreState

Highlight effect while pressing item in custom ListView adapter

There's a system visual effect everytime you click a view in Android. In Lollipop it's the ripple effect. When I created a ListView and associated it to an ordinary ArrayAdapter, this effect was present. Now that I've added a custom ListView, this effect is lost.
Now, I've tried to isolate what the problem is, and since using the same list item layout with a default adapter worked nicely, I would say that the problem is on my custom adapter.
I've seen many solutions related to this case that just implemented the ripple effect calling some drawables; this is not what I'm trying to do. The ripple effect shows only because I'm running the app on Android 5, now what I want to do is to have the default system highlight effect for my items when they're being clicked.
Here are the (hopefully) related pieces of my custom adapter:
public class CustomCardSetsAdapter extends BaseAdapter {
List<Card> totalList;
ArrayList<Boolean> hiddenItems;
ListView parentLV;
Integer curPosition = -1;
public static int selectedRowIndex;
public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
{
this.parentLV = parentListView;
assignSetValues(cardList);
totalList = cardList.getBlackrockMountain();
totalList.addAll(cardList.getClassic());
totalList.addAll(cardList.getCurseofNaxxramas());
totalList.addAll(cardList.getGoblinsvsGnomes());
Collections.sort(totalList,
new Comparator<Card>() {
public int compare(Card f1, Card f2) {
return f1.toString().compareTo(f2.toString());
}
});
hiddenItems = new ArrayList<>();
for (int i = 0; i < totalList.size(); i++) {
if(!totalList.get(i).getCollectible())
hiddenItems.add(true);
else
hiddenItems.add(false);
}
}
#Override
public int getCount() {
return (totalList.size() - getHiddenCount());
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final int index = getRealPosition(position);
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
}
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer prevPosition = curPosition;
curPosition = position;
if(prevPosition >= parentLV.getFirstVisiblePosition() &&
prevPosition <= parentLV.getLastVisiblePosition())
{
View view = parentLV.getChildAt(prevPosition- parentLV.getFirstVisiblePosition());
parentLV.getAdapter().getView(prevPosition,view, parentLV);
}
v.setBackgroundColor(Color.WHITE);
}
});
Card curCard = totalList.get(index);
TextView cardName = (TextView) convertView.findViewById(R.id.cardName);
cardName.setText(curCard.getName());
setRarityColor(curCard,cardName);
TextView manaCost = (TextView) convertView.findViewById(R.id.manaCost);
manaCost.setText((curCard.getCost()).toString());
ImageView setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
setSetIcon(curCard,setIcon);
if(position == curPosition)
convertView.setBackgroundColor(Color.WHITE);
else
convertView.setBackgroundColor(Color.TRANSPARENT);
return convertView;
}
#Override
public int getItemViewType(int position) {
return R.layout.card_list_item;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean isEmpty() {
return false;
}
private int getHiddenCount()
{
int count = 0;
for(int i = 0;i <totalList.size();i++)
if(hiddenItems.get(i))
count++;
return count;
}
private int getRealPosition(int position) {
int hElements = getHiddenCountUpTo(position);
int diff = 0;
for(int i=0;i<hElements;i++) {
diff++;
if(hiddenItems.get(position+diff))
i--;
}
return (position + diff);
}
private int getHiddenCountUpTo(int location) {
int count = 0;
for(int i=0;i<=location;i++) {
if(hiddenItems.get(i))
count++;
}
return count;
}
}
Thanks in advance.
in your ListView XML, add:
android:drawSelectorOnTop="true"
I also think you are using your adapter wrong...
Use the ViewHolder Pattern on your Adapter:
public class CustomCardSetsAdapter extends BaseAdapter {
List<Card> totalList;
ArrayList<Boolean> hiddenItems;
ListView parentLV;
Integer curPosition = -1;
public static int selectedRowIndex;
private class ViewHolderRow{
TextView cardName;
TextView manaCost;
ImageView setIcon;
}
public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
{
this.parentLV = parentListView;
assignSetValues(cardList);
totalList = cardList.getBlackrockMountain();
totalList.addAll(cardList.getClassic());
totalList.addAll(cardList.getCurseofNaxxramas());
totalList.addAll(cardList.getGoblinsvsGnomes());
Collections.sort(totalList,
new Comparator<Card>() {
public int compare(Card f1, Card f2) {
return f1.toString().compareTo(f2.toString());
}
});
hiddenItems = new ArrayList<>();
for (int i = 0; i < totalList.size(); i++) {
if(!totalList.get(i).getCollectible())
hiddenItems.add(true);
else
hiddenItems.add(false);
}
}
#Override
public int getCount() {
return (totalList.size() - getHiddenCount());
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final int index = getRealPosition(position);
ViewHolderRow theRow;
if(convertView == null) {
theRow = new ViewHolderRow();
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
// Cache your views
theRow.cardName = (TextView) convertView.findViewById(R.id.cardName);
theRow.manaCost = (TextView) convertView.findViewById(R.id.manaCost);
theRow.setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
// Set the Tag to the ViewHolderRow
convertView.setTag(theRow);
}else{
// get the Row to re-use
theRow = (ViewHolderRow) convertView.getTag();
}
//... Removed convertView.setOnClickListener
Card curCard = totalList.get(index);
// Set Items
theRow.cardName.setText(curCard.getName());
setRarityColor(curCard,theRow.cardName);
theRow.manaCost.setText((curCard.getCost()).toString());
setSetIcon(curCard,theRow.setIcon);
if(position == curPosition){
convertView.setBackgroundColor(Color.WHITE);
}else{
convertView.setBackgroundColor(Color.TRANSPARENT);
}
return convertView;
}
#Override
public int getItemViewType(int position) {
return R.layout.card_list_item;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean isEmpty() {
return false;
}
private int getHiddenCount()
{
int count = 0;
for(int i = 0;i <totalList.size();i++)
if(hiddenItems.get(i))
count++;
return count;
}
private int getRealPosition(int position) {
int hElements = getHiddenCountUpTo(position);
int diff = 0;
for(int i=0;i<hElements;i++) {
diff++;
if(hiddenItems.get(position+diff))
i--;
}
return (position + diff);
}
private int getHiddenCountUpTo(int location) {
int count = 0;
for(int i=0;i<=location;i++) {
if(hiddenItems.get(i))
count++;
}
return count;
}
}
Set an onListItemClickListener instead of using this on the entire convertView...
yourListView.setOnItemClickListener(ListListener);
private final OnItemClickListener ListListener = new OnItemClickListener{
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
// ... Do something on click
}
}

Adding a new row dynamically using a button

I am trying to add rows in a list view when a button is clicked , but my application is getting crashed everytime .
Here is my code :
public class MTCRichGraphicsActivity extends Activity {
int ELEMENT_COUNT = 3;
int position=0;
Button bAddView;
String[] elements = new String[ELEMENT_COUNT];
int r =0 ;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bAddView = (Button) findViewById(R.id.bNewEvent);
final ListView list = (ListView) findViewById(R.id.list3d);
bAddView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.bNewEvent :
for (int i = 0; i< ELEMENT_COUNT; i++) {
elements[i] = String.valueOf(i);
}
final MyAdapter adapter = new MyAdapter(MTCRichGraphicsActivity.this,elements);
adapter.notifyDataSetChanged();
//list.setScrollY(currentPosition);
//list.setTranslationY(currentPosition);
list.setDivider( null );
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
ELEMENT_COUNT = ELEMENT_COUNT + 3;
}
}
});
}
}
Here I want to add 3 rows everytime a button(i.e. bNewEvent) is clicked , so I am incrementing ELEMENT_COUNT by 3 everytime. It works fine for first time , but when I press button second time it crashes.
Here is my adapter class :
public class MyAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private final String[] mItems;
TextView t;
ViewHolder holder;
public MyAdapter(Activity c,String[] objects) {
mInflater = c.getLayoutInflater();
mItems = objects;
}
public int getCount() {
return mItems.length;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView t;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem2, parent,false);
}
holder = new ViewHolder();
holder.t1 = (TextView) convertView.findViewById(R.id.tv1);
holder.t2 = (TextView) convertView.findViewById(R.id.tv2);
holder.t3 = (TextView) convertView.findViewById(R.id.tv3);
holder.t4 = (TextView) convertView.findViewById(R.id.tv4);
holder.t1.setText("Title"+position);
position = position + 3;
//((ImageView)convertView).setTextAlignment(1);
return convertView;
}
#Override
public Object getItem(int position) {
return mItems[position];
}
#Override
public long getItemId(int position) {
return position;
}
}
you can't use an array like this..
String[] elements = new String[ELEMENT_COUNT];
causes the array to have the same number of elements as the initial value of ELEMENT_COUNT, you can't then just increment ELEMENT_COUNT by 3 and try
for (int i = 0; i< ELEMENT_COUNT; i++) {
elements[i] = String.valueOf(i);
}
as the array only contains as many elements are initially defined. You need to change 'elements' to an ArrayList.
ArrayList<string> elements;
U define
int ELEMENT_COUNT = 3;
String[] elements = new String[ELEMENT_COUNT];
But u can't Resize Array
for (int i = 0; i< ELEMENT_COUNT; i++) {
elements[i] = String.valueOf(i);
}
this So u got Exception
Change Array To List
Like
List<String> element =new ArrayList<String>();
for (int i = 0; i< ELEMENT_COUNT; i++) {
element.add("String.valueOf(i)")
}
and Change Adapter also Like This

Android AlphabetIndexer English and Hebrew(Unicode) togather

Following is my listview adapter classes using AlphabetIndexer.
It does not work when I add unicode chars (for hebrew) togather with the english.
I get exception in: getSectionForPosition. getting to index -1....
Tries it with 2 entries in the DB - 1 starting with hebrew char (unicode) and one with english. The first char for AlphabetIndexer was the unicode char.
Really really need help in this one....
public abstract class RecipeListViewAdapter extends SimpleCursorAdapter implements SectionIndexer
{
protected Context mContext;
protected Cursor mCursor;
private LayoutInflater mInflater;
public static final int TYPE_HEADER = 1;
public static final int TYPE_NORMAL = 0;
private static final int TYPE_COUNT = 2;
private AlphabetIndexer indexer;
private int[] usedSectionNumbers;
private Map<Integer, Integer> sectionToOffset;
private Map<Integer, Integer> sectionToPosition;
protected ImageLoader mImageLoader = new ImageLoader( MyApp.Instance() );
public RecipeListViewAdapter( Context context,
int layout,
Cursor c,
String[] from,
int[] to )
{
super(context, layout, c, from, to);
mContext = context;
mCursor = c;
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
indexer = new AlphabetIndexer(c, c.getColumnIndexOrThrow("NAME"), "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
sectionToPosition = new TreeMap<Integer, Integer>();
sectionToOffset = new HashMap<Integer, Integer>();
final int count = super.getCount();
int i;
for( i = count - 1 ; i >= 0; i-- )
{
sectionToPosition.put(indexer.getSectionForPosition(i), i);
}
i = 0;
usedSectionNumbers = new int[sectionToPosition.keySet().size()];
for( Integer section : sectionToPosition.keySet() )
{
sectionToOffset.put(section, i);
usedSectionNumbers[i] = section;
i++;
}
for(Integer section: sectionToPosition.keySet())
{
sectionToPosition.put(section, sectionToPosition.get(section) + sectionToOffset.get(section));
}
}
#Override
public int getCount()
{
if( super.getCount() != 0 )
{
return super.getCount() + usedSectionNumbers.length;
}
return 0;
}
#Override
public Object getItem(int position)
{
if (getItemViewType(position) == TYPE_NORMAL) //we define this function later
{
return super.getItem( GetItemPosition( position ) );
}
return null;
}
public int GetItemPosition( final int position )
{
return position - sectionToOffset.get(getSectionForPosition(position)) - 1;
}
public int getPositionForSection(int section) {
if (! sectionToOffset.containsKey(section)){
int i = 0;
int maxLength = usedSectionNumbers.length;
while (i < maxLength && section > usedSectionNumbers[i]){
i++;
}
if (i == maxLength) return getCount();
return indexer.getPositionForSection(usedSectionNumbers[i]) + sectionToOffset.get(usedSectionNumbers[i]);
}
return indexer.getPositionForSection(section) + sectionToOffset.get(section);
}
public int getSectionForPosition(int position) {
int i = 0;
int maxLength = usedSectionNumbers.length;
while (i < maxLength && position >= sectionToPosition.get(usedSectionNumbers[i])){
i++;
}
return usedSectionNumbers[i-1];
}
public Object[] getSections() {
return indexer.getSections();
}
//nothing much to this: headers have positions that the sectionIndexer manages.
#Override
public int getItemViewType(int position) {
if (position == getPositionForSection(getSectionForPosition(position))){
return TYPE_HEADER;
} return TYPE_NORMAL;
}
#Override
public int getViewTypeCount() {
return TYPE_COUNT;
}
#Override
public View getView( int position,
View convertView,
ViewGroup parent )
{
final int type = getItemViewType(position);
if (type == TYPE_HEADER)
{
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.header, parent, false);
}
((TextView)convertView.findViewById(R.id.header)).setText((String)getSections()[getSectionForPosition(position)]);
return convertView;
}
else
{
ViewHolder holder = new ViewHolder();
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.recipes_list_view_entry, null);
holder.name = (TextView) convertView.findViewById( R.id.name_entry );
holder.author = (TextView) convertView.findViewById( R.id.username_entry );
holder.ratingBar = (RatingBar) convertView.findViewById( R.id.list_RatingBarId );
holder.userRatingBar = (RatingBar) convertView.findViewById( R.id.list_userRatingBarId );
holder.diffculty = (ImageView) convertView.findViewById( R.id.list_DifficultyImageViewId );
holder.preparationTime = (ImageView) convertView.findViewById( R.id.list_TimeImageViewId );
holder.recipePic = new DisplayableImageView( (ImageView) convertView.findViewById( R.id.list_RecipeImageViewId ) );
holder.name.setTypeface( MyApp.Fonts.ARIAL );
holder.name.setTextSize( MyApp.Fonts.RUNNING_TEXT_SIZE );
holder.name.setTextColor( Color.BLACK );
}
else
{
holder = (ViewHolder) convertView.getTag();
}
if( super.getItem( GetItemPosition(position) ) != null )
{
// Check if single
if( getCount() == position+1 && position == 1 )
{
convertView.setBackgroundResource( R.drawable.list_single );
}
else if( getItemViewType(position-1) == TYPE_HEADER )
{
// Check if single item in the middle of the list
if( getItemViewType(position+1) == TYPE_HEADER )
{
convertView.setBackgroundResource( R.drawable.list_single );
}
else if( position == getCount() - 1 )
{
convertView.setBackgroundResource( R.drawable.list_single );
}
else
{
convertView.setBackgroundResource( R.drawable.list_up );
}
}
else
{
// Middle or bottom
convertView.setBackgroundResource( R.drawable.list_middle );
//If not last
if( getCount() != position + 1 )
{
// Check if middle or down
if( getItemViewType(position+1) == TYPE_HEADER )
{
convertView.setBackgroundResource( R.drawable.list_down );
}
else
{
convertView.setBackgroundResource( R.drawable.list_middle );
}
}
else
{
// If it is last - use list_down
convertView.setBackgroundResource( R.drawable.list_down );
}
}
FillRecipeDataToHolder( GetItemPosition(position), holder );
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
return convertView;
}
}
//these two methods just disable the headers
#Override
public boolean areAllItemsEnabled() {
return false;
}
#Override
public boolean isEnabled(int position) {
if (getItemViewType(position) == TYPE_HEADER){
return false;
}
return true;
}
protected abstract void FillRecipeDataToHolder(int position, ViewHolder holder);
static class ViewHolder
{
TextView separator;
DisplayableImageView recipePic;
TextView name;
TextView author;
RatingBar ratingBar;
RatingBar userRatingBar;
ImageView diffculty;
ImageView preparationTime;
TextView serveCount;
}
}

Update TextView within custom ListView

I'm trying to update the TextView within a custom ListView at a set time interval, for example the TextView will update every 200ms however I can't figure out how to do this. The object updates with a number internally and I would like to show that in the mTitleText Textview however as the code below shows at the moment I can only achieve it when the user presses a button.
public class ListAdapter extends BaseAdapter {
private ArrayList< Object > mObjects;
private int mNumObjs = 0;
private LayoutInflater mLayoutInflater;
private Context mContext;
public ListAdapter ( Context context, ArrayList< Object > objects ) {
mObjects;= objects;
mLayoutInflater = LayoutInflater.from(context);
mContext = context;
}
public int getCount() {
return mObjects;.size();
}
public Object getItem( int position ) {
return mObjects;.get(position);
}
public long getItemId( int position ) {
return position;
}
public void addObject( Object obj) {
obj.setId(mNumObjs);
mObjects.add( obj );
(mNumObjs);++;
notifyDataSetChanged();
}
public void deleteObject( int pos ) {
mObjects;.remove( pos );
notifyDataSetChanged();
}
public View getView( final int position, View convertView, ViewGroup parent ) {
final TimerView holder;
if( convertView == null ) {
convertView = mLayoutInflater.inflate( R.layout.customlistview, null );
holder = new HolderView();
holder.mListPosition = position;
holder.mDeleteButton = (Button)convertView.findViewById(R.id.Delete);
holder.mDeleteButton.setText( "Button No: " + position );
holder.mDeleteButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
deleteObject(holder.mListPosition);
}
});
holder.mButton = (Button)convertView.findViewById(R.id.Button);
holder.mButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Object obj = mObjects.get(holder.mListPosition);
mTitleText.setText(obj.getNum());
}
});
convertView.setTag(holder);
}
else {
holder = (TimerView) convertView.getTag();
}
holder.mListPosition = position;
holder.mDeleteButton.setText( "Button No: " + position );
return convertView;
}
class HolderView{
int mListPosition;
Button mDeleteButton;
Button mButton;
TextView mTitleText;
}
}
Okay I managed to figure this out myself, if your updates don't need to be very frequent ( >1 sec ) you can use notifyDataSetChanged() however if like me you need to constantly update the listview every 200ms or so you need to iterate through the visible objects on the list view and update it.
private Runnable showUpdate = new Runnable(){
public void run(){
mAdapter.updateList();
//mAdapter.notifyDataSetChanged();
int count = mListView.getCount();
for( int i = 0; i < count; i ++ )
{
View convertView = mListView.getChildAt( i );
if( convertView != null )
{
HolderView holder = (HolderView) convertView.getTag();
Object obj = (Object)mAdapter.getItem( holder.mListPosition );
holder.mTitleText.setText( obj.getText() );
}
}
}
};
Thread mThread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(100);
mHandler.post(showUpdate);
//mHandler.sendEmptyMessage(MSG_UPDATE);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Update the text in your list mObjects and call notifyDataSetChanged() on your adapter.

Categories

Resources