在 ListViews 中使用 ViewStub 会导致 onItemClick 问题
Using ViewStub within ListViews causes onItemClick problems
我有一个有趣的困境。我有一个 ListView
,我用它来包含 CardView
。但是,每个 CardView
实际上是一对两个:一张默认(正面)卡片,然后是一张背面卡片,我将其设置为在用户单击卡片时翻转。由于用户可能不会点击任何列表项,我使用 ViewStub
作为背卡,并会在列表项点击时延迟膨胀。
因此,当用户第一次单击卡片以翻到背面时,一切看起来都很好并且翻页有效(onItemClick()
通过单击卡片中的任意位置调用)。但是,任何再次翻转到前面的尝试都不会触发 onItemClick()
调用,除非我单击视图的最顶部(列表项)。
我做了很多调试(改变焦点和大小)并发现这是仅在 ViewStub
inflation 之后引起的。使前后卡片正常 CardView
s 允许 onItemClick()
每次都成功发射。
那么 ViewStub
对我的 onItemClick()
造成困扰的原因是什么?有没有办法解决它,而不是让我的所有视图自动膨胀?
这是我使用的代码:
card_container_layout.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<include layout="@layout/card_front_view"
android:id="@+id/main_card_view_layout" />
<ViewStub android:id="@+id/stub_flipped_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/flipped_card"
android:layout="@layout/card_back_view" />
</FrameLayout>
card_front_view.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp"
android:id="@+id/card_view"
android:descendantFocusability="blocksDescendants" >
<LinearLayout
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/card_view_height">
<ImageView android:id="@+id/img_main_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/my_image"
android:background="#ff10fffd" />
<TextView
android:id="@+id/lbl_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Name"
style="@style/main_card_title_text"
android:layout_alignParentBottom="true"
android:padding="15dp"
android:background="#5b000000"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:padding="4dp" >
<TextView
android:id="@+id/lbl_item_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
style="@style/main_card_text" />
<ImageView android:id="@+id/img_sync_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_centerVertical="true"/>
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
card_back_view.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_width="match_parent"
card_view:cardCornerRadius="5dp"
android:id="@+id/flipped_card"
android:alpha="0"
android:descendantFocusability="blocksDescendants">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Here are the items:"
android:gravity="center"
style="@style/card_flipped_title_text"
android:background="#ad000000"/>
<GridView android:id="@+id/grid_images"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:numColumns="3">
<!-- make believe there were items here -->
</GridView>
</LinearLayout>
</android.support.v7.widget.CardView>
好吧,我做了更多的深入研究,看来根本不是 ViewStub
造成的,实际上是 GridView
。由于我无法弄清楚的原因,GridView
继续劫持所有触摸事件,尽管将 focusable 和 clickable 设置为 false 并阻止了后代 focusability,如上面的示例 XML 所示。
因此,我绕过它的 hacky 方法是拦截来自 GridView 的所有触摸事件,并且在 onTouchListener()
内,如果我检测到 MotionEvent.ACTION_UP
,表明我已经触摸屏幕并刚刚松开,然后我将手动执行与 CardView
.
其余部分相同的操作
itemGrid.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View grid, MotionEvent event) {
// hacky way to make sure that we absorb the GridView's focus stealing and still do the right thing
if (MotionEvent.ACTION_UP == event.getAction()) doExpectedStuff();
return true; // absorb the touch here
}
});
抱歉,这不是最优雅的解决方案,并且同意捕获 up 事件对大多数人来说并不是一种放之四海而皆准的方法,但它对我的具体情况有所帮助。希望这仍然可以帮助其他人。
我有一个有趣的困境。我有一个 ListView
,我用它来包含 CardView
。但是,每个 CardView
实际上是一对两个:一张默认(正面)卡片,然后是一张背面卡片,我将其设置为在用户单击卡片时翻转。由于用户可能不会点击任何列表项,我使用 ViewStub
作为背卡,并会在列表项点击时延迟膨胀。
因此,当用户第一次单击卡片以翻到背面时,一切看起来都很好并且翻页有效(onItemClick()
通过单击卡片中的任意位置调用)。但是,任何再次翻转到前面的尝试都不会触发 onItemClick()
调用,除非我单击视图的最顶部(列表项)。
我做了很多调试(改变焦点和大小)并发现这是仅在 ViewStub
inflation 之后引起的。使前后卡片正常 CardView
s 允许 onItemClick()
每次都成功发射。
那么 ViewStub
对我的 onItemClick()
造成困扰的原因是什么?有没有办法解决它,而不是让我的所有视图自动膨胀?
这是我使用的代码:
card_container_layout.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<include layout="@layout/card_front_view"
android:id="@+id/main_card_view_layout" />
<ViewStub android:id="@+id/stub_flipped_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/flipped_card"
android:layout="@layout/card_back_view" />
</FrameLayout>
card_front_view.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp"
android:id="@+id/card_view"
android:descendantFocusability="blocksDescendants" >
<LinearLayout
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/card_view_height">
<ImageView android:id="@+id/img_main_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/my_image"
android:background="#ff10fffd" />
<TextView
android:id="@+id/lbl_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Name"
style="@style/main_card_title_text"
android:layout_alignParentBottom="true"
android:padding="15dp"
android:background="#5b000000"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:padding="4dp" >
<TextView
android:id="@+id/lbl_item_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
style="@style/main_card_text" />
<ImageView android:id="@+id/img_sync_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_centerVertical="true"/>
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
card_back_view.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_width="match_parent"
card_view:cardCornerRadius="5dp"
android:id="@+id/flipped_card"
android:alpha="0"
android:descendantFocusability="blocksDescendants">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Here are the items:"
android:gravity="center"
style="@style/card_flipped_title_text"
android:background="#ad000000"/>
<GridView android:id="@+id/grid_images"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:numColumns="3">
<!-- make believe there were items here -->
</GridView>
</LinearLayout>
</android.support.v7.widget.CardView>
好吧,我做了更多的深入研究,看来根本不是 ViewStub
造成的,实际上是 GridView
。由于我无法弄清楚的原因,GridView
继续劫持所有触摸事件,尽管将 focusable 和 clickable 设置为 false 并阻止了后代 focusability,如上面的示例 XML 所示。
因此,我绕过它的 hacky 方法是拦截来自 GridView 的所有触摸事件,并且在 onTouchListener()
内,如果我检测到 MotionEvent.ACTION_UP
,表明我已经触摸屏幕并刚刚松开,然后我将手动执行与 CardView
.
itemGrid.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View grid, MotionEvent event) {
// hacky way to make sure that we absorb the GridView's focus stealing and still do the right thing
if (MotionEvent.ACTION_UP == event.getAction()) doExpectedStuff();
return true; // absorb the touch here
}
});
抱歉,这不是最优雅的解决方案,并且同意捕获 up 事件对大多数人来说并不是一种放之四海而皆准的方法,但它对我的具体情况有所帮助。希望这仍然可以帮助其他人。