oubowu / PinnedSectionItemDecoration

A powerful ItemDecoration for Recyclerview, supports the common layoutmanager.
Apache License 2.0
2.09k stars 218 forks source link

ItemDecoration标签点击事件异常(标签布局中部分子View点击事件不生效) #80

Open liuyuttkx opened 5 years ago

liuyuttkx commented 5 years ago

设置标签可点击的View id, 如果该View在布局中是被多层嵌套的,它的点击事件不生效。 应用场景:粘性标签中不同子view拥有不同的点击事件。

示例:标签布局如下,并设置三个TextView可被点击 builder.setClickIds(R.id.stockName, R.id.ipo_time,R.id.fluctuate );

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root_item" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#987" android:orientation="horizontal">

<TextView
    android:id="@+id/stockName"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:gravity="left"
    android:paddingBottom="12dp"
    android:paddingTop="12dp"
    android:text="股票名称"
    android:textSize="13dp"
    android:layout_width="0dp" />

    <TextView
        android:id="@+id/ipo_time"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="上市日期"
 />

<LinearLayout
    android:id="@+id/ll_fluctuate"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:tag="test no"
    android:layout_weight="1.3"
    android:gravity="center">

    <TextView
        android:id="@+id/fluctuate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:gravity="right|center_vertical"
        android:lines="1"
        android:background="#f00"
        android:text="首日最"

/>

异常现象: view Id 为 stockName 、ipo_time 、ll_fluctuate 的三个View,如果设置点击事件,则可以在OnHeaderClickAdapter.class中的onHeaderClick(View view, int id, int position)方法中收到回调,但如果设置viewId 为fluctuate 的TextView可被点击,则它的点击事件无法生效。

原因:查看源码在Decoration初始化时,给设置点击事件的子View确定对应的区域时(点击事件触发时,根据点击的坐标来确认是发生在哪个子View的区域),是 PinnedHeaderItemDecoration 类的 401 行,该行实际上是调用 OnItemTouchListener.class 的setClickBounds(int id, View view)方法。源码如下:

public void setClickBounds(int id, View view) { ClickBounds bounds; if (mBoundsArray.get(id) == null) { bounds = new ClickBounds(view, view.getLeft(), view.getTop(), view.getLeft() + view.getMeasuredWidth(), view.getTop() + view.getMeasuredHeight()); mBoundsArray.put(id, bounds); } else { bounds = mBoundsArray.get(id); bounds.setBounds(view.getLeft(), view.getTop(), view.getLeft() + view.getMeasuredWidth(), view.getTop() + view.getMeasuredHeight()); } }

可以看出是根据子view的getLeft() getTop()等来确定View在Decoration中的坐标。但是getLeft() getTop()是获取相对父控件的距离。综上所述,结合布局,可以发现TextView fluctuate 的点击区域在初始化设置时,是它相对于它的父控制LinearLayout(id为ll_fluctuate)的值,而并不是实际相对于Decoration 的区域,所以 TextView id 为ipo_time stockName 可以正常获取点击事件,而点击TextView fluctuate 所在区域没有回调。

修复该问题: 在OnItemTouchListener 类中增加如下两个方法,并作出如下修改

将PinnedHeaderItemDecoration.class中401行和 SmallPinnedHeaderItemDecoration.class 的 274行的 mItemTouchListener.setClickBounds(mClickId, view); 修改为 mItemTouchListener.setClickViewkBounds(mPinnedHeaderView, mClickId, view);

`/**

public int[] getLeftAndTopBounds(View itemView, int childId, View view) { int[] bounds = new int[2]; if (itemView.getId() == childId) { bounds[0] = itemView.getLeft(); bounds[1] = itemView.getTop(); return bounds; } else { if (itemView instanceof ViewGroup) { ViewGroup group = (ViewGroup) itemView; for (int i = 0; i < group.getChildCount(); i++) { View childAt = group.getChildAt(i); if (childAt.getId() == childId) { bounds[0] = childAt.getLeft(); bounds[1] = childAt.getTop(); return bounds; } else if (childAt instanceof ViewGroup) { int[] childViewBounds = getLeftAndTopBounds(childAt, childId, view); if (childViewBounds != null) { bounds[0] = childViewBounds[0] + childAt.getLeft(); bounds[1] = childViewBounds[1] + childAt.getTop(); return bounds; } } } } } return null; }`

这仅仅是个人拙见,还请楼主测试一下。