forked from upstream-mirrors/OpenTracks
Use GestureDetector rather than doing it on our own.
This commit is contained in:
@@ -27,12 +27,14 @@ import android.graphics.Paint.Style;
|
|||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.GestureDetector;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.VelocityTracker;
|
import android.view.ScaleGestureDetector;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
|
||||||
import android.widget.Scroller;
|
import android.widget.Scroller;
|
||||||
|
|
||||||
|
import androidx.core.view.GestureDetectorCompat;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -94,8 +96,6 @@ public class ChartView extends View {
|
|||||||
private final int markerHeight;
|
private final int markerHeight;
|
||||||
private final Scroller scroller;
|
private final Scroller scroller;
|
||||||
private double maxX = 1.0;
|
private double maxX = 1.0;
|
||||||
private VelocityTracker velocityTracker = null;
|
|
||||||
private float lastMotionEventX = -1;
|
|
||||||
private int zoomLevel = 1;
|
private int zoomLevel = 1;
|
||||||
|
|
||||||
private int leftBorder = BORDER;
|
private int leftBorder = BORDER;
|
||||||
@@ -115,11 +115,76 @@ public class ChartView extends View {
|
|||||||
private boolean reportSpeed = true;
|
private boolean reportSpeed = true;
|
||||||
private boolean showPointer = false;
|
private boolean showPointer = false;
|
||||||
|
|
||||||
/**
|
private GestureDetectorCompat detectorScrollFlingTab = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||||
* Constructor.
|
|
||||||
*
|
@Override
|
||||||
* @param context the context
|
public boolean onDown(MotionEvent e) {
|
||||||
*/
|
if (!scroller.isFinished()) {
|
||||||
|
scroller.abortAnimation();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||||
|
if (Math.abs(distanceX) > 0) {
|
||||||
|
int availableToScroll = effectiveWidth * (zoomLevel - 1) - getScrollX();
|
||||||
|
if (availableToScroll > 0) {
|
||||||
|
scrollBy(Math.min(availableToScroll, (int) distanceX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||||
|
fling((int) -velocityX);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapConfirmed(MotionEvent event) {
|
||||||
|
// Check if the y event is within markerHeight of the marker center
|
||||||
|
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2) < markerHeight) {
|
||||||
|
int minDistance = Integer.MAX_VALUE;
|
||||||
|
Waypoint nearestWaypoint = null;
|
||||||
|
synchronized (waypoints) {
|
||||||
|
for (Waypoint waypoint : waypoints) {
|
||||||
|
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
nearestWaypoint = waypoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nearestWaypoint != null && minDistance < markerWidth) {
|
||||||
|
Intent intent = IntentUtils.newIntent(getContext(), MarkerDetailActivity.class)
|
||||||
|
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestWaypoint.getId());
|
||||||
|
getContext().startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private ScaleGestureDetector detectorZoom = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScale(ScaleGestureDetector detector) {
|
||||||
|
float scaleFactor = detector.getScaleFactor();
|
||||||
|
if (scaleFactor >= 1.1f) {
|
||||||
|
zoomIn();
|
||||||
|
return true;
|
||||||
|
} else if (scaleFactor <= 0.9) {
|
||||||
|
zoomOut();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
public ChartView(Context context, boolean chartByDistance) {
|
public ChartView(Context context, boolean chartByDistance) {
|
||||||
super(context);
|
super(context);
|
||||||
this.chartByDistance = chartByDistance;
|
this.chartByDistance = chartByDistance;
|
||||||
@@ -226,16 +291,6 @@ public class ChartView extends View {
|
|||||||
series[index].setEnabled(enabled);
|
series[index].setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets chart by distance.
|
|
||||||
* It is expected that after changing this value, data will be reloaded.
|
|
||||||
*
|
|
||||||
* @param value true for by distance, false for by time
|
|
||||||
*/
|
|
||||||
public void setChartByDistance(boolean value) {
|
|
||||||
chartByDistance = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets metric units.
|
* Sets metric units.
|
||||||
*
|
*
|
||||||
@@ -414,79 +469,14 @@ public class ChartView extends View {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
if (velocityTracker == null) {
|
boolean isZoom = detectorZoom.onTouchEvent(event);
|
||||||
velocityTracker = VelocityTracker.obtain();
|
boolean isScrollTab = detectorScrollFlingTab.onTouchEvent(event);
|
||||||
}
|
return isZoom || isScrollTab;
|
||||||
velocityTracker.addMovement(event);
|
|
||||||
float x = event.getX();
|
|
||||||
switch (event.getAction()) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
// Stop the fling
|
|
||||||
if (!scroller.isFinished()) {
|
|
||||||
scroller.abortAnimation();
|
|
||||||
}
|
|
||||||
lastMotionEventX = x;
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
if (lastMotionEventX == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Scroll to follow the motion event
|
|
||||||
int deltaX = (int) (lastMotionEventX - x);
|
|
||||||
lastMotionEventX = x;
|
|
||||||
if (deltaX < 0) {
|
|
||||||
if (getScrollX() > 0) {
|
|
||||||
scrollBy(deltaX);
|
|
||||||
}
|
|
||||||
} else if (deltaX > 0) {
|
|
||||||
int availableToScroll = effectiveWidth * (zoomLevel - 1) - getScrollX();
|
|
||||||
if (availableToScroll > 0) {
|
|
||||||
scrollBy(Math.min(availableToScroll, deltaX));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
// Check if the y event is within markerHeight of the marker center
|
|
||||||
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2) < markerHeight) {
|
|
||||||
int minDistance = Integer.MAX_VALUE;
|
|
||||||
Waypoint nearestWaypoint = null;
|
|
||||||
synchronized (waypoints) {
|
|
||||||
for (int i = 0; i < waypoints.size(); i++) {
|
|
||||||
Waypoint waypoint = waypoints.get(i);
|
|
||||||
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
|
|
||||||
if (distance < minDistance) {
|
|
||||||
minDistance = distance;
|
|
||||||
nearestWaypoint = waypoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nearestWaypoint != null && minDistance < markerWidth) {
|
|
||||||
Intent intent = IntentUtils.newIntent(getContext(), MarkerDetailActivity.class)
|
|
||||||
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestWaypoint.getId());
|
|
||||||
getContext().startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VelocityTracker myVelocityTracker = velocityTracker;
|
|
||||||
myVelocityTracker.computeCurrentVelocity(1000);
|
|
||||||
int initialVelocity = (int) myVelocityTracker.getXVelocity();
|
|
||||||
if (Math.abs(initialVelocity) > ViewConfiguration.getMinimumFlingVelocity()) {
|
|
||||||
fling(-initialVelocity);
|
|
||||||
}
|
|
||||||
if (velocityTracker != null) {
|
|
||||||
velocityTracker.recycle();
|
|
||||||
velocityTracker = null;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
updateEffectiveDimensionsIfChanged(
|
updateEffectiveDimensionsIfChanged(View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(heightMeasureSpec));
|
||||||
View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(heightMeasureSpec));
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,8 +626,7 @@ public class ChartView extends View {
|
|||||||
private String getXAxisLabel() {
|
private String getXAxisLabel() {
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
if (chartByDistance) {
|
if (chartByDistance) {
|
||||||
return metricUnits ? context.getString(R.string.unit_kilometer)
|
return metricUnits ? context.getString(R.string.unit_kilometer) : context.getString(R.string.unit_mile);
|
||||||
: context.getString(R.string.unit_mile);
|
|
||||||
} else {
|
} else {
|
||||||
return context.getString(R.string.description_time);
|
return context.getString(R.string.description_time);
|
||||||
}
|
}
|
||||||
@@ -737,8 +726,7 @@ public class ChartView extends View {
|
|||||||
* @param yValue the y value
|
* @param yValue the y value
|
||||||
* @return the marker width.
|
* @return the marker width.
|
||||||
*/
|
*/
|
||||||
private float drawYAxisMarker(
|
private float drawYAxisMarker(ChartValueSeries chartValueSeries, Canvas canvas, int xPosition, int yValue) {
|
||||||
ChartValueSeries chartValueSeries, Canvas canvas, int xPosition, int yValue) {
|
|
||||||
String marker = chartValueSeries.formatMarker(yValue);
|
String marker = chartValueSeries.formatMarker(yValue);
|
||||||
Paint paint = chartValueSeries.getMarkerPaint();
|
Paint paint = chartValueSeries.getMarkerPaint();
|
||||||
Rect rect = getRect(paint, marker);
|
Rect rect = getRect(paint, marker);
|
||||||
@@ -873,8 +861,7 @@ public class ChartView extends View {
|
|||||||
topBorder = (int) (density * BORDER + titleDimensions[0] * (titleDimensions[1] + spacer));
|
topBorder = (int) (density * BORDER + titleDimensions[0] * (titleDimensions[1] + spacer));
|
||||||
Rect xAxisLabelRect = getRect(axisPaint, getXAxisLabel());
|
Rect xAxisLabelRect = getRect(axisPaint, getXAxisLabel());
|
||||||
// border + x axis marker + spacer + .5 x axis label
|
// border + x axis marker + spacer + .5 x axis label
|
||||||
bottomBorder = (int) (density * BORDER + getRect(xAxisMarkerPaint, "1").height() + spacer
|
bottomBorder = (int) (density * BORDER + getRect(xAxisMarkerPaint, "1").height() + spacer + (xAxisLabelRect.height() / 2));
|
||||||
+ (xAxisLabelRect.height() / 2));
|
|
||||||
rightBorder = (int) (density * BORDER + xAxisLabelRect.width() + spacer);
|
rightBorder = (int) (density * BORDER + xAxisLabelRect.width() + spacer);
|
||||||
updateEffectiveDimensions();
|
updateEffectiveDimensions();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user