Dynamic display of ListView elements partially working
I am making a time sheet program where a user inputs his in- and out-punches. I have a ListView that I am populating from an array of calendar objects. I would like each row to show the day and date then on a new line the time, but I only want to display the day and date if it is different from the previous element.
Currently, I am setting visibility in the BaseAdapter based on comparisons using position vs position-1 (which are used as indices to the array). This only works if the whole list fits on the screen. If it extends beyond the screen and the user scrolls around the results are unpredictable.
To further confuse things, I am setting the color of the times, based on the position, to alternate between green and red (in/out) and it works as expected, scrolling or not.
How does Android handle the ListView position when scrolling or what could I do differently to show/hide the day and date?
public class TimeSheetActivity extends Activity {
SQLiteDatabase timesDatabase;
Cursor punchCursor;
private static Calendar[] allPunches;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timesheet);
} //end onCreate()
@Override
public void onResume() {
super.onResume();
//Open database
timesDatabase = openOrCreateDatabase(
"times_database.db",
SQLiteDatabase.CREATE_IF_NECESSARY,
null);
timesDatabase.setLocale(Locale.getDefault());
timesDatabase.setLockingEnabled(true);
timesDatabase.setVersion(1);
punchCursor = timesDatabase.query("Timepunches", null, null, null, null, null, "punch ASC;");
updateTimeSheet();
} //end onResume()
@Override
public void onPause() {
super.onPause();
timesDatabase.close();
} //end onResume()
private static class EfficientAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return allPunches.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.time_list_row, null);
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.day_textview);
holder.text2 = (TextView) convertView.findViewById(R.id.date_textview);
holder.text3 = (TextView) convertView.findViewById(R.id.times_this_day_textview);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
String dayNames[] = new DateFormatSymbols().getWeekdays();
开发者_运维百科 //Initialize first list element
if (position < 1) {
holder.text1.setText(dayNames[allPunches[position].get(Calendar.DAY_OF_WEEK)]);
holder.text2.setText(formatDate(allPunches[position]));
}
else {
holder.text1.setText(dayNames[allPunches[position].get(Calendar.DAY_OF_WEEK)]);
holder.text2.setText(formatDate(allPunches[position]));
holder.text1.setVisibility(View.VISIBLE);
holder.text2.setVisibility(View.VISIBLE);
//Hide day and date if same as last
if (formatDate(allPunches[position]).contentEquals(formatDate(allPunches[position-1]))) {
holder.text1.setVisibility(View.GONE);
holder.text2.setVisibility(View.GONE);
}
}
holder.text3.setText(formatTime(allPunches[position], true) + " " + position);
//Color in/out punches
if (position%2 == 0) {
holder.text3.setTextColor(Color.GREEN);
}
else {
holder.text3.setTextColor(Color.RED);
}
return convertView;
} //end getView()
static class ViewHolder {
public TextView text1;
TextView text2;
TextView text3;
}
} //end EfficientAdapter
public void updateTimeSheet() {
punchCursor = timesDatabase.query("Timepunches", null, null, null, null, null, "punch ASC;");
allPunches = new Calendar[punchCursor.getCount()];
int i = 0; //for indexing allPunches
Calendar nextDay = Calendar.getInstance();
nextDay.setLenient(true);
//populate allPunches
for (punchCursor.moveToFirst(); !punchCursor.isAfterLast(); punchCursor.moveToNext()) {
allPunches[i] = Calendar.getInstance();
allPunches[i].setTimeInMillis(punchCursor.getLong(0));
++i;
} //end for
final ListView timeSheetListView = (ListView)findViewById(R.id.timesheet_listview);
timeSheetListView.setAdapter(new EfficientAdapter(this));
timeSheetListView.setOnItemClickListener(new OnItemClickListener() {...}); //end click listener for list item
} //end updateTimeSheet()
public static String formatTime(Calendar thisTime, boolean showAMPM) {...}
public static String formatDate(Calendar thisDate) {
String formattedDate = "";
formattedDate += thisDate.get(Calendar.MONTH) +"-"+ thisDate.get(Calendar.DAY_OF_MONTH) +"-"+ thisDate.get(Calendar.YEAR);
return formattedDate;
} //end formatDate()
} //end TimeSheet Activity
The views in the ListView are resused as you scroll. This likely causes the odd behavior you see. The important thing to remember when overriding getView is to set the behavior explicitly every time. Don't depend on a a view being in a default state, since you may be reusing a view that has already been changed.
In your particular case, make sure that you always set the visiblity explicitly to true or gone.
Also, did you copy paste this code directly? I believe you are missing a closing bracket for your second else statement.
I seem to have been setting VISIBLE in the wrong place. Here is the code for getView() that seems to have it fixed!
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.time_list_row, null);
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.day_textview);
holder.text2 = (TextView) convertView.findViewById(R.id.date_textview);
holder.text3 = (TextView) convertView.findViewById(R.id.times_this_day_textview);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
String dayNames[] = new DateFormatSymbols().getWeekdays();
holder.text1.setVisibility(View.VISIBLE);
holder.text2.setVisibility(View.VISIBLE);
//Initialize list
if (position < 1) {
holder.text1.setText(dayNames[allPunches[position].get(Calendar.DAY_OF_WEEK)]);
holder.text2.setText(formatDate(allPunches[position]));
}
else {
//Show day and date if not same as last
holder.text1.setText(dayNames[allPunches[position].get(Calendar.DAY_OF_WEEK)]);
holder.text2.setText(formatDate(allPunches[position]));
if (formatDate(allPunches[position]).contentEquals(formatDate(allPunches[position-1]))) {
holder.text1.setVisibility(View.GONE);
holder.text2.setVisibility(View.GONE);
}
}
holder.text3.setText(formatTime(allPunches[position], true));
//Color in/out punches
if (position%2 == 0) {
holder.text3.setTextColor(Color.GREEN);
}
else {
holder.text3.setTextColor(Color.RED);
}
return convertView;
} //end getView()
static class ViewHolder {
public TextView text1;
TextView text2;
TextView text3;
}
} //end EfficientAdapter
精彩评论