Я делаю операцию выбора даты, которая выглядит как прокручиваемый 30-дневный месяц/календарь (подумайте о календаре Outlook). Средство выбора даты содержит ListView (для прокрутки) видов MonthView, каждый из которых представляет собой TableView отдельных дней. Каждый отдельный день в MonthView - это кнопка. Когда MonthView инстанциируется я хожу каждый из дней (кнопки) и прикрепить щелчок слушатель:Android: кнопка в ListView не принимает события onClick
final Button b = getButtonAt(i);
b.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
setSelectedDate(buttonDayClosure, b);
}
});
setSelectedDate делает множество вещей, но он также включает фон кнопки на желтый для обозначения выбирается дата.
На моем эмуляторе все работает так, как вы ожидали. Активность появляется, вы нажимаете день, день становится желтым. Нет проблем.
Тем не менее, на некоторых эмуляторах моего партнера и на физических устройствах, когда вы касаетесь дня, ничего не происходит ... пока вы не прокрутите ListView ... а затем вдруг выбранный день станет желтым. Так, например, вы касаетесь «третьего», а затем ничего не происходит. Подождите несколько секунд, а затем прокрутите список ListView (касаясь области календаря, которая НЕ является третьей), и как только ListView прокручивает 3-й, магически становится желтым.
На моих одноранговых эмуляторах, которые показывают это поведение, я могу установить точку останова в первой строке onClick, и я вижу, что BP фактически не попадает, пока прокручивается ListView.
Такое поведение для меня не имеет никакого смысла. Я бы предположил, что поведение onClick не связано с инкапсулирующими усилиями прокрутки View.
Любые мысли о том, почему это может быть так, и как я могу исправить ситуацию, так что onClicks всегда происходит сразу же при нажатии кнопки?
Спасибо.
сообщение Священное писание: ArrayAdapter и ListView запрошенный код:
public class MonthArrayAdapter extends ArrayAdapter<Date> {
private MonthView[] _views;
private Vector<Procedure<Date>> _dateSelectionChangedListeners = new Vector<Procedure<Date>>();
public MonthArrayAdapter(Context context, int textViewResourceId, Date minSelectableDay, Date maxSelectableDay) {
super(context, textViewResourceId);
int zeroBasedMonth = minSelectableDay.getMonth();
int year = 1900 + minSelectableDay.getYear();
if(minSelectableDay.after(maxSelectableDay))
{
throw new IllegalArgumentException("Min day cannot be after max day.");
}
Date prevDay = minSelectableDay;
int numMonths = 1;
for(Date i = minSelectableDay; !sameDay(i, maxSelectableDay); i = i.addDays(1))
{
if(i.getMonth() != prevDay.getMonth())
{
numMonths++;
}
prevDay = i;
}
_views = new MonthView[numMonths];
for(int i = 0; i<numMonths; i++)
{
Date monthDate = new Date(new GregorianCalendar(year, zeroBasedMonth, 1, 0, 0).getTimeInMillis());
Date startSunday = findStartSunday(monthDate);
this.add(monthDate);
_views[i] = new MonthView(this.getContext(), startSunday, minSelectableDay, maxSelectableDay);
zeroBasedMonth++;
if(zeroBasedMonth == 12)
{
year++;
zeroBasedMonth = 0;
}
}
for(final MonthView a : _views)
{
a.addSelectedDateChangedListener(new Procedure<MonthView>()
{
@Override
public void execute(MonthView input) {
for(final MonthView b: _views)
{
if(a != b)
{
b.clearCurrentSelection();
}
}
for(Procedure<Date> listener : _dateSelectionChangedListeners)
{
listener.execute(a.getSelectedDate());
}
}
});
}
}
void addSelectedDateChangedListener(Procedure<Date> listener)
{
_dateSelectionChangedListeners.add(listener);
}
private boolean sameDay(Date a, Date b)
{
return a.getYear() == b.getYear() && a.getMonth() == b.getMonth() &&
a.getDate() == b.getDate();
}
@Override
public View getView (int position, View convertView, ViewGroup parent)
{
return _views[position];
}
private Date findStartSunday(Date d)
{
return d.subtractDays(d.getDay());
}
public void setSelectedDate(Date date)
{
for(MonthView mv : _views)
{
mv.setSelectedDate(date);
}
}
}
и
public class DatePicker extends ActivityBase {
public static final String CHOSEN_DATE_RESULT_KEY = "resultKey";
public static final String MIN_SELECTABLE_DAY = DatePicker.class.getName() + "MIN";
public static final String MAX_SELECTABLE_DAY = DatePicker.class.getName() + "MAX";
private static final String SELECTED_DATE = UUID.randomUUID().toString();
private long _selectedDate = -1;
private MonthArrayAdapter _monthArrayAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Date now = new Date();
Bundle inputs = this.getIntent().getExtras();
long min = inputs.getLong(MIN_SELECTABLE_DAY, 0);
Date minSelectableDate;
if(min == 0)
{
minSelectableDate = new Date(now);
}
else
{
minSelectableDate = new Date(min);
}
Log.i(DatePicker.class.getName(), "min date = " + minSelectableDate.toString());
long max = inputs.getLong(MAX_SELECTABLE_DAY, 0);
Date maxSelectableDate;
if(max == 0)
{
maxSelectableDate = new Date(now.addDays(35).getTime());
}
else
{
maxSelectableDate = new Date(max);
}
setContentView(R.layout.date_picker);
Button doneButton = (Button) findViewById(R.id.DatePickerDoneButton);
if(doneButton == null)
{
Log.e(this.getClass().getName(), "Could not find doneButton from view id.");
finish();
return;
}
doneButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
Intent result = new Intent();
result.putExtra(CHOSEN_DATE_RESULT_KEY, _selectedDate);
setResult(RESULT_OK, result);
finish();
}
});
Button cancelButton = (Button) findViewById(R.id.DatePickerCancelButton);
if(cancelButton == null)
{
Log.e(this.getClass().getName(), "Could not find cancelButton from view id.");
finish();
return;
}
cancelButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
setResult(RESULT_CANCELED, null);
finish();
}
});
ListView lv = (ListView)findViewById(R.id.DatePickerMonthListView);
lv.setDividerHeight(0);
_monthArrayAdapter =
new MonthArrayAdapter(this, android.R.layout.simple_list_item_1, minSelectableDate, maxSelectableDate);
_monthArrayAdapter.addSelectedDateChangedListener(new Procedure<Date>()
{
@Override
public void execute(Date input) {
_selectedDate = input.getTime();
}
});
lv.setAdapter(_monthArrayAdapter);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
if(savedInstanceState.containsKey(SELECTED_DATE))
{
_selectedDate = savedInstanceState.getLong(SELECTED_DATE);
_monthArrayAdapter.setSelectedDate(new Date(_selectedDate));
}
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.putLong(SELECTED_DATE, _selectedDate);
}
}
Вы можете разместить полный код вашего адаптера и вашего ListActivity пожалуйста? – nbarraille 2010-12-01 18:40:12