【问题标题】:How to get specific view clicked from RecyclerView with onInterceptTouchEvent?如何使用 onInterceptTouchEvent 从 RecyclerView 单击特定视图?
【发布时间】:2015-11-13 23:20:37
【问题描述】:

我一直在寻找,但仍然没有找到任何东西。我试过了

View child = mirecycler.findChildViewUnder(e.getX(), and.getY());  

在我的情况下,它仅用于获取父级 CardView 容器“行”,我需要获取特定的 TextViewImageView

我想将onClick 设置为ImageView 而不影响onClickCardView

public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
    View child = rv.findChildViewUnder(e.getX(), e.getY());
    if (child != null && mGestureDetector.onTouchEvent(e)) {
        Toast.makeText(MainActivity.this, "tocaste " + child, Toast.LENGTH_SHORT).show();
        return true;
    }
    return false;
}

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

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}

【问题讨论】:

  • 正确格式化所有代码会很有帮助。

标签: android android-recyclerview onclicklistener


【解决方案1】:

如果您必须使用 onInterceptTouchEvent,我不确定是否可以帮助您。我只在不需要管理特定点击时使用它,但也许我的解决方案可以与它一起使用(虽然我没有尝试过)

我将为您提供一个解决方案,使用客户适配器检测点击的位置:

public class SomeRecyclerAdapter extends RecyclerView.Adapter<SomeRecyclerAdapter.SomeListViewHolder> {

    ....

    @Override
public void onBindViewHolder(final SomeViewHolder holder, final int position) {
    SomeItem item = someList.get(position);

    holder.itemView.setTag(item);
    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            SomeListItem item = (SomeListItem) holder.itemView.getTag();
            Toast.makeText(context, "Recycle Click " + item.getName(), Toast.LENGTH_SHORT).show();
        }
    });

    holder.vImage.setTag(item);
    holder.vImage
            .setOnClickListener(new CompoundButton.OnClickListener(){

                @Override
                public void onClick(View v) {
                    SomeListItem item = (SomeItem) holder.vImage.getTag();
                    Toast.makeText(context, item.getName() + " Image Clicked", Toast.LENGTH_SHORT).show();
                }
            });
    ....

    public static class SomeListViewHolder extends RecyclerView.ViewHolder{
        protected ImageView vImage;

        public SomeListViewHolder(View itemView) {
            super(itemView);
            vImage = (ImageView) itemView.findViewById(R.id.tem_some_list);
        }

    }

}

我的示例是如何处理 Recycler 项目图像中的点击。 我已经尝试过这个解决方案并且它有效,这意味着如果您单击该项目(图像除外),它将打印“Recycle Click ...”,如果您单击图像,它将打印“...”。点击图片”。

也许(未经测试,但您可以这样做并告诉我们)您可以将 onInterceptTouchEvent 用于 CardView,将 onClickListener 用于图像。

我希望这是您正在寻找的,如果您找到更好的解决方案,请告诉我。

【讨论】:

  • 不要将您的项目用作查看器的标签。您的项目数据有时会发生变化,另一方面,您也必须分配一些额外的内存。
  • 我在这个 repo github.com/eneim/RVP 中做了一个简单的 onItemClick,它使用了 viewholder 的适配器位置,尊重 Android 峰会演示。希望能给你一些新的想法
【解决方案2】:
public class RecyclerViewItemClickListener implements RecyclerView.OnItemTouchListener {

    private static final String TAG = RecyclerItemClickListener.class.getSimpleName();

    public void setListener(OnItemClickListener mListener) {
        this.mListener = mListener;
    }

    private OnItemClickListener mListener;

    public RecyclerViewItemClickListener(Context context) {
        this(context, null);
    }


    GestureDetector mGestureDetector;

    public RecyclerViewItemClickListener(Context context, OnItemClickListener listener) {
        mListener = listener;
        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }
        });
    }

    @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());
        View exactView = findExactChild(childView, e.getX(), e.getY())
        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(view, exactView, view. view.getChildPosition(childView));
        }
        return false;
    }

    @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

public View findExactChild(View childView, int x, int y){
            if(!(childView instanceof ViewGroup)) return child;
        ViewGroup group = (ViewGroup) childView;
            final int count = group.getChildCount();
            for (int i = count - 1; i >= 0; i--) {
                final View child = group.getChildAt(i);
                final float translationX = child.getTranslationX();
                final float translationY = child.getTranslationY();
                if (x >= child.getLeft() + translationX &&
                        x <= child.getRight() + translationX &&
                        y >= child.getTop() + translationY &&
                        y <= child.getBottom() + translationY) {
                    return child;
                }
            }
            return null;
        }
    }

正如你所说,findViewUnder 只返回容器。您需要再运行一次,以确定触摸事件的 x 和 y 是否在容器的任何子级上。

View exactView = findExactChild(childView, e.getX(), e.getY())

这将运行另一遍以找到确切的孩子。

【讨论】:

  • 如果我没记错这一行 if(!(childView instanceof ViewGroup)) return child;应该返回 childView 而不是 child
  • ViewCompat.getTranslationX(child) 返回 0.0
  • @wonsuc 你不应该使用ViewCompat,尝试直接调用getTranslationY()
  • @NikolaDespotoski 我做了,结果是一样的。
【解决方案3】:

所以一种解决方案是使用 onTouchListener。您可以做的是在您的子 ImageView 上设置一个 onTouchListener 并返回 true,这样触摸就不会传递给视图父级。

【讨论】:

    【解决方案4】:

    NBajanca 的回答效果很好,但在适配器内无法访问 mainactivity 的 UI 元素,因此解决方案是使用 de 回调。

    然后,我们在适配器中的代码将如下所示。

    public class NegociosAdapter extends RecyclerView.Adapter<NegociosAdapter.ViewHolder>  {
    
       interface MyCallback{
           void Presionofoto(int position);
       }
        private MyCallback callback;
    
     public NegociosAdapter(ArrayList<Negocios> negociosArrayList,MyCallback callback) {
            this.negociosArrayList = negociosArrayList;
            this.callback=callback;
        }
    public static class ViewHolder extends RecyclerView.ViewHolder  {
    
            public ImageView foto;
            public TextView nombre;
    
            public ViewHolder(View itemView) {
    
                super(itemView);
                foto = (ImageView) itemView.findViewById(R.id.foto);
                nombre = (TextView) itemView.findViewById(R.id.txtnombre);
    
            }
        }
     public void onBindViewHolder(ViewHolder viewHolder, final int position) {
    
            Negocios rowNegocio = negociosArrayList.get(position);
            viewHolder.nombre.setText(rowNegocio.getNombre());
             viewHolder.foto.setImageBitmap(rowNegocio.getImagen());
             viewHolder.foto.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    callback.Presionofoto(position);
                   //When click here method "Presionofoto" be running on mainactivity
    
                }
            });
    }
     @Override
        public int getItemCount() {
            return negociosArrayList.size();
        }
    }
    

    在主要活动中:

    public class MainActivity extends AppCompatActivity implements NegociosAdapter.MyCallback{
    
     NegociosAdapter adapter = new NegociosAdapter(datosResult,this);
                recycler.setAdapter(adapter);
    
    //we have that implement method abstract "Presionofoto"
    
    @Override
    public void Presionofoto(final int position) {
    //here we can access to UI, this 
     Toast.makeText(getBaseContext(), "Hello From MainActivity", Toast.LENGTH_SHORT).show();
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-13
      • 1970-01-01
      • 2019-01-21
      • 2020-01-19
      相关资源
      最近更新 更多