I have a big problem and I tried to debug it for a long time but I can not get the error.
I have a Listview and load it with pictures, where the Path is saved in the database.
Its all works fine, but I have one Problem:
If I have e.g. 4 items. The first two have pictures and the last 2 not. So the last item in the list always have the picture from the last item which had a picture and I can not figure out why. I looked in the database if it maybe have a Path in it for the last element but its empty.
There is my code:
SimpleCursorAdapter adapter;
adapter = new SimpleCursorAdapter(this, R.layout.my_listlayout,
MainController.getInstance().getMyCursor(db),
new String[] {"F1", "F2", "F3", "F4"},
new int[] {R.id.imageViewF1, R.id.textViewF2, R.id.textViewF3, R.id.textViewF4}, 0);
adapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (columnIndex == 1) {
ImageView imageView = (ImageView) view;
String Pic = cursor.getString(1);
if (Pic != null) {
// load the picture in the view
imageView.setImageDrawable(...);
}
return true;
}
if (columnIndex == 2) {
//..
}
if (columnIndex == 3) {
//..
}
if (columnIndex == 4) {
//..
}
return false;
}
});
ListView view = (ListView)findViewById(R.id.listViewFirst);
view.setAdapter(adapter);
Maybe I'M doing something wrong in the adapter?
Related
I'm using multiple selection on the listview in my app which is being populated by db (SimpleCursorAdapter). There's some weird behavior with the listview selection.
If there are more than 7 items in the database, if I select the 1st item in the listview, the 8th item also gets selected even when I'm not selecting the 8th item and vice-versa. If I select the 9th item, the 2nd row gets selected.
What's happening here?
Code:
String[] projection = { ..table_columns..};
String[] from = { table_columns..};
Cursor cursor = contentResolver.query(SomeContentProvider.CONTENT_URI, projection, null, null,
null);
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.color,
R.id.name,
R.id.desc,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.layout_main,
cursor,
from,
to,
0);
dataAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int column) {
int nNameIndex = cursor.getColumnIndexOrThrow(EventsTable.COLUMN_NAME);
if( column == nNameIndex ){
TextView nname = (TextView) view;
String name = cursor.getString(cursor.getColumnIndex(EventsTable.COLUMN_NAME));
String formatted_name = "NAME: " +name;
nname.setText(formatted_name);
return true;
}
return false;
}
});
listView.setAdapter(dataAdapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
if (!listView.isItemChecked(pos)){
listView.setItemChecked(pos, true);
v.setBackground(getResources().getDrawable(R.drawable.listview_bg_selected));
v.setSelected(true);
} else {
listView.setItemChecked(pos, false);
v.setBackground(getResources().getDrawable(R.drawable.listview_bg));
v.setSelected(false);
}
if (listView.getCheckedItemCount() > 0) {
if (mMode == null) {
mMode = startActionMode(new ActionModeCallback());
} else {
mMode.setTitle(listView.getCheckedItemCount() + " " + "Selected");
}
} else {
if (mMode != null) {
mMode.finish();
}
}
return true;
}
});
I suspect it's because in your bindView of your adapter you are not checking if the item is checked, and then changing the background appropriately.
You experiencing your views being recycled.
So when you scroll, and say item one goes out of view and was selected, the view for item 1 is reused for item 8.
SO add something like this to your view binder
int post = cursor.getPosition();
if (!listView.isItemChecked(pos)){
v.setBackground(getResources().getDrawable(R.drawable.listview_bg_selected));
} else {
v.setBackground(getResources().getDrawable(R.drawable.listview_bg));
}
Im trying to change text color in a listview, which is displaying my entries from database. The problem is that it displays invisible text ( or it displays nothing at all. only the lines which are separating my entries on this list) but after clicking on entry it shows me details from this entries. Displaying works good without trying to use ViewBinder.
// map each name to a TextView
String[] from = new String[] { "event" };
int[] to = new int[] { R.id.countryTextView };
conAdapter = new SimpleCursorAdapter(Clock.this, R.layout.day_plan, null, from, to);
SimpleCursorAdapter.ViewBinder binder = new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex){
int getIndex = cursor.getColumnIndex("colour");
String empname = cursor.getString(getIndex);
tv = (TextView)findViewById(R.id.countryTextView);
tv.setTextColor(Color.WHITE);
if(empname.equals("Green"))
{
tv.setTextColor(Color.WHITE);
return true;
}
return false;
}
};
setListAdapter(conAdapter); // set adapter
((SimpleCursorAdapter) conAdapter).setViewBinder(binder);
How can I change it to work ok ?
You have to add the text to the textview:
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex)
{
((TextView) view).setTextColor(Colors.RED);
((TextView) view).setText(cursor.getString(cursor.getColumnIndex("YOUR-COLUMN-NAME")));
return false;
}
change line
tv = (TextView)view.findViewById(R.id.countryTextView); // <-- add 'view.'
call
conAdapter.setViewBinder(SimpleCursorAdapter.ViewBinder)
setListAdapter(conAdapter); // set adapter
I have a ListView that reads data from sqlite with SimpleCursorAdapter and the table has about 1000 rows but i've filtered my list in my Activity by date, so the filtered cursor contains 2 rows for that special day.Therefor i wanted to add a custom row number(can't use _id) for my list.one soloution that i've tought about,was ViewBinder, here is my code:
adapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View aView, Cursor aCursor, int aColumnIndex) {
if (aColumnIndex == 0) {
aCursor.moveToFirst();
if(aCursor.moveToFirst()) {
TextView textView = (TextView) aView;
textView.setText("" + WeeklyListRowNumber);
WeeklyListRowNumber = WeeklyListRowNumber + 1;
}
return true;
}
return false;
}
});
I have 11 columns in my List and WeeklyListRowNumber initialized 1 on the top,my problem is my rownumbers turns to 7,8 but it must be 1 , 2.can somebody tells me how can I solve this issue?
public View getView(int position, View convertView, ViewGroup parent) {
View retval = null;
retval = LayoutInflater.from(parent.getContext()).inflate(
R.layout.content, null);
title = (TextView) retval.findViewById(R.id.contactName);
number = (TextView) retval.findViewById(R.id.contactNumber);
title.setText(text to display in list);
number.setText(""+position);//add row number to list //fixed the variable
}
As You are using the adapter for the list view so u may getting the position variable in getview .
Use that position (int) as custom list row number
it will start from zero(0).
Set it according as per requirement...
finaly i've soved my problem with ViewBinder :
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View aView, Cursor aCursor, int aColumnIndex) {
if (aColumnIndex == 0) {
TextView textView = (TextView) aView;
int CursorPos = aCursor.getPosition() + 1;
textView.setText(Integer.toString(CursorPos));
return true;
}
return false;
}});
I retrieve from database my swimming performance. I would like to change background color of one field according to his value. For example if i swimm 4 laps I want color background. I try this code that set background correctly but text disappears.
String[] columns = new String[] { "swimm_pos", "swimm_date","swimm_lap", "swimm_stroke", "swimm_time", "swimm_media", "swimm_efficiency", "swimm_note" };
int[] to = new int[] { R.id.row_counter, R.id.swimm_date, R.id.swimm_lap, R.id.swimm_stroke, R.id.swimm_time, R.id.swimm_medialap, R.id.swimm_efficiency, R.id.swimm_note};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.contacto_list_item,
cursor,
columns,
to);
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.swimm_lap)
{
int color = cursor.getInt(columnIndex);
String s = String.valueOf(color);
if (s.equals("4")) {
TextView tv = (TextView)view;
tv.setBackgroundColor(0xFF558866);}
return true;
}
return false;}
});
And is also possible, when lap is equals to 4 set background color of another field, for example in my code: R.id.swimm_pos?
thank you.
Returning true from ViewBinder implies that you are also binding the data to the View.
But in your case you are not setting the text of R.id.swimm_lap.
So add setText before return statement
tv.setText(s);
return true;
Edit:
For the second question suppose you want to change background of R.id.row_counter depending upon swim lap then add
else if (view.getId() == R.id.row_counter){
int color = cursor.getString(cursor.getColumnIndex("swimm_lap"));
if (s.equals("4")) {
view.setBackgroundColor(0xFF558866);
}
}
Solved, here the right code:
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.row_counter)
{
int color = cursor.getInt(cursor.getColumnIndex("swimm_lap"));
String s = String.valueOf(color);
if (s.equals("4")) {
TextView tv = (TextView)view;
tv.setBackgroundColor(0xFF558866);
}
return true;
}
return false;}
});
this.setListAdapter(adapter);
datasource.close();
}
Ok, so this has been somewhat addressed alot on this site, however I do not believe the exact problem with what my code uses. I am filling a listView with CheckedTextViews which works completely. However when I click on an item it gets checked but when I scroll up and down random rows are also checked. I realize it must have something to do with how the ListView keeps track of the items. I am running into some errors at the moment. I attempted to fill a hashmap with the list of the rows so I can keep track which one is set to true and which are false. However I am not positive where to implement the map and try to fill it.
Here is my OnCreate
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewmenu);
//Get table name of menu clicked.
Bundle extras = getIntent().getExtras();
tableName = extras.getString("table");
// map each contact's name to a TextView in the ListView layout
String[] from = new String[] { "name" };
int[] to = new int[] { R.id.toppingCheckedTextView };
for(int i=0; i< from.length; i++){
map.put(i, false);
}
contactAdapter = new SimpleCursorAdapter(
ViewToppingListing.this, R.layout.toppings_list_item, null, from, to);
setListAdapter(contactAdapter); // set contactView's adapter
}
I attempt to place the map in the onCreate to fill it however it complains about a nullpointer.
Here is where I tried using the OnListItemClick method
#Override
protected void onListItemClick(ListView arg0, View arg1, int arg2, long arg3){
final int index = arg2 - arg0.getFirstVisiblePosition();
View v = arg0.getChildAt(index);
CheckedTextView ctv = (CheckedTextView) v.findViewById(R.id.toppingCheckedTextView);
if((Boolean)map.get(index) == true){
ctv.setChecked(true);
ctv.setVisibility(View.VISIBLE);
} else{
ctv.setVisibility(View.GONE);
}
}
I have read alot on this, and it seems that alot of solutions involves using getView(), however I don't know if that applies to my situation. Any help would be greatly appreciated!
First of all do you need a SimpleCursorAdapter? You set the adapter with a null cursor:
contactAdapter = new SimpleCursorAdapter(
ViewToppingListing.this, R.layout.toppings_list_item, null, from, to); // the third parameter is the cursor and you set it to null!
The behavior you see it's because of the ListView is recycling views and yes you'll have to implement your own adapter and override bindView(). The code bellow is based on another answer to a similar question maybe you'll want to look at it( Getting the selected View from ListView ). Here is an example:
public class TestCursorAdapter extends ListActivity {
MySimpleAdapter adapter;
private HashMap<Long, Boolean> positionHide = new HashMap<Long, Boolean>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] columns = new String[] { "_id", "name" };
MatrixCursor mc = new MatrixCursor(columns); // cursor for testing
for (int i = 1; i < 35; i++) {
long id = i;
mc.addRow(new Object[] { id, "Name" + i });
}
String[] from = new String[] { "name" };
int[] to = new int[] { R.id.checked_text };
adapter = new MySimpleAdapter(this,
R.layout.adapter_mysimpleadapter_row, mc, from, to);
setListAdapter(adapter);
}
private class MySimpleAdapter extends SimpleCursorAdapter {
public MySimpleAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
CheckedTextView ctv = (CheckedTextView) view
.findViewById(R.id.checked_text);
long pos = cursor.getLong(0); // the id from the cursor
if (positionHide.get(pos) == null) {
ctv.setChecked(false);
// we don't have this id in the hashmap so the value is by
// default false, the TextView is GONE
} else {
// we have the value in the Hashmap so see what it is and set
// the textview visibility from this value
Boolean tmp = positionHide.get(pos);
if (tmp.booleanValue()) {
ctv.setChecked(true);
} else {
ctv.setChecked(false);
}
}
}
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Boolean tmp = positionHide.get(id);
if (tmp == null) {
// if null we don't have this key in the hashmap so
// we add it with the value true
positionHide.put(id, true);
} else {
positionHide.put(id, !tmp.booleanValue());
// if the value exists in the map then inverse it's value
}
adapter.notifyDataSetChanged(); // notify the adapter that something has
// changed
}
}