ViewPager + GridView的onItemClick

3

我有一个GridView放在ViewPager的布局中(我不确定这是否有所不同)。

inside SampleAdapter for ViewPager{
@Override
        public Object instantiateItem(ViewGroup container, int position) {
            View page = null;
            if (position == 0) {
                page = getLayoutInflater().inflate(R.layout.layoutone,
                        container, false);
            } else {
                page = getLayoutInflater().inflate(R.layout.layouttwo,
                        container, false);
                GridView grid = (GridView) page.findViewById(R.id.gridview);
                grid.setOnItemClickListener(new OnItemClickListener() {

                    @Override
                    public void onItemClick(AdapterView<?> arg0, View arg1,
                            int arg2, long arg3) {

                                  //switch to another activity based on click event

                    }

                });
                grid.setAdapter(new GridItemAdapter(context)); //sets custom gridItemLayout


        container.addView(page);

        return (page);

    }

}

我可以正常查看网格视图,自定义布局也按照我的GridAdapter工作。但是,我的点击事件没有被触发。这是因为instantiateItem()方法的调用吗?我该如何解决这个问题?

我还不太了解Fragments如何与ViewPager一起使用,所以如果这个解决方案涉及切换到基于Fragment的方法,希望有人能详细说明一下。


请问您能否包含GridItemAdapter中的getView函数?如果可以,请告诉我。 - Sherif elKhatib
“getView”函数只是填充R.layout.mycustomlayout,但我会尽快回家后发布它。” - Kgrover
3个回答

2
因为ViewPager在捕捉点击/动作事件时有点贪婪,所以在ViewPager中点击有点有趣。 一种解决方案 包括覆盖ViewPager的ViewGroup.onInterceptTouchEvent(MotionEvent ev)。然而,并不总是需要这样做。具体来说,我无法为pager设置onClickListner而不这样做,但是为pager内部的视图设置onClickListner对我来说完美地工作(我在结尾附上了代码示例)。然而,我从未在GridView / onItemClickListener中执行过此操作。您正在做的实质上是为页码器内部的视图设置单击监听器,这是另一层。随着您在Android中嵌套事物,由于系统处理消耗点击的方式,触摸事件变得更加复杂。
你的情况中存在的问题是,某些东西在不将触摸事件传递给列表项的情况下消耗了它。实际上,Android 处理触摸事件的方式是,当触摸事件发生时,它会将其传递给顶层视图的触摸事件处理程序函数。如果视图处理该事件,则返回 true,系统知道事件已处理完毕。如果视图不想处理该事件,则返回 false,系统将事件传递给层次结构中的下一个更高级别的视图。在你的情况下,某些东西(可能是 ViewPager 或可能是 GridView)在触及网格项之前就消耗了事件,因此 onItemClickListener 永远不会被触发。
作为测试,如果你可以为 GridView(即整个视图)设置 onClickListener 并使其正常工作,那么这意味着问题不在于 ViewPager。在这种情况下,你需要自己实现 GridView 的版本,并覆盖它如何处理触摸事件以确保事件传递到子项。然而,如果这样做不起作用,你将需要像之前提到的那样覆盖 ViewPager。
(注:显然,这两种解决方案都需要大量时间,因此在执行任何一种方案之前,请确保您已经仔细检查了任何简单的错误,例如将监听器放在错误的视图上,误读行为并认为它没有触发等。)
参考资料,这是一个有效的instantiateItem方法版本(实际上仍在进行中,因此不是100%完美)。 'menupage'视图是LinearLayout。
public Object instantiateItem(View collection, int position) {
    LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    int page = R.layout.menu_page;
    String meal = "";
    switch (position) {
        case 0:
            meal = "Breakfast!";
            break;
        case 1:
            meal = "Lunch!";
            break;
        case 2:
            meal = "Dinner!";
            break;
    }

    View view = inflater.inflate(page, null);
    TextView mealTitle = (TextView) view.findViewById(R.id.meal_title);
    mealTitle.setText(meal);

    ((ViewPager) collection).addView(view, 0);
    final ViewPager pager = (ViewPager)collection;

    View menupage = view.findViewById(R.id.menu_page_ll);
    menupage.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            int page = ((ViewPager) pager).getCurrentItem();
            Intent i = new Intent(getApplicationContext(), Menus.class);
            i.putExtra("page", page);
            startActivity(i);
        }
    });

    return view;
}

感谢您详细的回复!我会尝试实现并进行更多调试,然后告诉您一切进展如何。 - Kgrover
非常有趣。ViewPagers不应该消耗点击事件,但你下一步可能是重写onInterceptTouchEvent并确保它对于点击事件返回false(但你仍希望它处理滑动事件)。 - matt5784
我应该在哪里重写 onInterceptTouchEvent 方法?在 instantiateItem() 方法中吗?抱歉,我对 ViewPagers 还不熟悉。 - Kgrover
你需要实现自己的ViewPager类并在其中进行重写。这是pager本身的一种方法,而不是适配器的方法。正如我在我的答案中所说,这很不幸,因为它并不是最简单的事情。 - matt5784
好的,谢谢。我会先等一下看是否有其他的解决方法,但最坏情况下我会那么做。:)不过还是要赞一下你的努力。 - Kgrover
我添加了grid.brintToFront(),现在它显示为: ' 10-18 22:33:20.789: I/InputDispatcher(133): 将触摸传递给当前输入目标:操作:0,通道'40c37b28 com.package.name/com.package.name.classname(服务器)' - Kgrover

2
我建议您创建一个单独的Fragment,并使用您的ViewPager适配器的getItem(position)方法来发送位置和实例化您的Fragment。在Fragment内部,您可以轻松地填充您的布局并使用GridView
 @Override
 public Fragment getItem(int position) {
    return GridFragment.newInstance(position);
}

我觉得你当前的使用方式有些复杂,所以我建议你尝试一下我的方法。这里提供了一个示例演示链接


谢谢你的建议!我会尽快尝试。如果需要帮助,希望你能一路指导- 我是新手。 - Kgrover
你能更详细地描述一下你的代码是如何与ListView配合工作的吗?我不确定如何处理GridFragment。目前,我给你悬赏是因为你提出了一种新的方法。希望你能帮助我实现它。 - Kgrover
你可以尝试将ListView替换为GridView并使其正常工作! - Lalit Poptani
我会尝试,但是需要再回复你。最近时间不太充裕。谢谢。 - Kgrover
我编辑了我的回答,并在我的 Github 上添加了一个小的 GridView 示例,请下载并查看。 - Lalit Poptani

0

你的listView里面有任何可点击的对象吗? 如果你的listView或gridView项包含可点击的视图(按钮、复选框等),你的OnItemClickListener将不会被调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接