5

我在 ViewPager 的 Fragment 内使用 GoogleMap (v2 api)。我遇到的最初问题是 ViewPager 正在捕获所有水平滚动手势,因此只有在用户从垂直或对角方向开始时才能拖动地图。所有水平拖动都被ViewPager. 我发现解决方案是创建一个派生ViewPager类并覆盖该canScroll方法。被拖动的 View 被传递给这个方法,因此您可以根据它的 View 类型做出决定。

就我而言,我的 Fragment 是一个SupportMapFragment(来自com.google.android.gms.maps包),它给了我一个 GoogleMap 对象来与之交互。但是,我在 ViewPager 的canScroll方法中收到的实际控制是maps.j.b. 我已经用我的自定义 ViewPager 类中的以下代码解决了这个问题。但是,当我对此一无所知时,我对检查这个类名感到不舒服。什么是maps.jb?这是在运行时动态创建的类吗?在框架的未来更新中,类型是否可能发生变化?仅给定 View 对象,是否有更可靠的方法来检查拖动是否由地图控件启动?

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if(v.getClass().getName().equals("maps.j.b")) {
        return true;
    }
    return super.canScroll(v, checkV, dx, x, y);
}
4

3 回答 3

3

这是在运行时动态创建的类吗?

这可能是 ProGuard 重命名的输出。

在框架的未来更新中,类型是否可能发生变化?

AFAIK,是的。我不知道 ProGuard 保证名称在构建之间保持不变。

请注意,这将取决于库项目。当您使用新版本的库项目时,类名可能会更改。但是,由于这与您自己的应用程序相关联,因此在紧要关头,您可以坚持使用名称游戏,并且只需要在使用新版本的库项目时修复名称。

话虽如此,我同意基于名称的匹配是 icky。

仅给定 View 对象,是否有更可靠的方法来检查拖动是否由地图控件启动?

好吧,因为这不是 a MapView,所以我们无法知道 a 到底maps.j.b是什么。我们知道它不是 a MapView,因为它没有命名MapView,并且 Google 只保留了该名称(-keep大概是通过 ProGuard 配置中的指令),因此我们可以在我们的应用程序中使用它。

你可以尝试用你自己的来创建你自己MapFragmentMapView,看看你是否得到 aMapView而不是 a maps.j.b(这可能是MapViewused by 的一些内部子类SupportMapFragment)。如果您通过了实际的MapView,那么您可以进行直接相等性检查以查看传入的对象是否是您MapFragmentMapView.

或者,您可以查看是否instanceof说 amaps.j.b是 a MapView

随着时间的推移,这些都不能保证可靠,因为可以想象谷歌可以改变事情,以便将MapView其包裹在某些东西中。但是,我的猜测是它比生成的类名更可能是稳定的。

maps.j.b继承自SurfaceView。因此,半可靠地检测 a 是否View传入的一种方法canScroll()是测试 if (v instanceof SurfaceView)。如果 Maps V2 稍后执行其他操作(例如,TextureView在 API 级别 11+ 上扩展)或您的ViewPager页面有另一个SurfaceView(例如,a VideoView),则此操作会失败。

我已经就此提出了一个问题,试图获得一些稳定的方法来将此确定添加到 Maps V2 API。

于 2013-01-17T22:13:04.763 回答
2

希望这对一年后有所帮助......在我的情况下,我通过忽略 View 对象解决了这个问题。您可以做的是通知 CustomViewPager 以便当前页面包含地图。

public class CustomViewPager extends ViewPager {
    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (this.containsMap()) {
            return true;
        }
        return super.canScroll(v, checkV, dx, x, y);
    }
}

在我的情况下 containsMap() 只需检查当前页面是否对应于预定义的页面索引:

public boolean containsMap(){
    return getCurrentItem() == MAP_PAGE;
}

但它可能更复杂:添加一个名为 setCanScrollIndex(int index, boolean canScroll) 的方法来保留对那些包含地图的页面的引用。在适当的时候从你的活动中调用它。

于 2014-03-21T11:11:17.780 回答
2

首先,@Rich 感谢您分享您的解决方案 - 这是我一直在寻找的东西。我有一个视图寻呼机,其片段扩展 SupportMapfragment 是其项目之一。在我的解决方案中,我有一个自定义 XML 布局文件,因为我需要向片段添加一些额外的按钮。这是我的解决方案:

public class MapFragmentScrollOverrideViewPager extends ViewPager {

public MapFragmentScrollOverrideViewPager(Context context) {
    super(context);
}

public MapFragmentScrollOverrideViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if(v instanceof MapHoldingRelativeLayout) {
        return true;
    }
    return super.canScroll(v, checkV, dx, x, y);
} }

public class MapHoldingRelativeLayout extends RelativeLayout {

public MapHoldingRelativeLayout(Context context) {
    super(context);
}

public MapHoldingRelativeLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MapHoldingRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}  }

片段布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    xmlns:android="http://schemas.android.com/apk/res/android">

    <Button 
        android:id="@+id/switchNearbyOffersButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="XXXX"
        />

    <xxx.view.MapHoldingRelativeLayout
        android:id="@+id/mapLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/switchNearbyOffersButton"
         />

</RelativeLayout>

片段本身:

public final class NearbyOffersFragment extends SupportMapFragment {

    public static NearbyOffersFragment newInstance(String content) {
        NearbyOffersFragment fragment = new NearbyOffersFragment();
        return fragment;
    }

    private GoogleMap googleMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setUpMapIfNeeded();
    }

    private void setUpMapIfNeeded() {
        if (googleMap == null) {
            googleMap = getMap();
            if (googleMap != null) {
                setUpMap();
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        final View rootView = inflater.inflate(R.layout.fragment_nearby_offers,
                container, false);
        final View mapFragmentLayout = super.onCreateView(inflater, container,
                savedInstanceState);
        MapHoldingRelativeLayout mapLayout = (MapHoldingRelativeLayout) rootView
                .findViewById(R.id.mapLayout);
        mapLayout.addView(mapFragmentLayout);
        return rootView;
    }
    @Override
    public void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    private void setUpMap() {
        googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        googleMap.getUiSettings().setZoomControlsEnabled(true);
        googleMap.getUiSettings().setAllGesturesEnabled(true);
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(new LatLng(41.474856, -88.056928))
                .zoom(14.5f)
                .build();
        googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
    }
}

由于原始 SupportMapFragment 的布局在我的自定义 RelativeLyout 内,因此您可以使用 instanceof 运算符而不是直接引用 maps.jb 类...

于 2013-02-28T18:58:57.530 回答