Add discrete granularity to pinch and scroll events (#170)

* Add discrete granularity to pinch and scroll events

* Better tests
pull/172/head
Mattia Iavarone 7 years ago committed by GitHub
parent 07f6078385
commit 9b8cc16d96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  2. 10
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  3. 25
      cameraview/src/main/views/com/otaliastudios/cameraview/GestureLayout.java
  4. 16
      cameraview/src/main/views/com/otaliastudios/cameraview/PinchGestureLayout.java
  5. 26
      cameraview/src/main/views/com/otaliastudios/cameraview/ScrollGestureLayout.java

@ -206,6 +206,7 @@ public class CameraViewTest extends BaseTest {
@Test
public void testGestureAction_zoom() {
mockController.mockStarted(true);
mockController.mZoomChanged = false;
MotionEvent event = MotionEvent.obtain(0L, 0L, 0, 0f, 0f, 0);
ui(new Runnable() {
@Override
@ -214,10 +215,18 @@ public class CameraViewTest extends BaseTest {
public boolean onTouchEvent(MotionEvent event) { return true; }
};
cameraView.mPinchGestureLayout.setGestureType(Gesture.PINCH);
cameraView.mapGesture(Gesture.PINCH, GestureAction.ZOOM);
}
});
mockController.mZoomChanged = false;
cameraView.mapGesture(Gesture.PINCH, GestureAction.ZOOM);
// If factor is 0, we return the same value. The controller should not be notified.
cameraView.mPinchGestureLayout.mFactor = 0f;
cameraView.dispatchTouchEvent(event);
assertFalse(mockController.mZoomChanged);
// For larger factors, the value is scaled. The controller should be notified.
cameraView.mPinchGestureLayout.mFactor = 1f;
cameraView.dispatchTouchEvent(event);
assertTrue(mockController.mZoomChanged);
}
@ -230,7 +239,7 @@ public class CameraViewTest extends BaseTest {
when(o.getExposureCorrectionMaxValue()).thenReturn(10f);
mockController.setMockCameraOptions(o);
mockController.mockStarted(true);
mockController.mExposureCorrectionChanged = false;
MotionEvent event = MotionEvent.obtain(0L, 0L, 0, 0f, 0f, 0);
ui(new Runnable() {
@Override
@ -239,10 +248,17 @@ public class CameraViewTest extends BaseTest {
public boolean onTouchEvent(MotionEvent event) { return true; }
};
cameraView.mScrollGestureLayout.setGestureType(Gesture.SCROLL_HORIZONTAL);
cameraView.mapGesture(Gesture.SCROLL_HORIZONTAL, GestureAction.EXPOSURE_CORRECTION);
}
});
mockController.mExposureCorrectionChanged = false;
cameraView.mapGesture(Gesture.SCROLL_HORIZONTAL, GestureAction.EXPOSURE_CORRECTION);
// If factor is 0, we return the same value. The controller should not be notified.
cameraView.mScrollGestureLayout.mFactor = 0f;
cameraView.dispatchTouchEvent(event);
assertFalse(mockController.mExposureCorrectionChanged);
// For larger factors, the value is scaled. The controller should be notified.
cameraView.mScrollGestureLayout.mFactor = 1f;
cameraView.dispatchTouchEvent(event);
assertTrue(mockController.mExposureCorrectionChanged);
}

@ -505,7 +505,9 @@ public class CameraView extends FrameLayout {
case ZOOM:
oldValue = mCameraController.getZoomValue();
newValue = source.scaleValue(oldValue, 0, 1);
mCameraController.setZoom(newValue, points, true);
if (newValue != oldValue) {
mCameraController.setZoom(newValue, points, true);
}
break;
case EXPOSURE_CORRECTION:
@ -513,8 +515,10 @@ public class CameraView extends FrameLayout {
float minValue = options.getExposureCorrectionMinValue();
float maxValue = options.getExposureCorrectionMaxValue();
newValue = source.scaleValue(oldValue, minValue, maxValue);
float[] bounds = new float[]{minValue, maxValue};
mCameraController.setExposureCorrection(newValue, bounds, points, true);
if (newValue != oldValue) {
float[] bounds = new float[]{minValue, maxValue};
mCameraController.setExposureCorrection(newValue, bounds, points, true);
}
break;
}
}

@ -7,12 +7,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
/**
* Using Views to address the need to draw stuff, but think about it.
* Simple classes could be enough.
*/
abstract class GestureLayout extends FrameLayout {
// The number of possible values between minValue and maxValue, for the scaleValue method.
// We could make this non-static (e.g. larger granularity for exposure correction).
private final static int GRANULARITY = 50;
protected boolean mEnabled;
protected Gesture mType;
protected PointF[] mPoints;
@ -48,5 +48,22 @@ abstract class GestureLayout extends FrameLayout {
return mPoints;
}
// Implementors should call capValue at the end.
public abstract float scaleValue(float currValue, float minValue, float maxValue);
// Checks for newValue to be between minValue and maxValue,
// and checks that it is 'far enough' from the oldValue, in order
// to reduce useless updates.
protected static float capValue(float oldValue, float newValue, float minValue, float maxValue) {
if (newValue < minValue) newValue = minValue;
if (newValue > maxValue) newValue = maxValue;
float distance = (maxValue - minValue) / (float) GRANULARITY;
float half = distance / 2;
if (newValue >= oldValue - half && newValue <= oldValue + half) {
// Too close! Return the oldValue.
return oldValue;
}
return newValue;
}
}

@ -3,12 +3,8 @@ package com.otaliastudios.cameraview;
import android.content.Context;
import android.graphics.PointF;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
class PinchGestureLayout extends GestureLayout {
@ -16,7 +12,7 @@ class PinchGestureLayout extends GestureLayout {
ScaleGestureDetector mDetector;
private boolean mNotify;
private float mAdditionFactor = 0;
/* tests */ float mFactor = 0;
public PinchGestureLayout(Context context) {
@ -32,7 +28,7 @@ class PinchGestureLayout extends GestureLayout {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mNotify = true;
mAdditionFactor = ((detector.getScaleFactor() - 1) * ADD_SENSITIVITY);
mFactor = ((detector.getScaleFactor() - 1) * ADD_SENSITIVITY);
return true;
}
});
@ -75,7 +71,7 @@ class PinchGestureLayout extends GestureLayout {
@Override
public float scaleValue(float currValue, float minValue, float maxValue) {
float add = mAdditionFactor;
float add = mFactor;
// ^ This works well if minValue = 0, maxValue = 1.
// Account for the different range:
add *= (maxValue - minValue);
@ -87,10 +83,6 @@ class PinchGestureLayout extends GestureLayout {
} else if (add < 0) {
add *= (currValue - minValue);
} Nope, I don't like this, it slows everything down. */
float newValue = currValue + add;
if (newValue < minValue) newValue = minValue;
if (newValue > maxValue) newValue = maxValue;
return newValue;
return capValue(currValue, currValue + add, minValue, maxValue);
}
}

@ -1,16 +1,9 @@
package com.otaliastudios.cameraview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
class ScrollGestureLayout extends GestureLayout {
@ -19,7 +12,7 @@ class ScrollGestureLayout extends GestureLayout {
private GestureDetector mDetector;
private boolean mNotify;
private float mDistance;
/* tests */ float mFactor;
public ScrollGestureLayout(Context context) {
@ -47,8 +40,8 @@ class ScrollGestureLayout extends GestureLayout {
horizontal = mType == Gesture.SCROLL_HORIZONTAL;
}
mPoints[1].set(e2.getX(), e2.getY());
mDistance = horizontal ? (distanceX / getWidth()) : (distanceY / getHeight());
mDistance = horizontal ? -mDistance : mDistance; // When vertical, up = positive
mFactor = horizontal ? (distanceX / getWidth()) : (distanceY / getHeight());
mFactor = horizontal ? -mFactor : mFactor; // When vertical, up = positive
mNotify = true;
return true;
}
@ -80,21 +73,14 @@ class ScrollGestureLayout extends GestureLayout {
@Override
public float scaleValue(float currValue, float minValue, float maxValue) {
float delta = mDistance; // -1 ... 1
float delta = mFactor; // -1 ... 1
// ^ This works well if minValue = 0, maxValue = 1.
// Account for the different range:
delta *= (maxValue - minValue); // -(max-min) ... (max-min)
delta *= 2; // Add some sensitivity.
// Add some sensitivity.
delta *= 2;
// Cap
float newValue = currValue + delta;
if (newValue < minValue) newValue = minValue;
if (newValue > maxValue) newValue = maxValue;
LOG.i("curr="+currValue, "min="+minValue, "max="+maxValue, "out="+newValue);
return newValue;
return capValue(currValue, currValue + delta, minValue, maxValue);
}
}

Loading…
Cancel
Save