Android:ListView中的按钮未接收onClick事件

Android:ListView中的按钮未接收onClick事件,android,Android,我正在制作一个日期选择器活动,它看起来像一个滚动的30天月/日历(想想Outlook日历)。日期选择器包含MonthView视图的列表视图(用于滚动),每个视图都是各个日期的表视图。MonthView中的每一天都是一个按钮。当MonthView被实例化时,我每天都会行走(按钮),并附加一个单击侦听器: final Button b = getButtonAt(i); b.setOnClickListener(new OnClickListener() { @Override

我正在制作一个日期选择器活动,它看起来像一个滚动的30天月/日历(想想Outlook日历)。日期选择器包含MonthView视图的列表视图(用于滚动),每个视图都是各个日期的表视图。MonthView中的每一天都是一个按钮。当MonthView被实例化时,我每天都会行走(按钮),并附加一个单击侦听器:

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;
}