0

我试图从不同的角度来解决这个问题,但没有运气。也许问一个一般性问题会有所帮助。

从技术上讲,我使用的是 osmdroid 的 MapView 实现,而不是 Google 的 Maps API,但我认为这个问题是更通用的编程视图与 onCreate 中定义的 main_activity.xml 视图。

基本上在我的 MainActivity 中,如果我创建一个视图,如 MapView,然后以编程方式将其设置为 ContentView,我还必须以编程方式添加我想在我的应用程序中显示的任何其他视图:

public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.mapView = new MapView(this, 256);
    ...
    this.setContentView(this.mapView);
}

如果我尝试将 ContentView 设置为 activity_main,则无法在创建时调整 MapView。也许我错过了一些东西:(请注意,我有处理加载自定义离线图块集的方法,并在地图上放置标记等......)

public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    this.mapView = (MapView)findViewById(R.id.mapview);
    ...
    this.intializeMapTiles();
    this.mapView.setBuiltInZoomControls(true);
    this.mapView.setMultiTouchControls(true);
    this.mapController.setCenter(new GeoPoint((int)(50.349622 * 1E6), (int)(-71.823700 *1E6)));
    ...
    this.mapView.invalidate();
}

在这种情况下,这是我的 activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <org.osmdroid.views.MapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="false"/>

</RelativeLayout>

当尝试从 ContentView (acitivty_main) 获取 MapView 时,我对它的任何方法更改都不会产生任何影响。就好像我无法访问正在呈现的确切 MapView。我试过让我的 MapView 无效,但这没关系。我得到一个默认外观和行为的 MapView。

我试图解决这个问题的原因自然是我在寻找我的应用程序来包含多个 MapView。我想包括一个SlidingDrawer,或者一些显示带有按钮的视图的方法,只有在你长按地图标记时才会显示。(请注意,我在地图标记长按时会显示 Toast 弹出窗口,所以我在这方面做得很好)

我必须以编程方式而不是从 main_activity.xml 添加这些其他视图(SlideingDrawer 等)。即使这样也有一个 catch-22,其中 SlidingDrawer 构造函数需要一个来自 xml 的 AttributeSet,这对自己构建来说很痛苦。(我试过了)那么你也必须担心布局。

有人有什么建议吗?通用还是其他?谢谢!

4

1 回答 1

1

出于多种原因,这实际上可能对其他人有用。

如果您不得不使用只能通过其编程构造函数配置所需方式的视图(例如,您可以只包含 activity_main.xml 中的视图,但视图不是您需要的,除非您自己构建它,就像使用 OSMDroid 的 MapView 使用离线平铺地图一样)然后您就无法扩展该视图并实现包含 AttributeSet 的该视图的构造函数。AttributeSet 基本上是从该视图的 activity_main.xml xml 解析的结构。当您从 onCreate() 中调用 this.setContentView(R.layout.activity_main) 时,该构造函数将在 Activity 中自动调用。因此,任何自定义构造函数的内容都需要进入扩展视图的构造函数。

例如,我必须扩展 OSMDroid MapView,然后完全从超级实现我的离线地图瓦片源。注意你必须 super() 扩展构造函数的第一行,因为对象方法在继承的构造函数完成之前不可用,所以任何 super() 方法调用都必须是静态方法。

public class FieldMapView extends MapView {
    public FieldMapView(Context context, AttributeSet attrs) throws Exception {
        super(
            context, 
            256, 
            new DefaultResourceProxyImpl(context), 
            FieldMapView.getOfflineMapProvider(context, MainActivity.mapTileArchiveFilename),
            null,
            attrs); 
        this.setUseDataConnection(false);
        this.setBuiltInZoomControls(false);
        this.setMultiTouchControls(true);
    }

然后在我的activity_main.xml中我指向视图的扩展版本:(例如FieldMapView)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.test.FieldMapView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="false"/>

所以现在我有我的扩展视图来处理任何程序化样式要求,我是如何让 SlidingDrawer 使用它的?我创建了一个以 0dip 高度视图作为句柄的 SlidingDrawer。然后我包含了一个 LinearLayout ,其中包含按钮,任何你想要的等等......

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.test.FieldMapView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="false"/>

    <SlidingDrawer
        android:layout_width="wrap_content"
        android:id="@+id/slidingDrawerActions"
    android:content="@+id/action_content"
    android:padding="10dip"
    android:layout_height="75dip"
        android:handle="@+id/handle2"
        android:layout_alignBottom="@id/mapview"
    android:orientation="vertical"
    android:clickable="false">

        <LinearLayout
            android:layout_width="wrap_content"
            android:id="@+id/action_content"
            android:orientation="horizontal"
            android:gravity="center"
            android:padding="10dip"
            android:background="#FF999999"
            android:layout_height="wrap_content"
            android:clickable="false">

            <View
                android:id="@id/handle2"
                android:layout_width="0dip"
                android:layout_height="0dip" />
            <ImageButton
                android:id="@+id/chatActionButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="2dip"
                android:src="@drawable/ic_action_edit"
                android:text="Chat">
            </ImageButton>
    </LinearLayout>
    </SlidingDrawer>
</RelativeLayout>

在我的 MainActivity onCreate() 中,我只是找到 SlidingDrawer 视图并相应地分配任何侦听器。为了在 MapView 中长按 Marker 时打开抽屉(这现在变得更加特定于 OSMDroid),我自然有一个 OnItemGestureListener 来打开抽屉:

class NodeGestureListener implements OnItemGestureListener<NodeOverlayItem> {
    @Override
    public boolean onItemLongPress(int index, NodeOverlayItem node) {
        if(slidingDrawerActions.isOpened() || slidingDrawerActions.isMoving()) {
            return false;
        }
        slidingDrawerActions.animateOpen();
        return false;
    }

棘手的部分是我想通过单击 MapView 来关闭它(而不是通过触摸占用空间的关闭按钮),所以我必须分配 SlidingDrawer.OnDrawerOpenListener 和 OnDrawerCloseListener 类。他们只是简单地翻转一个布尔值,指示抽屉是打开还是关闭。然后,我为 MapView 设置了一个简单的 onClickListener,如果它基于 SlidingDrawer 侦听器设置的 isActionDrawerOpen 打开,则关闭抽屉。

public void onCreate(final Bundle savedInstanceState) {
    ...
    this.mapView.setOnClickListener(new MapViewClickListener());
    ...
    this.slidingDrawerActions = (SlidingDrawer)findViewById(R.id.slidingDrawerActions);
    this.slidingDrawerActions.setOnDrawerOpenListener(new SlidingDrawerOpenListener());
    this.slidingDrawerActions.setOnDrawerCloseListener(new SlidingDrawerCloseListener());
    ...
}

...

private boolean isActionDrawerOpen = false;
class SlidingDrawerOpenListener implements SlidingDrawer.OnDrawerOpenListener {
    @Override
    public void onDrawerOpened() {
        isActionDrawerOpen = true;
    }
}
class SlidingDrawerCloseListener implements SlidingDrawer.OnDrawerCloseListener {
    @Override
    public void onDrawerClosed() {
        isActionDrawerOpen = false;
    }
}

private boolean skippedMapViewClickListener = false;
class MapViewClickListener implements OnClickListener {
    public void onClick(View view) {
        if(isActionDrawerOpen) {
            if(skippedMapViewClickListener) {
                slidingDrawerActions.animateClose();
                skippedMapViewClickListener = false;
            } else {
                skippedMapViewClickListener = true;
            }
        }
    }
}

Note the skippedMapViewClickListener boolean. The problem I had was that the MapView OnClickListener would be called immediately after the SlidingDrawer listener when long pressing the Marker. Meaning the long press would be considered a MapView click, plus the long press itself would open the drawer before OnClickListener was called, so OnClickListener would always see the drawer as open, and would close it. What I did was effectively skip the 1st onClick this way, so the drawer would stay open until you clicked on the MapView. Seems to work great.

I hope this helps someone. There are like 4 problems I solved with this approach.

于 2012-12-18T05:23:55.963 回答