android - Fragment 内的 ScrollView 内的 MapFragment
android - MapFragment inside ScrollView inside Fragment
我的目标是让 MapFragment 处理触摸事件而不是 ScrollView。
MapFragment 正在以编程方式添加到 Fragment 内部的 ScrollView 中。
<ScrollView
android:id="@+id/scrollview_event"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/button_create"
android:layout_alignParentTop="true" >
<LinearLayout
android:id="@+id/linearlayout_event"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_light"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearlayout_where"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical" >
<RelativeLayout
android:id="@+id/linearlayout_header_event"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textview_where"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="@string/where"
android:textColor="@color/text_dark"
android:textSize="@dimen/text_heading" />
<View
android:id="@+id/view_divider_where"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@id/textview_where"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp"
android:background="@color/bg_dark" />
<ImageView
android:id="@+id/imageview_close_event"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_margin="5dp"
android:clickable="true"
android:onClick="onClickCloseEvent"
android:src="@drawable/close_dark" />
</RelativeLayout>
<FrameLayout
android:id="@+id/framelayout_map"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginTop="10dp" >
<FrameLayout
android:id="@+id/fragment_map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/imageview_center_event"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="top"
android:layout_margin="6dp"
android:background="@color/bg_transparent_light"
android:clickable="true"
android:padding="6dp"
android:src="@drawable/event_pin" />
<ImageView
android:id="@+id/imageview_my_position"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="bottom|left"
android:layout_margin="6dp"
android:background="@color/bg_transparent_light"
android:clickable="true"
android:padding="6dp"
android:src="@drawable/gps_target" />
</FrameLayout>
<TextView
android:id="@+id/textview_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@color/bg_dark"
android:padding="6dp"
android:textColor="@color/text_light"
android:textSize="@dimen/text_address"
android:visibility="visible" />
</LinearLayout>
//other views and layouts...
</LinearLayout>
</ScrollView>
mapFragment = new FragmentMap();
getChildFragmentManager().beginTransaction().add(R.id.fragment_map, mapFragment, TAG).commit();
getChildFragmentManager().executePendingTransactions();
FragmentMap 看起来像这样:
public class FragmentMap extends SupportMapFragment {
private OnTouchListener mListener;
private boolean mTouchListener = false;
@Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);
TouchableWrapper frameLayout = new TouchableWrapper(getActivity());
frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
frameLayout.addView(layout);
setListener(new OnTouchListener() {
@Override
public void onTouch() {
//Prevents NullPointerException
}
});
return frameLayout;
}
public void setListener(OnTouchListener listener) {
mListener = listener;
}
public interface OnTouchListener {
public abstract void onTouch();
}
public boolean getTouch() {
return mTouchListener;
}
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchListener = true;
break;
case MotionEvent.ACTION_UP:
mTouchListener = false;
break;
}
mListener.onTouch();
return super.dispatchTouchEvent(event);
}
}
}
我在地图上设置监听器:
mapFragment.setListener(new FragmentMap.OnTouchListener() {
@Override
public void onTouch() {
scrollView.requestDisallowInterceptTouchEvent(true);
}
});
这应该在 XML 布局中声明地图片段时起作用,但是当我以编程方式添加它时,它却不起作用。
要在父视图中启用或禁用拦截事件,您可以使用 Android 的 onInterceptTouchEvent(MotionEvent ev)
方法。但它是自上而下传播的(即父视图 return 如果它使用了事件则为真,否则为假)。所以创建一个扩展 ScrollView
的 class,并覆盖该方法:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(checkCoordinateCross(ev, YOUR_TARGET_VIEW_ID)) {
return false;
}
return true;
}
private boolean checkCoordinateCross(MotionEvent ev, int resId) {
View target = findViewById(resId);
if(target == null) {
return false;
}
if(ev.getX() > target.getX() && ev.getX() < target.getX() + target.getWidth() && ev.getY() > target.getY() && ev.getY() < target.getY() + target.getHeight()) {
return true;
}
return false;
}
请注意,YOUR_TARGET_VIEW_ID 必须是 ScrollView 的子级,否则 findViewById(...)
将 return 为空。
我的目标是让 MapFragment 处理触摸事件而不是 ScrollView。
MapFragment 正在以编程方式添加到 Fragment 内部的 ScrollView 中。
<ScrollView
android:id="@+id/scrollview_event"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/button_create"
android:layout_alignParentTop="true" >
<LinearLayout
android:id="@+id/linearlayout_event"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_light"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearlayout_where"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical" >
<RelativeLayout
android:id="@+id/linearlayout_header_event"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textview_where"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="@string/where"
android:textColor="@color/text_dark"
android:textSize="@dimen/text_heading" />
<View
android:id="@+id/view_divider_where"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@id/textview_where"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp"
android:background="@color/bg_dark" />
<ImageView
android:id="@+id/imageview_close_event"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_margin="5dp"
android:clickable="true"
android:onClick="onClickCloseEvent"
android:src="@drawable/close_dark" />
</RelativeLayout>
<FrameLayout
android:id="@+id/framelayout_map"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginTop="10dp" >
<FrameLayout
android:id="@+id/fragment_map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/imageview_center_event"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="top"
android:layout_margin="6dp"
android:background="@color/bg_transparent_light"
android:clickable="true"
android:padding="6dp"
android:src="@drawable/event_pin" />
<ImageView
android:id="@+id/imageview_my_position"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="bottom|left"
android:layout_margin="6dp"
android:background="@color/bg_transparent_light"
android:clickable="true"
android:padding="6dp"
android:src="@drawable/gps_target" />
</FrameLayout>
<TextView
android:id="@+id/textview_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@color/bg_dark"
android:padding="6dp"
android:textColor="@color/text_light"
android:textSize="@dimen/text_address"
android:visibility="visible" />
</LinearLayout>
//other views and layouts...
</LinearLayout>
</ScrollView>
mapFragment = new FragmentMap();
getChildFragmentManager().beginTransaction().add(R.id.fragment_map, mapFragment, TAG).commit();
getChildFragmentManager().executePendingTransactions();
FragmentMap 看起来像这样:
public class FragmentMap extends SupportMapFragment {
private OnTouchListener mListener;
private boolean mTouchListener = false;
@Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);
TouchableWrapper frameLayout = new TouchableWrapper(getActivity());
frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
frameLayout.addView(layout);
setListener(new OnTouchListener() {
@Override
public void onTouch() {
//Prevents NullPointerException
}
});
return frameLayout;
}
public void setListener(OnTouchListener listener) {
mListener = listener;
}
public interface OnTouchListener {
public abstract void onTouch();
}
public boolean getTouch() {
return mTouchListener;
}
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchListener = true;
break;
case MotionEvent.ACTION_UP:
mTouchListener = false;
break;
}
mListener.onTouch();
return super.dispatchTouchEvent(event);
}
}
}
我在地图上设置监听器:
mapFragment.setListener(new FragmentMap.OnTouchListener() {
@Override
public void onTouch() {
scrollView.requestDisallowInterceptTouchEvent(true);
}
});
这应该在 XML 布局中声明地图片段时起作用,但是当我以编程方式添加它时,它却不起作用。
要在父视图中启用或禁用拦截事件,您可以使用 Android 的 onInterceptTouchEvent(MotionEvent ev)
方法。但它是自上而下传播的(即父视图 return 如果它使用了事件则为真,否则为假)。所以创建一个扩展 ScrollView
的 class,并覆盖该方法:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(checkCoordinateCross(ev, YOUR_TARGET_VIEW_ID)) {
return false;
}
return true;
}
private boolean checkCoordinateCross(MotionEvent ev, int resId) {
View target = findViewById(resId);
if(target == null) {
return false;
}
if(ev.getX() > target.getX() && ev.getX() < target.getX() + target.getWidth() && ev.getY() > target.getY() && ev.getY() < target.getY() + target.getHeight()) {
return true;
}
return false;
}
请注意,YOUR_TARGET_VIEW_ID 必须是 ScrollView 的子级,否则 findViewById(...)
将 return 为空。