Android:ListView中的按钮未接收onClick事件
我正在制作一个日期选择器活动,它看起来像一个滚动的30天月/日历(想想Outlook日历)。日期选择器包含MonthView视图的列表视图(用于滚动),每个视图都是各个日期的表视图。MonthView中的每一天都是一个按钮。当MonthView被实例化时,我每天都会行走(按钮),并附加一个单击侦听器:Android:ListView中的按钮未接收onClick事件,android,Android,我正在制作一个日期选择器活动,它看起来像一个滚动的30天月/日历(想想Outlook日历)。日期选择器包含MonthView视图的列表视图(用于滚动),每个视图都是各个日期的表视图。MonthView中的每一天都是一个按钮。当MonthView被实例化时,我每天都会行走(按钮),并附加一个单击侦听器: final Button b = getButtonAt(i); b.setOnClickListener(new OnClickListener() { @Override
final Button b = getButtonAt(i);
b.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
setSelectedDate(buttonDayClosure, b);
}
});
setSelectedDate执行多种操作,但它也会将按钮的背景变为黄色,以表示选择了日期
在我的模拟器上,一切都如您所期望的那样工作。活动开始了,你按一天,天就变黄了。没问题
然而,在我同行的一些模拟器和物理设备上,当你每天触摸时,什么都不会发生。。。在滚动列表视图之前。。。然后突然,选定的日期变为黄色。例如,你触摸“第三个”,然后什么也没发生。等待几秒钟,然后滚动ListView(触摸日历中非第三个区域),一旦ListView滚动,第三个区域就会神奇地变为黄色
在显示这种行为的对等仿真器上,我可以在onClick的第一行上设置一个断点,我发现在滚动ListView之前,实际上不会命中BP
这种行为对我来说毫无意义。我希望onClick行为与封装视图的滚动工作无关
有没有想过为什么会出现这种情况,以及我如何纠正这种情况,以便在触碰按钮时总是立即出现一次点击
谢谢
Post Scriptus: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);
}
}
}
公共类MonthArrayAdapter扩展了ArrayAdapter{
private MonthView[]_视图;
私有向量_dateSelectionChangedListeners=新向量();
公共MonthArrayAdapter(上下文上下文、int-textViewResourceId、Date-minSelectableDay、Date-maxSelectableDay){
super(上下文,textViewResourceId);
int zeroBasedMonth=minSelectableDay.getMonth();
int year=1900+分钟selectableday.getYear();
如果(分钟可选日后(最大可选日))
{
抛出新的IllegalArgumentException(“Min day不能在max day之后”);
}
Date prevDay=分钟可选日;
int numMonths=1;
对于(日期i=minSelectableDay;!sameDay(i,maxSelectableDay);i=i.addDays(1))
{
如果(i.getMonth()!=prevDay.getMonth())
{
numMonths++;
}
prevDay=i;
}
_视图=新的MonthView[Nummoths];
对于(int i=0;i有相同的问题,正在寻找答案。当我没有得到onClick方法时,我完全不相信,直到我滚动列表。如果我找到答案,我会在这里发布
现在,我最好的猜测是尝试除单击之外的其他事件(因为滚动空间正在吞噬复杂的触摸事件,这些事件会变成单击事件):
“downView”是一个静态变量,用于跟踪被单击的元素
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
downView = v;
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (downView == v) {
handleClick(v);
return true;
}
downView = null;
}
return false;
}
});
因此,除了手动将您自己的点击事件与触摸事件组合在一起之外,我将添加一个完全独立的答案
我与Android团队交换了一些电子邮件(被googly使用会带来一些额外的好处),他们认为我手动实现ListAdapter的尝试效率低下,如果我没有正确连接适配器的data observer方法,可能会导致“事件处理方面的有趣问题”
因此,我做了以下工作:
1) 将ListAdapter的实现替换为BaseAdapter的子类,该子类重写了必要的函数
2) 停止使用list.invalidateViews()并开始使用adapter.notifyDataChanged()
虫子似乎已经消失了
这比手动编写单击事件要复杂得多,但从长远来看,这也是更正确的代码。主要原因是ListView不喜欢具有视图数组的适配器
所以问题是由
public View getView (int position, View convertView, ViewGroup parent)
{
return _views[position];
}
当查看ListView代码(或者更确切地说是ListView.ActainView方法)时,您将看到如下代码
if (scrapView != null) {
...
child = mAdapter.getView(position, scrapView, this);
...
if (child != scrapView) {
mRecycler.addScrapView(scrapView);
使用scrapView!=\u views[position]调用getView(position,…)
,因此scrapView将被回收。另一方面,很可能相同的视图也被再次添加到ListView,导致视图具有奇怪的状态(请参阅)
最后,这应该在ListView IMO中得到修复,但我建议暂时不要使用包含视图数组的适配器。Aswer是:
public View getView(int position, View convertView, ViewGroup parent) {
View v=makeMyView(position);
v.setFocusableInTouchMode(false);
return v;
}
你能发布你的适配器和ListActivity的完整代码吗?这是适配器。请等待ListView。好的,nbarraille,希望能有所帮助。
public View getView(int position, View convertView, ViewGroup parent) {
View v=makeMyView(position);
v.setFocusableInTouchMode(false);
return v;
}