ListView 行内的 ViewPager 防止 onItemClick 被触发

ViewPager inside ListView row prevents onItemClick to be fired(ListView 行内的 ViewPager 防止 onItemClick 被触发)

本文介绍了ListView 行内的 ViewPager 防止 onItemClick 被触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 ListView 的每一行中都有一个 ViewPager.它工作正常,当用户使用滑动手势时它会更改其中的视图,但它会阻止调用 ListView 的 onItemClick 方法.我知道 ViewPager 是罪魁祸首,因为当我隐藏它时,会调用 onItemClick,所以这就是我正在尝试的:

我创建了一个 ViewGroup 作为行 (RowView).此 ViewGroup 已重写 onInterceptTouchEvent 以避免 ViewPager 在我检测到点击时处理进一步的触摸事件.但是仍然没有调用 onItemClick 回调.并且列表选择器在单击时也不显示.我希望这两个功能起作用.

这是来自 RowView 的 onInterceptTouchEvent 的样子:

@Override公共布尔 onInterceptTouchEvent(MotionEvent ev) {int actionMasked = ev.getActionMasked();开关(actionMasked){案例 MotionEvent.ACTION_DOWN:Log.d("RowView", "OnInterceptTouchEvent - Down");tapDetector.onTouchEvent(ev);返回假;案例 MotionEvent.ACTION_CANCEL:Log.d("RowView", "OnInterceptTouchEvent - 取消");tapDetector.onTouchEvent(ev);休息;案例 MotionEvent.ACTION_UP:如果(tapDetector.onTouchEvent(ev)){Log.d("RowView", "OnInterceptTouchEvent - UP!");返回真;}休息;}返回 super.onInterceptTouchEvent(ev);}

有解决这个问题的建议吗?

编辑:关于如何在 ViewPager 处于活动状态时不调用 MainActivity 中的 onItemClick 的无效示例(棒棒糖列表选择器也不出现)

<块引用>

主活动

ListView listView = (ListView) findViewById(R.id.main_list);listView.setAdapter(new MainListAdapter(this, 30));listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@覆盖public void onItemClick(AdapterView parent, View view, int position, long id) {Log.d(TAG, "onItemClick:" + 位置);}});

<块引用>

列表项 XML:

<块引用>

列表适配器:

公共类 MainListAdapter 扩展 BaseAdapter {私有上下文上下文;私人 LayoutInflater 充气机;私人整数计数;公共 MainListAdapter(上下文上下文,int 计数){this.context = 上下文;this.inflater = LayoutInflater.from(context);this.count = 计数;}@覆盖公共 int getCount() {返回计数;}@覆盖公共对象getItem(int位置){返回位置;}@覆盖public long getItemId(int position){返回位置;}@覆盖public View getView(int position, View convertView, ViewGroup parent) {ViewHolder 支架;if(convertView == null) {持有人 = 新的 ViewHolder();convertView = createRow(父级,持有者);} 别的 {持有人 = (ViewHolder) convertView.getTag();}holder.textView.setText(Integer.toString(position));int randomPages = (int) (new Random().nextDouble()*5+2);holder.viewPager.setAdapter(new NumAdapter(context, randomPages));返回转换视图;}私有视图 createRow(ViewGroup parent, ViewHolder holder) {查看视图 = inflater.inflate(R.layout.row_main_listview, parent, false);holder.textView = (TextView) view.findViewById(R.id.row_num);holder.viewPager = (ViewPager) view.findViewById(R.id.row_viewpager);view.setTag(持有人);返回视图;}私有静态类 ViewHolder {公共文本视图文本视图;公共 ViewPager viewPager;}}

<块引用>

ViewPager 的适配器:

公共类 NumAdapter 扩展 PagerAdapter {私人 LayoutInflater 充气机;私人整数计数;公共 NumAdapter(上下文上下文,int 计数){this.inflater = LayoutInflater.from(context);this.count = 计数;}@覆盖公共对象实例化项(ViewGroup 容器,int 位置){TextView textView = (TextView) inflater.inflate(R.layout.page_viewpager, container, false);textView.setText("页面" + 位置);容器.addView(textView);返回文本视图;}@覆盖公共 int getCount() {返回计数;}@覆盖公共布尔 isViewFromObject(查看 arg0,对象 arg1){返回 arg0 == arg1;}@覆盖public void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View)object);}}

解决方案

尽管列表选择器不起作用,但这是我最终为解决此问题所做的工作.这可以改进,但就目前而言,这是我喜欢它工作方式的唯一解决方法.

public class CustomListView extends ListView implements AbsListView.OnScrollListener {/** 用于检测水龙头*/私有 GestureDetector TapDetector;/** 因为我们需要设置我们自己的 OnScrollListener,所以这里存储一个* 在外面使用,如果有的话*/私人 OnScrollListener onScrollListener;私有布尔 isScrolling = false;公共CustomListView(上下文上下文){超级(上下文);初始化视图(上下文);}公共CustomListView(上下文上下文,AttributeSet attrs){超级(上下文,属性);初始化视图(上下文);}public CustomListView(上下文上下文,AttributeSet attrs,int defStyleAttr){超级(上下文,属性,defStyleAttr);初始化视图(上下文);}@TargetApi(Build.VERSION_CODES.LOLLIPOP)public CustomListView(上下文上下文,AttributeSet attrs,int defStyleAttr,int defStyleRes){超级(上下文,属性,defStyleAttr,defStyleRes);初始化视图(上下文);}私人无效initView(上下文上下文){tapDetector = new GestureDetector(context, new TapListener());super.setOnScrollListener(this);}@覆盖公共无效 setOnScrollListener(OnScrollListener onScrollListener){this.onScrollListener = onScrollListener;}@覆盖公共布尔dispatchTouchEvent(MotionEvent ev){boolean isTap = tapDetector.onTouchEvent(ev);if(ev.getActionMasked() == MotionEvent.ACTION_UP) {//如果 ListView 正在滚动,则不执行单击//所以它能够停止滚动if(isTap && !isScrolling && hasOnItemClickListener()) {int itemPosition = pointToPosition((int)ev.getX(), (int)ev.getY());performItemClick(this, itemPosition, getItemIdAtPosition(itemPosition));}}返回 super.dispatchTouchEvent(ev);}公共布尔 hasOnItemClickListener() {返回 getOnItemClickListener() != null;}@覆盖公共无效 onScrollStateChanged(AbsListView 视图,int scrollState){isScrolling = scrollState != OnScrollListener.SCROLL_STATE_IDLE;如果(this.onScrollListener!= null){onScrollListener.onScrollStateChanged(view, scrollState);}}@覆盖公共无效 onScroll(AbsListView 视图,int firstVisibleItem,int visibleItemCount,int totalItemCount){如果(this.onScrollListener!= null){onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);}}

I have a ViewPager inside every row of a ListView. It works fine, it changes the views inside it when the user use the swipe gesture, but it prevents the ListView's onItemClick method to be called. I know that the ViewPager is the culprit because when I hide it, the onItemClick is called, so this is what I am trying:

I have created a ViewGroup to be the row (RowView). This ViewGroup has onInterceptTouchEvent overriden to avoid the ViewPager to handle further touch events when I detect a click. But the onItemClick callback is still not being called. And the list selector doesn't show either on click. I want this two features to work.

This is how the onInterceptTouchEvent from RowView looks like:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    int actionMasked = ev.getActionMasked();
    switch(actionMasked) {
        case MotionEvent.ACTION_DOWN:
            Log.d("RowView", "OnInterceptTouchEvent - Down");
            tapDetector.onTouchEvent(ev);
            return false;
        case MotionEvent.ACTION_CANCEL:
            Log.d("RowView", "OnInterceptTouchEvent - Cancel");
            tapDetector.onTouchEvent(ev);
            break;
        case MotionEvent.ACTION_UP:
            if(tapDetector.onTouchEvent(ev)) {
                Log.d("RowView", "OnInterceptTouchEvent - UP!");
                return true;
            }
            break;
    }

    return super.onInterceptTouchEvent(ev);
}

Any suggestions to solve this?

EDIT: Not working example about how the onItemClick in MainActivity is not called when the ViewPager is active (Lollipop list selector doesn't appear either)

MainActivity

ListView listView = (ListView) findViewById(R.id.main_list);
listView.setAdapter(new MainListAdapter(this, 30));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Log.d(TAG, "onItemClick: " + position);
    }
});

List item XML:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:descendantFocusability="blocksDescendants"
    >

    <TextView
        android:id="@+id/row_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        />

    <android.support.v4.view.ViewPager
        android:id="@+id/row_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        />
</RelativeLayout>

List adapter:

public class MainListAdapter extends BaseAdapter {
    private Context context;
    private LayoutInflater inflater;
    private int count;

    public MainListAdapter(Context context, int count) {
        this.context = context;
        this.inflater = LayoutInflater.from(context);
        this.count = count;
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if(convertView == null) {
            holder = new ViewHolder();
            convertView = createRow(parent, holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.textView.setText(Integer.toString(position));
        int randomPages = (int) (new Random().nextDouble()*5+2);
        holder.viewPager.setAdapter(new NumAdapter(context, randomPages));

        return convertView;
    }

    private View createRow(ViewGroup parent, ViewHolder holder) {
        View view = inflater.inflate(R.layout.row_main_listview, parent, false);
        holder.textView = (TextView) view.findViewById(R.id.row_num);
        holder.viewPager = (ViewPager) view.findViewById(R.id.row_viewpager);
        view.setTag(holder);

        return view;
    }

    private static class ViewHolder {
        public TextView textView;
        public ViewPager viewPager;
    }
}

ViewPager's Adapter:

public class NumAdapter extends PagerAdapter {
    private LayoutInflater inflater;
    private int count;

    public NumAdapter(Context context, int count) {
        this.inflater = LayoutInflater.from(context);
        this.count = count;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        TextView textView = (TextView) inflater.inflate(R.layout.page_viewpager, container, false);
        textView.setText("Page " + position);
        container.addView(textView);
        return textView;
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == arg1;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View)object);
    }
}

解决方案

This is what I've done finally to manage this although the list selector doesn't work. This could be improved, but, for now, it is the only workaround that I like how it works.

public class CustomListView extends ListView implements AbsListView.OnScrollListener {
    /*
     *  Used for detect taps
     */
    private GestureDetector tapDetector;
    /*
     *  As we need to set our own OnScrollListener, this stores the one 
     *  used outside, if any
     */
    private OnScrollListener onScrollListener;

    private boolean isScrolling = false;

    public CustomListView(Context context) {
        super(context);
        initView(context);
    }

    public CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CustomListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView(context);
    }

    private void initView(Context context) {
        tapDetector = new GestureDetector(context, new TapListener());
        super.setOnScrollListener(this);
    }

    @Override
    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean isTap = tapDetector.onTouchEvent(ev);

        if(ev.getActionMasked() == MotionEvent.ACTION_UP) {
            // Don't perform the click if the ListView is scrolling
            // so it is able to stop the scroll
            if(isTap && !isScrolling && hasOnItemClickListener()) {
                int itemPosition = pointToPosition((int)ev.getX(), (int)ev.getY());
                performItemClick(this, itemPosition, getItemIdAtPosition(itemPosition));
            }
        }

        return super.dispatchTouchEvent(ev);
    }

    public boolean hasOnItemClickListener() {
        return getOnItemClickListener() != null;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        isScrolling = scrollState != OnScrollListener.SCROLL_STATE_IDLE;

        if(this.onScrollListener != null) {
            onScrollListener.onScrollStateChanged(view, scrollState);
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if(this.onScrollListener != null) {
            onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

这篇关于ListView 行内的 ViewPager 防止 onItemClick 被触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:ListView 行内的 ViewPager 防止 onItemClick 被触发