开发者

Android Rotating MapView

I am creating an application which trakcs down users path on a mapview. What I want to achieve when user takes a left turn for instance map should rotate it self in such a way that the head of the mapview should always point to upward direction. I hope that makes sense.

I came across Mr. Romain Guy's post an he says

开发者_开发问答I have done this in the past and it requires to create a custom ViewGroup that rotates the Canvas in the dispatchDraw() method. You also need to increase the size of the MapView (so that it draws enough pixels when rotated.) You will also need to rotate the touch events in dispatchTouchEvent(). Or if you use Android 3.0 you can simply call theMapView.rotate() :

Does anyone came accross some solution similiar to my question ? A working example would be excellent :)


Keep in mind that it's not an ideal approach, because the text on the map is a static image and will rotate along with the map tiles (at some point it will be upside down).

Here's an example of how to put the MapView into your own Layout widget and rotate it. I've done it with the OpenStreetMaps, but it should be quite the same for Google Maps.

First create the "rotating" Layout widget

package com.eli.util;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.LinearLayout;

public class RotatingLinearLayout extends LinearLayout {

    private final int mDiagonal;
    private float mBearing;

    public RotatingLinearLayout(final Context pContext, final AttributeSet pAttrs) {
        super(pContext, pAttrs);
        final DisplayMetrics dm = pContext.getResources().getDisplayMetrics();
        mDiagonal = (int) Math.hypot(dm.widthPixels, dm.heightPixels);
    }

    public void setBearing(final float pBearing) {
        mBearing = pBearing;
    }

    @Override
    protected void dispatchDraw(final Canvas pCanvas) {
        pCanvas.rotate(-mBearing, getWidth() >> 1, getHeight() >> 1);
        super.dispatchDraw(pCanvas);
    }

    @Override
    protected void onMeasure(final int pWidthMeasureSpec,
            final int pHeightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
        super.onMeasure(MeasureSpec.makeMeasureSpec(mDiagonal, widthMode), MeasureSpec.makeMeasureSpec(mDiagonal, heightMode));
    }
}

Surround by it your MapView in the layout.xml

<com.eli.util.RotatingLinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/rotating_layout">
    <org.osmdroid.views.MapView
        android:id="@+id/map_view"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:enabled="true"
        android:clickable="true"/>
</com.eli.util.RotatingLinearLayout>

Now, every time you receive a geo fix, update the bearing of the rotating layout and it should turn.


Here is the code that worked for me to have a proper centering of the view

@Override
protected void dispatchDraw(final Canvas pCanvas) {
    int translateX = mDiagonal / 2 - screenWidth / 2;
    int translateY = mDiagonal / 2 - screenHeight / 2;

    pCanvas.translate(- translateX, - translateY);
    pCanvas.rotate(-mBearing, mDiagonal / 2, mDiagonal / 2);

    super.dispatchDraw(pCanvas);
}


You can find an example at installation of android sdk

android-sdks/add-ons/addon-google_apis-google_inc_-8/samples/MapDemo

But maybe you have to change a bit two method to get right orientation on touch event.

private class RotateView extends ViewGroup implements SensorListener {

/* ...  */

    private Matrix invertedMatrix = new Matrix();
    private float[] tempLocation = new float[2];


    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.rotate(mHeading, getWidth() * 0.5f, getHeight() * 0.5f);
        canvas.getMatrix().invert(invertedMatrix);
        mCanvas.delegate = canvas;
        super.dispatchDraw(mCanvas);
        canvas.restore();
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        centeringAllowed = false;

        float[] location = tempLocation;
        location[0] = ev.getX();
        location[1] = ev.getY();
        invertedMatrix.mapPoints(location);
        ev.setLocation(location[0], location[1]);
        return super.dispatchTouchEvent(ev);
    }
}

This class is part of MapDemo project

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜