【问题标题】:How to add a sliding drawer a MapView/View that's created programmatically如何向以编程方式创建的 MapView/View 添加滑动抽屉
【发布时间】:2012-12-03 08:59:30
【问题描述】:

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

从技术上讲,我使用的是 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,这对自己构建来说很痛苦。 (我试过了)那你也得担心布局了。

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

【问题讨论】:

  • 从您提交的代码来看,它应该可以工作。有两件事要尝试——确保您不会通过留下 this.mapView = new mapView(...) 调用而意外覆盖您的 this.mapView。其次,有时您需要在更改后刷新,因此请在更改后尝试 this.mapView.invalidate()。
  • 感谢您的建议。我更新了我的第二个样本。 this.mapView.invalidate() 没有帮助。 MapView 不接受我的方法调用(例如,图块、中心、缩放等都是默认设置,甚至不显示缩放控件)
  • 我仍然会检查您对 mapView 的引用,并确保它没有被意外修改。同时,您可以将编程视图元素与 XML 混合。您可以使用布局的 addView 方法将代码实例化的地图视图添加到 Xml 布局。有关这方面的示例,请参阅this question 的答案
  • 废话,你是对的!我在设置映射器的自定义 MapTiles 方法中重置了 MapView。我还没有说它是固定的,我只有时间来达到顶峰,但你应该提供这个作为答案,这样我就可以代表你了!
  • Arg... 我刚刚意识到我仍然存在必须以编程方式构造 MapView 的原始问题。 SlidingDrawer 视图等......都来自 Main_Activity,而我正在尝试用我自己的替换 Main_Activity 的 MapView。 (为我的图块、缩放按钮等构建和配置...)

标签: android android-activity android-mapview


【解决方案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 类。他们只是简单地翻转一个布尔值,指示抽屉是打开还是关闭。然后,我根据 SlidingDrawer 侦听器设置的 isActionDrawerOpen 为 MapView 设置一个简单的 onClickListener,如果它是打开的,它会关闭抽屉。

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 布尔值。我遇到的问题是,当长按标记时,会在 SlidingDrawer 侦听器之后立即调用 MapView OnClickListener。这意味着长按将被视为 MapView 单击,加上长按本身会在调用 OnClickListener 之前打开抽屉,因此 OnClickListener 将始终将抽屉视为打开并关闭它。我所做的就是以这种方式有效地跳过第一个 onClick,因此抽屉将保持打开状态,直到您单击 MapView。看起来效果很好。

我希望这对某人有所帮助。我用这种方法解决了大约 4 个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多