Here's my problem. I finally figured out how to get my custom view
working, but discovered that "canvas.drawCircle(..)" draws based on
the screens dimensions and not the underlying bitmap (I may be
misusing some terms/concepts here, still a little iffy on the whole
custom view).
Basically, I have a bitmap of a map image, and I want to be able to
draw based on the bitmap's pixel dimensions, and to the bitmap if
possible, so that when it's panned/zoomed, it stays in its respective
place. Here is the code for my custom view. I x'd out my latitude and
longitude. The touch handling is code adapted from a Hello, Android
(3e) excerpt.
package mikey.gps.NAV;
import java.util.Vector;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
public class CustomView extends View {
private int mMode;
private double curLat, curLng;
public static final int MAP = 0;
public static final int NAV = 1;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Vector<LocationNode> mPath = new Vector<LocationNode>();
Bitmap map;
//Geographical information for translating to pixels
private double XZero = xxxxxx;
private double YZero = yyyyyyy;
private double XWidth = 0.01388333333334;
private double YWidth = 0.00693333333334;
//Image dimensions
private double IWidth = 1389;
private double IHeight = 971;
//Matrices for scaling the image
public Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public CustomView(Context context) {
super(context);
init();
}
private void init() {
map = BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.campus);
//mPaint.setFilterBitmap(true);
matrix.setTranslate(1f, 1f);
invalidate();
}
/* When the view is invalidated, onDraw does different actions
* depending on its mode. If it is the map display, it simply
* draws a circle on the current location. If it is on navigate,
* it draws a circle on the start and goal nodes, then lines to
* form the path.
*
* (non-Javadoc)
* @see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawBitmap(map, matrix, mPaint);
if(mMode == NAV) {
canvas.drawCircle(translateX(mPath.lastElement().lat),
translateY(mPath.lastElement().lng),
10, mPaint);
canvas.drawCircle(translateX(mPath.firstElement().lat),
translateY(mPath.firstElement().lng),
10, mPaint);
for(int i = 0; i < mPath.size()- 1; i++) {
LocationNode startNode = mPath.elementAt(i);
LocationNode stopNode = mPath.elementAt(i+1);
float startX = translateX(startNode.lat);
float startY = translateY(startNode.lng);
float stopX = translateX(stopNode.lat);
float stopY = translateY(stopNode.lng);
canvas.drawLine(startX, startY, stopX, stopY,
mPaint);
}
}
else if (mMode == MAP) {
canvas.drawCircle(translateX(curLat),
translateY(curLng), 10, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent e) {
// TODO Auto-generated method stub
WrapMotionEvent event = WrapMotionEvent.wrap(e);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
// ...
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
invalidate();
return true;
}
/* Handler method for touch events. The event
* is passed in from the overlying activity.
*/
public void setMatrix(WrapMotionEvent event) {
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
// ...
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
}
/** Determine the space between the first two fingers */
private float spacing(WrapMotionEvent event) {
// ...
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, WrapMotionEvent event) {
// ...
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/* Translates the latitude coordinate into a pixel coordinate */
public float translateX(double x) {
float newX = (float) (IWidth * ((x - XZero) / XWidth));
return newX;
}
/* Translates the longitude coordinate into a pixel coordinate */
public float translateY(double y) {
float newY = (float) (IHeight * ((YZero - y) / YWidth));
return newY;
}
/* Called by the navigator to enable drawing the route */
public void setPath(Vector<LocationNode> path) {
mPath.clear();
mPath = new Vector<LocationNode>(path);
}
/* Called by the map display to enable drawing the
* current location */
public void setCurLocation(double lat, double lng) {
curLat = lat;
curLng = lng;
}
public void setMode(int mode) {
mMode = mode;
}
}
I'm currently working with "MAP" mode, but it will also come into
play for NAV. But I basically need to draw to the bitmap, which is
scaled and manipulated through the canvas(?) so that the current
location dot will stay in the same spot when the bitmap is panned or
zoomed, instead of staying in a static location based on the screen's
dimensions. Any advice?
-Mike
--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en