在Recyler视图中多次调用onClick

时间:2015-12-29 11:38:04

标签: android android-recyclerview

我想在Recycler View中处理事件 -

class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

        private ClickListener clickListener;
        private GestureDetector gestureDetector;

        public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener){

            this.clickListener = clickListener;
            gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
                @Override
                public boolean onSingleTapUp(MotionEvent e) {
                    return true;
                }

                @Override
                public void onLongPress(MotionEvent e) {
                   View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                    if(child!=null && clickListener!=null)
                    {
                        clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                        Log.i("TAG", "Radhe handling LongPress ");
                    }
                }
            });
        }

        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {

            View child = rv.findChildViewUnder(e.getX(), e.getY());
            if(child!=null && clickListener!=null && gestureDetector.onTouchEvent(e));
            {
                clickListener.onClick(child, rv.getChildPosition(child));
            }
            return false;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        }

    }

    public static interface ClickListener{
        public void onClick(View view, int position);
        public void onLongClick(View view, int position);

    }

此外,我还有以下代码 -

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
        recyclerView = (RecyclerView) layout.findViewById(R.id.drawerList);
        filterAdapter = new FilterAdapter(getActivity(), getData());
        recyclerView.setAdapter(filterAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
            @Override
            public void onClick(View view, int position) {
                Log.i("TAG", "Radhe child Clicked ");
                Toast.makeText(getActivity(),"CLick",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLongClick(View view, int position) {
                Log.i("TAG", "Radhe child Long Clicked ");
                Toast.makeText(getActivity(),"Long CLick",Toast.LENGTH_SHORT).show();
            }
        }));


        return layout;
    }

现在当我运行它时: - 和

This is not for multiple touches. I clicked only once. only once.

有人能说出为什么会这样吗?我不知道它的原因。提前谢谢。

6 个答案:

答案 0 :(得分:5)

当您从onClick致电onInterceptTouchEvent时,您需要return true来表明该事件已被消耗,而不是继续为其发起事件。

addOnItemTouchListener的Javadoc说:

  

一旦监听器从中返回true   RecyclerView.OnItemTouchListener.onInterceptTouchEvent(RecyclerView,   它的动作   RecyclerView.OnItemTouchListener.onTouchEvent(RecyclerView,   将为每个传入的MotionEvent调用MotionEvent方法,直到   手势的结束。

和来自onInterceptTouchEvent的错误表示

  

继续目前的行为并继续观察未来   手势中的事件。

只是为了澄清您现有的代码(但是我不确定您尝试使用if语句中的gestureDetector.onTouchEvent(e)实现了什么,请确保您不会意外地使用滚动事件):

@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
    View child = rv.findChildViewUnder(e.getX(), e.getY());
    if(child!=null && clickListener!=null && gestureDetector.onTouchEvent(e)) {
        clickListener.onClick(child, rv.getChildPosition(child));
        return true;
    }
    return false;
}

答案 1 :(得分:3)

我通常在适配器中处理点击事件,并通过类似下面的界面与片段/活动进行交互。

在适配器的 onBindViewHolder ;

viewHolder.mView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mListener.onItemClicked(holder.aValue);
    }
});

而mListener是一个带

的界面
public interface IclickListener<T> {

    void onItemClicked(T object);

}

答案 2 :(得分:0)

我的解决方案

  public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    if(e.getAction()==MotionEvent.ACTION_DOWN) return this.mGestureDetector.onTouchEvent(e);
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && this.mListener != null && this.mGestureDetector.onTouchEvent(e)) {
        this.mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        return true;
    }
    return false;

}

答案 3 :(得分:0)

我们可以利用Kotlin Extension Functions

用法

myView.setDebounceOnClickListener {
   // your code
}

扩展功能

fun View.setDebounceOnClickListener(onDebounceClick: (View) -> Unit) {
    val debounceClickListener = DebounceClickListener {
        onDebounceClick(it)
    }
    setOnClickListener(debounceClickListener)
}

使用

/**
 * Solves multiple click issue on view
 *
 * @param debounceDelayMillis delay millis which limits the rate at which a function gets invoked
 * @param onDebounceCLick a lambda block which gonna run if the interval between clicks is greater than provided delay millis
 *
 */
class DebounceClickListener(
    private var debounceDelayMillis: Int = 1000,
    private val onDebounceCLick: (View) -> Unit
) : View.OnClickListener {
    private var lastTimeClicked: Long = 0L
    override fun onClick(v: View) {
        if (SystemClock.elapsedRealtime() - lastTimeClicked < debounceDelayMillis) {
            return
        }
        lastTimeClicked = SystemClock.elapsedRealtime()
        onDebounceCLick(v)
    }
}

答案 4 :(得分:-1)

这应该解决它:

@Override
public boolean onSingleTapUp(MotionEvent e) {
      if(e.getAction()==MotionEvent.ACTION_UP)
      {
            //do something
      }
      return true;
}

答案 5 :(得分:-1)

我注意到,如果您在recyclerview中有“ n”个项目,它将循环“ n”次。 最好只将侦听器放在项目上。但是,

“返回真”使它循环两次。放置一个标志以避免循环(不推荐)

 @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                if(counter[0] ==1) {
                       // code
                    counter[0]=0;
                }
                else counter[0] +=1;

                return true;
            }