12

我目前正在开发一个跟踪系统来绘制用户在房间内或其他任何地方的移动轨迹。

现在我已经设法将我的地图导入应用程序,并且地图可以自由缩放和移动。下一步是在地图上放置一个标记以指示用户位置,并将标记在地图上四处移动。(就像漂浮在地图上一样)

我在某处读到它并认为这可以完成MyLocationOverlay,但是网上的大多数示例都是将它应用到google map. 但是,就我而言,我的地图不是google map,而是我的 OWN 地图。(地图可以是我房间的地图,也可以是我自己画的地图!)

我已经完成了跟踪算法,即我知道在哪里放置我的标记图像

所以剩下的唯一问题是如何在地图图像之上呈现标记图像。

详细来说,我有一个自定义视图,MapView,如下:

package com.example.drsystem;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

public class MapView extends View {

    private static final int INVALID_POINTER_ID = -1;

    private Drawable mImage;
    private float mPosX;
    private float mPosY;

    private float mLastTouchX;
    private float mLastTouchY;
    private int mActivePointerId = INVALID_POINTER_ID;

    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    public MapView(Context context) {
        this(context, null, 0);

        mImage = getResources().getDrawable(R.drawable.lv12n);
        mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
    }

    // called when XML tries to inflate this View
    public MapView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

        mImage = getResources().getDrawable(R.drawable.lv12n);
        mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
    }

    public MapView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
            final float x = ev.getX();
            final float y = ev.getY();

            mLastTouchX = x;
            mLastTouchY = y;
            mActivePointerId = ev.getPointerId(0);
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float y = ev.getY(pointerIndex);

            // Only move if the ScaleGestureDetector isn't processing a gesture.
            if (!mScaleDetector.isInProgress()) {
                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;

                invalidate();
            }

            mLastTouchX = x;
            mLastTouchY = y;

            break;
        }

        case MotionEvent.ACTION_UP: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_POINTER_UP: {
            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = ev.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mLastTouchX = ev.getX(newPointerIndex);
                mLastTouchY = ev.getY(newPointerIndex);
                mActivePointerId = ev.getPointerId(newPointerIndex);
            }
            break;
        }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        Log.d("MapView", "X: " + mPosX + " Y: " + mPosY);
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        mImage.draw(canvas);
        canvas.restore();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));

            invalidate();
            return true;
        }
    }

}

至此,地图成功输入到应用程序中,既可移动又可缩放。

然后,我将此自定义视图插入到布局 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MapView" >

    <com.example.drsystem.MapView
        android:id="@+id/mapView1"
        android:layout_width="fill_parent"
        android:layout_height="400dp"
        android:layout_above="@+id/button2"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" />

 ...

</RelativeLayout>

基于所有这些信息,我如何绘制一个点并不断更新它在我的地图上的位置?

更新:

问题只是将另一个小图像放在自定义视图的顶部并移动它。

我还附上截图供您参考:

在此处输入图像描述

按钮和文本视图上方的区域是我的MapView

4

2 回答 2

2

首先,使用 LocationClient API(而不是 LocationManager),因为它们与混合 gps 提供商 wifi 和网络一起工作得非常好。他们还使用传感器来识别运动,以便节省电池电量。

我使用以下 LocationOverlay 鳕鱼将我的图标放在地图上。根据您的需要定制它。它有点粗糙但有效。

private class LocationMarker extends ItemizedOverlay<OverlayItem> {
    private Activity appContext;
    private List<OverlayItem> items = new ArrayList<OverlayItem>();
    private Drawable marker = null;
    private OverlayItem inDrag = null;
    private ImageView dragImage = null;
    private int xDragImageOffset = 0;
    private int yDragImageOffset = 0;
    private int xDragTouchOffset = 0;
    private int yDragTouchOffset = 0;
    private MapView location;
    private boolean pickupOrDrop;

    public LocationMarker(Activity newAppContext, MapView newLocation, Drawable newMarker,
            ImageView newPoint, boolean newWhichPoint) {
        super(newMarker);
        this.appContext = newAppContext;
        this.location = newLocation;
        this.marker = newMarker;
        this.dragImage = newPoint;
        this.pickupOrDrop = newWhichPoint;

        xDragImageOffset = dragImage.getDrawable().getIntrinsicWidth() / 2;
        yDragImageOffset = dragImage.getDrawable().getIntrinsicHeight();
        populate();
    }

    public void placeMarker(GeoPoint myPoint) {
        OverlayItem toDrop = new OverlayItem(myPoint, "", "");
        items.add(toDrop);
        populate();
    }

    @Override
    protected OverlayItem createItem(int i) {
        return (items.get(i));
    }

    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        super.draw(canvas, mapView, shadow);
        boundCenterBottom(marker);
    }

    @Override
    public int size() {
        return (items.size());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event, MapView mapView) {
        if (pickupOrDrop != whichPoint)
            return false;
        final int action = event.getAction();
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        boolean result = false;

        // Draw temp image
        if (action == MotionEvent.ACTION_DOWN) {
            Log.d("iTaxeeta:Overlay", "Action Down" + marker.toString());
            GeoPoint myPoint = null;
            if (items.isEmpty()) {
                if (whichPoint == PICKUP) {
                    myPoint = source = location.getProjection().fromPixels(
                            x - xDragTouchOffset, y - yDragTouchOffset);
                } else if (whichPoint == DROP) {
                    myPoint = destination = location.getProjection().fromPixels(
                            x - xDragTouchOffset, y - yDragTouchOffset);
                }
                OverlayItem toDrop = new OverlayItem(myPoint, "", "");
                items.add(toDrop);
                populate();
            }
            for (OverlayItem item : items) {
                Point p = new Point(0, 0);
                Log.d("iTaxeeta:Overlay", item.getTitle());
                location.getProjection().toPixels(item.getPoint(), p);
                if (hitTest(item, marker, x - p.x, y - p.y)) {
                    result = true;
                    inDrag = item;
                    items.remove(inDrag);
                    populate();

                    xDragTouchOffset = 0;
                    yDragTouchOffset = 0;
                    setDragImagePosition(p.x, p.y);

                    dragImage.setVisibility(View.VISIBLE);
                    xDragTouchOffset = x - p.x;
                    yDragTouchOffset = y - p.y;

                    break;
                } 
                else {
                    items.clear();
                    populate();
                    if (whichPoint == PICKUP)
                        myPoint = source = location.getProjection().fromPixels(
                                x - xDragTouchOffset, y - yDragTouchOffset);
                    else if (whichPoint == DROP)
                        myPoint = destination = location.getProjection().fromPixels(
                                x - xDragTouchOffset, y - yDragTouchOffset);
                    new GetGeoAddress((IActionBar) appContext, myPoint).execute();
                    OverlayItem toDrop = new OverlayItem(myPoint, "", "");
                    items.add(toDrop);
                    populate();
                    if (source != null && destination != null) {
                        searchCabs.setEnabled(true);
                        // tip.startAnimation(rollUpAnimation);
                        searchCabs.setTextColor(Color.parseColor("#eeeee4"));
                        if (whichPoint == PICKUP)
                            searchCabs.setBackgroundColor(Color.parseColor("#fe000a"));
                        else if (whichPoint == DROP)
                            searchCabs.setBackgroundColor(Color.parseColor("#17ee27"));
                    }
                    break;
                }
            }
        }
        // Draw temp image while moving finger across the screen
        else if (action == MotionEvent.ACTION_MOVE && inDrag != null) {
            Log.d("iTaxeeta:Overlay", "Action Move" + marker.toString());
            setDragImagePosition(x, y);
            result = true;
        }
        // Position the selected point now
        else if (action == MotionEvent.ACTION_UP && inDrag != null) {
            GeoPoint myPoint = null;
            Log.d("iTaxeeta:Overlay", "Action Up" + marker.toString());
            dragImage.setVisibility(View.VISIBLE);
            if (whichPoint == PICKUP)
                myPoint = source = location.getProjection().fromPixels(x - xDragTouchOffset,
                        y - yDragTouchOffset);
            else if (whichPoint == DROP)
                myPoint = destination = location.getProjection().fromPixels(
                        x - xDragTouchOffset, y - yDragTouchOffset);
            OverlayItem toDrop = new OverlayItem(myPoint, inDrag.getTitle(),
                    inDrag.getSnippet());
            items.add(toDrop);
            populate();
            inDrag = null;
            new GetGeoAddress((IActionBar) appContext, myPoint).execute();
            if (source != null && destination != null) {
                searchCabs.setEnabled(true);
                // tip.startAnimation(rollUpAnimation);
                searchCabs.setTextColor(Color.parseColor("#eeeee4"));
                if (whichPoint == PICKUP)
                    searchCabs.setBackgroundColor(Color.parseColor("#fe000a"));
                else if (whichPoint == DROP)
                    searchCabs.setBackgroundColor(Color.parseColor("#17ee27"));
            }
            result = true;

        }

        return (result || super.onTouchEvent(event, mapView));
    }
于 2013-07-05T06:11:05.607 回答
1

这是我的代码的一部分,它完成了你的要求(但仅用于拖动手势),缩放有点复杂。我需要知道您的缩放基于哪个点,例如两个手指的中间或屏幕上的 (0.0)

首先初始化点但不可见

ImageButton dot = new ImageButton(this);// since I add onClick for the dot     
//setImageBitmap
dot.setVisibility(View.INVISIBLE);
RelativeLayout.LayoutParams dotparams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
dotparams.setMargins(0,0,0,0); 
dot.setLayoutParams(dotparams);
final RelativeLayout myLayout = (RelativeLayout)findViewById(R.id.maplayout);//set an Id for your RelativeLayout 
myLayout.addView(dot,dotparams);

用于将具有相关位置的点添加到地图

dotImageWidth/Height 可以从 Bitmap.getWidth()/getHeight() 得到

private void displayPositon(int dotx, int doty) {
    dot.setVisibility(View.VISIBLE);
    RelativeLayout.LayoutParams dotparams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    dotparams.setMargins((int)(((android.widget.RelativeLayout.LayoutParams) mImage.getLayoutParams()).leftMargin + dotx - dotImageWidth/2 ),(int)(((android.widget.RelativeLayout.LayoutParams) mImage.getLayoutParams()).topMargin + doty - dotImageHeight),0,0);
    dot.setLayoutParams(params);

在 onTouchEvent 之前切换

RelativeLayout.LayoutParams params[];
params = new RelativeLayout.LayoutParams[2];//one is the top-left of your mapView, one is the dot
params[0]= (android.widget.RelativeLayout.LayoutParams) dot.getLayoutParams();
params[1]= (android.widget.RelativeLayout.LayoutParams) mImage.getLayoutParams();

案例 Action_Down

dotleftMargin = ((android.widget.RelativeLayout.LayoutParams) dot.getLayoutParams()).leftMargin;
dottopMargin = ((android.widget.RelativeLayout.LayoutParams) dot.getLayoutParams()).topMargin;
mapleftMargin = ((android.widget.RelativeLayout.LayoutParams) mImage.getLayoutParams()).leftMargin;
maptopMargin = ((android.widget.RelativeLayout.LayoutParams) mImage.getLayoutParams()).topMargin;

案例 ACTION_MOVE

params[0].setMargins((int)(x - mLastTouchX  + dotleftMargin), (int)(y- mLastTouchY + dottopMargin), 0, 0);
params[1].setMargins((int)(x - mLastTouchX  + mapleftMargin), (int)(y- mLastTouchY + maptopMargin), 0, 0);
于 2013-07-05T07:06:06.623 回答