如何使用列表中的按钮在Listactivity中触发onListItemClick?


89

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

根据我的理解和经验,当单击列表项时,将可聚焦视图放在列表项中会阻止在ListActivity中触发onListItemClick()。该按钮在列表项中仍然正常运行,但是当按下按钮以外的内容时,我希望触发onListItemClick。

我该如何工作?


5
具有后代可聚焦性的解决方案确实很有帮助,您应该将其添加为答案并接受!
Maksym Gontar'9

@Max我之所以​​没有这样做,是因为这确实是一种不好的做法,一种解决方法。如果我找到了永久健康的解决方案,那么我会做出一个答案(如果我记得我一年前写过这个问题:))
CodeFusionMobile 2010年

我也想看看您的解决方法。我一直在尝试设置后代焦点,但无法使其与按钮一起使用。另外,我一直试图在列表行中放置一个GridView(带有ImageViews),并且存在类似的问题。
MrPurpleStreak 2010年

我给恕我直言的答案是一个比Ramps和Praveen提出的解决方案更优雅的解决方案。Ps没有试图在这里恢复被遗忘的问题,但我看到您尚未接受任何答案; D
Ewoks

@CodeFusionMobile您能否接受Ewoks的回答?投票最高的答案是有缺陷的,因为它禁用了ListView元素的onclick动画(在该位置变为蓝色)。这将为其他开发人员节省一些时间来尝试最佳答案,发现其有缺陷,然后转到Ewoks。
1英寸

Answers:


99

正如我在先前的评论解决方案中所写的那样,是在ImageButton上设置setFocusable(false)。

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

希望能帮助到你 ;)

干杯


3
android:descendantFocusability="blocksDescendants"很完美。
马修·米切尔

1
您,我的朋友,是我的个人英雄。您应该是投票最多的人!在几乎所有情况下,这都好得多!
OschtärEi

这应该是公认的答案。它对我来说非常有效。列表项中的所有视图似乎都必须是无法聚焦的,而这一操作无需单独设置即可。
2013年

1
这似乎对我不起作用。所谓根布局,是指行布局还是在定义列表视图的地方?无论如何,我尝试了所有可能的组合..不起作用:(
GreenBee

我写的是“列表元素的根布局”。因此,假设您具有列表并由具有多个Button,ImageButton,TextVeiw的布局(称为列表元素的根布局)组成。–
Ewoks

59

我希望我能在这里提供帮助。我假设您具有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-只是为了使内容清晰。
问候!


9
我的解决方案最终转向了另一种方式。我通过设置列表行布局的后代Focusability属性来阻止后代来解决此问题,然后突然起作用了。现在,我使用附有自定义viewbinder的simpleCursorAdapter来进行事件设置以及与按钮相关的其他奇特的事情。
CodeFusionMobile 2010年

3
我用了这个解决方案。但是,有一个警告:如果您的onClick处理程序导致列表的内容发生更改,这将导致调用getView并且如果您的小部件是有状态的(例如ToggleButton或CheckBox),并且getView设置了该状态,则您可能需要setOnClickListener (null),然后再在onView中更改状态,以避免产生循环效果。
Pierre-Luc Paour 2011年

3
那我的解决方案呢?我的印象是更优雅,能够应用于更容易,每当我们需要它..
伊渥克

第一条评论应作为答案,因此像我这样的人将不需要很多时间来找到它
keybee 2013年

谢谢!这很有用。我喜欢它作为其他线程中介绍的focus:blockDescendants方法的更本地化的替代方法。
Yoav Shapira

18

当自定义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);
               
    }
}

3
我喜欢您的解决方案:如果每行只有一个“可点击的”小部件,那么拒绝它们的可聚焦性是一个很好的解决方案。这确实意味着该行上任何位置的轻击都将匹配,但这在小部件是单选或复选框时是有用的行为。使用android:focusable =“ false”和android:focusableInTouchMode =“ false”在XML中可以实现相同的目的。
Pierre-Luc Paour 2011年

1
如果更改可见性,则xml方式似乎不起作用,因此必须在将“视图”设置为可见后通过代码来完成
max4ever 2012年

13

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

那是代码:

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
min SDK版本:3

我希望这会有所帮助
...对不起我的英语:(


@fellons不知道为什么,但是对我不起作用。我的onListItemClick没有被调用。
likejudo 2014年

您是否添加了属性代码android:focusable =“ false”和android:focusableInTouchMode =“ false”代码?
rfellons 2014年

2

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


1

我在ToggleButton上遇到了同样的问题。经过半天的撞墙碰壁,我终于解决了。就像使用“ android:focusable”使可聚焦视图变得不可聚焦一样简单。您还应该避免使用列表行的可聚焦性和可单击性(我刚刚组成的单词),只需将它们保留为默认值即可。

当然,既然列表行中的可聚焦视图无法聚焦,那么使用键盘的用户可能会遇到问题,将它们聚焦。这不太可能出现问题,但是如果您要编写100%无缺陷的应用程序,则可以使用onItemSelected事件使选定行的元素可聚焦,而先前选定行的元素不可聚焦。


我使用了这种方法。如果您可以解决无法专注于单个项目的问题,这是最简单的方法。这也使列表项的状态可绘制项保持应有的状态,而其他一些替代方法则不然。
乔纳森·S.

1
 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();
}
});

-1

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

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

然后使用myPojo中的getter方法,它将在item中调用其适当的值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.