【问题标题】:How to fire onListItemClick in Listactivity with buttons in list?如何使用列表中的按钮在 Listactivity 中触发 onListItemClick?
【发布时间】:2010-12-21 18:25:50
【问题描述】:

我有一个简单的 ListActivity,它使用自定义 ListAdapter 来生成列表中的视图。通常 ListAdapter 只会用 TextViews 填充视图,但现在我也想在其中放置一个按钮。

我的理解和经验是,在列表项中放置一个可聚焦的视图可以防止在单击列表项时在 ListActivity 中触发 onListItemClick()。该按钮在列表项中仍然正常工作,但是当按下按钮以外的其他内容时,我希望触发 onListItemClick。

我怎样才能做到这一点?

【问题讨论】:

  • 您的后代 Focusability 解决方案真的很有帮助,您应该将其添加为答案并接受它!
  • @Max 我不这样做的原因是因为这是一种非常糟糕的做法,是一种解决方法。如果我找到了一个永久健康的解决方案,我会给出答案(如果我记得我在一年前写过这个问题:))
  • 我也想看看你有什么解决方法。我一直在尝试设置后代焦点,但无法使用按钮。此外,我一直在尝试在列表行中放置一个 GridView(带有 ImageViews),并且存在类似的问题。
  • 恕我直言,我给出的答案比 Ramps 和 Praveen 提出的问题解决方案要优雅得多。 P.s.不试图在这里恢复被遗忘的问题,但我看到你还没有接受任何答案;D
  • @CodeFusionMobile 你能接受 Ewoks 的回答吗?投票最高的答案是有缺陷的,因为它禁用了 ListView 元素的 onclick 动画(它变成蓝色)。这将节省其他开发人员花费一些时间尝试最佳答案,发现它有缺陷,然后去 Ewoks 的。

标签: android android-widget android-listview


【解决方案1】:

正如我在previous comment 中所写,解决方案是在 ImageButton 上设置焦点(假)。

还有更优雅的解决方案尝试在列表元素的根布局中添加android:descendantFocusability="blocksDescendants" 。这将使点击 onListItem 成为可能,并且您可以单独处理 Button 或 ImageButton 点击​​

希望对你有帮助 ;)

干杯

【讨论】:

  • android:descendantFocusability="blocksDescendants" 非常完美。
  • 你,我的朋友,是我个人的英雄。你应该是票数最高的人!对于几乎任何情况,这都要好得多!
  • 这应该是公认的答案。它对我来说非常有效。看起来列表项中的所有视图都需要不可聚焦,而这个视图就是这样做的,而无需单独设置。
  • 这似乎对我不起作用。通过根布局,您是指行布局还是定义列表视图的位置?无论如何,我尝试了所有可能的组合..不工作:(
  • “列表元素的根布局”就像我写的那样。所以假设您有列表并由具有多个 Button、ImageButton、TextVeiw 的布局(称为列表元素的根布局)组成。
【解决方案2】:

我希望我能在这里提供帮助。我假设您有 listView 项目的自定义布局,并且此布局由按钮和其他一些视图组成 - 例如 TextView、ImageView 或其他。现在,您希望在单击按钮时触发不同的事件,并在单击其他所有内容时触发不同的事件。

您可以在不使用 ListActivity 的 onListItemClick() 的情况下实现这一点。
这是您必须做的:

您正在使用自定义布局,因此您可能正在覆盖自定义适配器中的 getView() 方法。诀窍是为您的按钮设置不同的侦听器,并为整个视图(您的行)设置不同的侦听器。看一下例子:

private class MyAdapter extends ArrayAdapter<String> implements OnClickListener {

    public MyAdapter(Context context, int resource, int textViewResourceId,
            List<String> objects) {
        super(context, resource, textViewResourceId, objects);
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        String text = getItem(position);
        if (null == convertView) {
            convertView = mInflater.inflate(R.layout.custom_row, null);
        }
        //take the Button and set listener. It will be invoked when you click the button.
        Button btn = (Button) convertView.findViewById(R.id.button);
        btn.setOnClickListener(this);
        //set the text... not important     
        TextView tv = (TextView) convertView.findViewById(R.id.text);
        tv.setText(text);
        //!!! and this is the most important part: you are settin listener for the whole row
        convertView.setOnClickListener(new OnItemClickListener(position));
        return convertView;
    }

    @Override
    public void onClick(View v) {
        Log.v(TAG, "Row button clicked");
    }
}

您的 OnItemClickListener 类可以这样声明:

private class OnItemClickListener implements OnClickListener{       
    private int mPosition;
    OnItemClickListener(int position){
        mPosition = position;
    }
    @Override
    public void onClick(View arg0) {
        Log.v(TAG, "onItemClick at position" + mPosition);          
    }       
}

当然,您可能会向 OnItemClickListener 构造函数添加更多参数。
还有一件重要的事情 - 上面显示的 getView 的实现非常难看,通常您应该使用 ViewHolder 模式来避免调用 findViewById .. 但您可能已经知道那个。
我的 custom_row.xml 文件是具有 id 为“button”的 Button、id 为“text”的 TextView 和 id 为“image”的 ImageView 的 RelativeLayout - 只是为了让事情更清楚。
问候!

【讨论】:

  • 我的解决方案最终采用了另一种方式。我通过将列表行布局的后代 Focusability 属性设置为阻止后代来解决了这个问题,然后它突然起作用了。现在我使用一个 simpleCursorAdapter 和一个附加的自定义 viewbinder 来进行事件设置和其他与按钮相关的花哨的事情。
  • 我使用了这个解决方案。但是,警告:如果您的 onClick 处理程序导致列表的内容发生更改,这将导致调用 getView 并且如果您的小部件是有状态的(如 ToggleButton 或 CheckBox),并且 getView 设置该状态,您可能需要 setOnClickListener (null) 在你改变onView中的状态之前,避免出现循环效果。
  • 我的解决方案怎么样?我的印象是更优雅,可以在需要时更容易应用..
  • 第一条评论应该被接受为答案,所以像我这样的人不需要几个小时就能找到它
  • 谢谢!这很有用。我喜欢它作为其他线程中描述的 focus:blockDescendants 方法的更本地化的替代方案。
【解决方案3】:

当自定义 ListView 包含可聚焦元素时,onListItemClick 将不起作用(我认为这是预期的行为)。只需从自定义视图中移除焦点,它就可以解决问题:

例如:

public class ExtendedCheckBoxListView extends LinearLayout {

    private TextView mText;
    private CheckBox mCheckBox;

    public ExtendedCheckBoxListView(Context context, ExtendedCheckBox aCheckBoxifiedText) {
         super(context);
         …
         mText.setFocusable(false);
         mText.setFocusableInTouchMode(false);

         mCheckBox.setFocusable(false);
         mCheckBox.setFocusableInTouchMode(false);
        …       
    }
}

【讨论】:

  • 我喜欢你的解决方案:如果每行只有一个“可点击”小部件,那么拒绝它们的可聚焦性是一个优雅的解决方案。这确实意味着在该行的任意位置点击都会匹配,但当小部件是单选框或复选框时,这是一个有用的行为。使用 android:focusable="false" 和 android:focusableInTouchMode="false" 在 XML 中也可以实现同样的效果。
  • 如果您更改可见性,xml 方式似乎不起作用,因此必须在将“视图”设置为可见后通过代码来完成
【解决方案4】:

我有同样的问题: OnListItemClick 没有被触发! [已解决]
这发生在扩展 ListActivity 的类上,
具有 ListActivity 的布局,内容 TextBox 和 ListView 嵌套到 LinearLayout
以及行的另一种布局(嵌套在 LineraLayout 中的 CheckBox 和 TextBox)。

那是代码:

res/layout/configpage.xml(ListActivity 的主目录)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent" > 
    <TextView  
        android:id="@+id/selection"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="pippo" /> 
    <ListView  
        android:id="@android:id/list"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:drawSelectorOnTop="false"  
        android:background="#aaFFaa" > 
    </ListView> 
<LinearLayout> 

res/layout/row.xml (layout for single row)  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"> 
  <CheckBox  
      android:id="@+id/img"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 

  <TextView  
      android:id="@+id/testo"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content"  
      **android:focusable="false"**  
      **android:focusableInTouchMode="false"** /> 
</LinearLayout> 

src/.../.../ConfigPage.java

public class ConfigPage extends ListActivity
{
    TextView selection;

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.configpage);  
        // loaded from res/value/strings  
        String[] azioni = getResources().getStringArray(R.array.ACTIONS);  
        setListAdapter(new ArrayAdapter&lt;String&gt;(this, R.layout.row, 
                R.id.testo,   azioni));  
        selection = (TextView) findViewById(R.id.selection);  
    }       

    public void onListItemClick(ListView parent, View view, int position, long id)
    {
        selection.setText(" " + position);
    }
}

当我添加到 row.xml 时,这开始起作用了

  • android:focusable="false"
  • android:focusableInTouchMode="false"

我使用 Eclipse 3.5.2
Android SDK 10.0.1
最低 SDK 版本:3

希望对你有帮助
...对不起我的英语:(

【讨论】:

  • @fellons 不知道为什么,但它对我不起作用。我的 onListItemClick 没有被调用。
  • 你添加属性代码android:focusable="false" 和android:focusableInTouchMode="false" 代码了吗?
【解决方案5】:

只需添加android:focusable="false" 作为按钮的属性之一

【讨论】:

    【解决方案6】:

    我在使用 ToggleButton 时遇到了同样的问题。经过半天的头撞墙后,我终于解决了。 就像使用'android:focusable'使可聚焦视图无法聚焦一样简单。您还应该避免玩弄列表行的可聚焦性和可点击性(我只是虚构了单词),只需将它们保留为默认值即可。

    当然,既然您在列表行中的可聚焦视图无法聚焦,那么使用键盘的用户可能会遇到问题,好吧,聚焦它们。这不太可能成为问题,但如果您想编写 100% 完美的应用程序,您可以使用 onItemSelected 事件使选定行的元素可聚焦,而先前选定行的元素不可聚焦。

    【讨论】:

    • 我使用了这种方法。如果您可以解决无法专注于单个项目的问题,这是最简单的方法。这也使列表项的状态可绘制对象保持原样,而其他一些解决方法则没有。
    【解决方案7】:
     ListView lv = getListView();
    lv.setTextFilterEnabled(true);
    
    lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view,
        int position, long id) {
      // When clicked, show a toast with the TextView text
      Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
          Toast.LENGTH_SHORT).show();
    }
    });
    

    【讨论】:

      【解决方案8】:

      我使用 getListAdapter().getItem(position) 实例化一个对象,该对象在项目中保存我的值

      MyPojo myPojo = getListAdapter().getItem(position);
      

      然后使用 myPojo 中的 getter 方法,它将在项目中调用其正确的值。

      【讨论】:

        猜你喜欢
        • 2015-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-26
        • 1970-01-01
        • 2011-10-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多