[android] #4929 - rewrite MyLocationView with camera and transformation matrix

This commit is contained in:
Tobrun Van Nuland
2016-05-31 17:02:49 +02:00
committed by Brad Leege
parent c7fb8890fe
commit 163ee916e5
3 changed files with 63 additions and 50 deletions

View File

@@ -3,8 +3,10 @@ package com.mapbox.mapboxsdk.maps.widgets;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff;
@@ -22,6 +24,7 @@ import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
@@ -45,7 +48,6 @@ public class MyLocationView extends View {
private MyLocationBehavior myLocationBehavior;
private MapboxMap mapboxMap;
private Projection projection;
private int maxSize;
private int[] contentPadding = new int[4];
private Location location;
@@ -57,8 +59,8 @@ public class MyLocationView extends View {
private float gpsDirection;
private float previousDirection;
private float accuracy = 0;
private Paint accuracyPaint = new Paint();
private float accuracy;
private Paint accuracyPaint;
private ValueAnimator locationChangeAnimator;
private ValueAnimator accuracyAnimator;
@@ -79,6 +81,11 @@ public class MyLocationView extends View {
private int backgroundOffsetRight;
private int backgroundOffsetBottom;
private Matrix matrix;
private Camera camera;
private PointF screenLocation;
private float tilt;
@MyLocationTracking.Mode
private int myLocationTrackingMode;
@@ -105,9 +112,20 @@ public class MyLocationView extends View {
private void init(Context context) {
setEnabled(false);
// setup LayoutParams
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
setLayoutParams(lp);
matrix = new Matrix();
camera = new Camera();
camera.setLocation(0, 0, -1000);
accuracyPaint = new Paint();
myLocationBehavior = new MyLocationBehaviorFactory().getBehavioralModel(MyLocationTracking.TRACKING_NONE);
compassListener = new CompassListener(context);
maxSize = (int) context.getResources().getDimension(R.dimen.my_locationview_size);
}
public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bearingDrawable) {
@@ -151,7 +169,6 @@ public class MyLocationView extends View {
backgroundOffsetTop = top;
backgroundOffsetRight = right;
backgroundOffsetBottom = bottom;
setShadowDrawableTint(backgroundTintColor);
invalidateBounds();
@@ -187,19 +204,17 @@ public class MyLocationView extends View {
int backgroundWidth = backgroundDrawable.getIntrinsicWidth();
int backgroundHeight = backgroundDrawable.getIntrinsicHeight();
int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight;
int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom;
backgroundBounds = new Rect(-backgroundWidth / 2 + horizontalOffset, -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 + verticalOffset);
backgroundDrawable.setBounds(backgroundBounds);
int foregroundWidth = foregroundDrawable.getIntrinsicWidth();
int foregroundHeight = foregroundDrawable.getIntrinsicHeight();
foregroundBounds = new Rect(-foregroundWidth / 2, -foregroundHeight / 2, foregroundWidth / 2, foregroundHeight / 2);
foregroundDrawable.setBounds(foregroundBounds);
int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight;
int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom;
int accuracyWidth = 2 * maxSize;
backgroundBounds = new Rect(accuracyWidth - (backgroundWidth / 2) + horizontalOffset, accuracyWidth + verticalOffset - (backgroundWidth / 2), accuracyWidth + (backgroundWidth / 2) + horizontalOffset, accuracyWidth + (backgroundHeight / 2) + verticalOffset);
foregroundBounds = new Rect(accuracyWidth - (foregroundWidth / 2), accuracyWidth - (foregroundHeight / 2), accuracyWidth + (foregroundWidth / 2), accuracyWidth + (foregroundHeight / 2));
// invoke a new measure
// invoke a new draw
invalidate();
}
@@ -207,23 +222,44 @@ public class MyLocationView extends View {
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null) {
if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null || screenLocation == null) {
// Not ready yet
return;
}
// Draw circle
float metersPerPixel = (float) projection.getMetersPerPixelAtLatitude(location.getLatitude());
float accuracyPixels = (Float) accuracyAnimator.getAnimatedValue() / metersPerPixel;
float accuracyPixels = (Float) accuracyAnimator.getAnimatedValue() / metersPerPixel / 2;
float maxRadius = getWidth() / 2;
canvas.drawCircle(foregroundBounds.centerX(), foregroundBounds.centerY(), accuracyPixels <= maxRadius ? accuracyPixels : maxRadius, accuracyPaint);
accuracyPixels = accuracyPixels <= maxRadius ? accuracyPixels : maxRadius;
// Draw shadow
// put matrix in origin
matrix.reset();
// apply tilt to camera
camera.save();
camera.rotate(tilt, 0, 0);
// map camera matrix on our matrix
camera.getMatrix(matrix);
// put matrix at location of MyLocationView
matrix.postTranslate(screenLocation.x, screenLocation.y);
// concat our matrix on canvas
canvas.concat(matrix);
// restore orientation from camera
camera.restore();
// draw circle
canvas.drawCircle(0, 0, accuracyPixels, accuracyPaint);
// draw shadow
if (backgroundDrawable != null) {
backgroundDrawable.draw(canvas);
}
// Draw foreground
// draw foreground
if (myBearingTrackingMode == MyBearingTracking.NONE) {
if (foregroundDrawable != null) {
foregroundDrawable.draw(canvas);
@@ -233,27 +269,8 @@ public class MyLocationView extends View {
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (foregroundDrawable != null && foregroundBounds != null) {
foregroundDrawable.setBounds(foregroundBounds);
}
if (foregroundBearingDrawable != null && foregroundBounds != null) {
foregroundBearingDrawable.setBounds(foregroundBounds);
}
if (backgroundDrawable != null && backgroundBounds != null) {
backgroundDrawable.setBounds(backgroundBounds);
}
setMeasuredDimension(4 * maxSize, 4 * maxSize);
}
public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) {
setRotationX((float) tilt);
this.tilt = (float) tilt;
}
void updateOnNextFrame() {
@@ -627,8 +644,9 @@ public class MyLocationView extends View {
void invalidate() {
int[] mapPadding = mapboxMap.getPadding();
UiSettings uiSettings = mapboxMap.getUiSettings();
setX((uiSettings.getWidth() - getWidth() + mapPadding[0] - mapPadding[2]) / 2 + (contentPadding[0] - contentPadding[2]) / 2);
setY((uiSettings.getHeight() - getHeight() - mapPadding[3] + mapPadding[1]) / 2 + (contentPadding[1] - contentPadding[3]) / 2);
float x = (uiSettings.getWidth() - getWidth() + mapPadding[0] - mapPadding[2]) / 2 + (contentPadding[0] - contentPadding[2]) / 2;
float y = (uiSettings.getHeight() - getHeight() - mapPadding[3] + mapPadding[1]) / 2 + (contentPadding[1] - contentPadding[3]) / 2;
screenLocation = new PointF(x, y);
MyLocationView.this.invalidate();
}
}
@@ -694,11 +712,7 @@ public class MyLocationView extends View {
@Override
void invalidate() {
PointF screenLocation = projection.toScreenLocation(latLng);
if (screenLocation != null) {
setX((screenLocation.x - getWidth() / 2));
setY((screenLocation.y - getHeight() / 2));
}
screenLocation = projection.toScreenLocation(latLng);
MyLocationView.this.invalidate();
}
}