如何添加滑动抽屉MapView / View以编程方式创建

时间:2012-12-15 17:03:03

标签: android android-activity android-mapview

我试图从不同角度处理这个问题而没有运气。也许提出一般性问题可能有所帮助。

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

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

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

如果我尝试将ContentView设置为activity_main,则无法在onCreate上调整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弹出窗口,所以我在这方面很好)

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

有人有什么建议吗?一般还是其他?谢谢!

1 个答案:

答案 0 :(得分:1)

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

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

例如,我不得不扩展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中,我指向View的扩展版本:(例如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"/>

所以现在我有我的扩展View来处理任何程序化的样式要求,我是如何让SlidingDrawer使用它的?我创建了一个SlidingDrawer,其高度为0dip View作为句柄。然后我包含了一个包含按钮的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;
            }
        }
    }
}

请注意skippedMapViewClickListener布尔值。我遇到的问题是,当长按Marker时,会在SlidingDrawer监听器之后立即调用MapView OnClickListener。这意味着长按将被视为MapView单击,加上长按本身将在调用OnClickListener之前打开抽屉,因此OnClickListener将始终将抽屉看作打开,并将关闭它。我所做的实际上是跳过第一个onClick这样,所以抽屉将保持打开,直到你点击MapView。似乎工作得很好。

我希望这有助于某人。我用这种方法解决了4个问题。