Skip to content

Commit

Permalink
snapToMarks added
Browse files Browse the repository at this point in the history
  • Loading branch information
shchurov committed Aug 6, 2016
1 parent 228752e commit b2bcd4c
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ private void setupCursorRect() {
cursorRect.right = cursorRect.left + cursorWidth;
}

int getMarksCount() {
return marksCount;
}

void onDraw(Canvas canvas) {
double step = 2 * PI / marksCount;
double offset = (PI / 2 - view.getRadiansAngle()) % step;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public HorizontalWheelView(Context context, AttributeSet attrs) {
super(context, attrs);
readAttrs(attrs);
drawer = new Drawer(this, attrs);
touchHandler = new TouchHandler(this);
touchHandler = new TouchHandler(this, attrs);
}

private void readAttrs(AttributeSet attrs) {
Expand Down Expand Up @@ -172,6 +172,10 @@ public void onRestoreInstanceState(Parcelable state) {
invalidate();
}

int getMarksCount() {
return drawer.getMarksCount();
}

public static class Listener {
public void onRotationChanged(double radians) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
Expand All @@ -11,33 +13,49 @@
import static com.github.shchurov.horizontalwheelview.HorizontalWheelView.SCROLL_STATE_DRAGGING;
import static com.github.shchurov.horizontalwheelview.HorizontalWheelView.SCROLL_STATE_IDLE;
import static com.github.shchurov.horizontalwheelview.HorizontalWheelView.SCROLL_STATE_SETTLING;
import static java.lang.Math.PI;

class TouchHandler extends GestureDetector.SimpleOnGestureListener {

private static final float SCROLL_ANGLE_MULTIPLIER = 0.002f;
private static final float FLING_ANGLE_MULTIPLIER = 0.0004f;
private static final float FLING_DURATION_MULTIPLIER = 0.2f;
private static final Interpolator INTERPOLATOR = new DecelerateInterpolator(1.4f);
private static final float FLING_ANGLE_MULTIPLIER = 0.0002f;
private static final int SETTLING_DURATION_MULTIPLIER = 1000;
private static final boolean DEFAULT_SNAP_TO_MARKS = false;
private static final Interpolator INTERPOLATOR = new DecelerateInterpolator(2.5f);

private HorizontalWheelView view;
private HorizontalWheelView.Listener listener;
private GestureDetector gestureDetector;
private ValueAnimator scrollAnimator;
private ValueAnimator settlingAnimator;
private boolean snapToMarks;
private int scrollState = SCROLL_STATE_IDLE;

TouchHandler(HorizontalWheelView view) {
TouchHandler(HorizontalWheelView view, AttributeSet attrs) {
this.view = view;
readAttrs(attrs);
gestureDetector = new GestureDetector(view.getContext(), this);
}

private void readAttrs(AttributeSet attrs) {
TypedArray a = view.getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalWheelView);
snapToMarks = a.getBoolean(R.styleable.HorizontalWheelView_snapToMarks, DEFAULT_SNAP_TO_MARKS);
a.recycle();
}

void setListener(HorizontalWheelView.Listener listener) {
this.listener = listener;
}

boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
if (event.getActionMasked() == MotionEvent.ACTION_UP && scrollState != SCROLL_STATE_SETTLING) {
updateScrollStateIfRequired(SCROLL_STATE_IDLE);
int action = event.getActionMasked();
if (scrollState != SCROLL_STATE_SETTLING
&& (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
if (snapToMarks) {
playSettlingAnimation(findNearestMarkAngle(view.getRadiansAngle()));
} else {
updateScrollStateIfRequired(SCROLL_STATE_IDLE);
}
}
return true;
}
Expand All @@ -48,6 +66,12 @@ public boolean onDown(MotionEvent e) {
return true;
}

void cancelFling() {
if (scrollState == SCROLL_STATE_SETTLING) {
settlingAnimator.cancel();
}
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
double newAngle = view.getRadiansAngle() + distanceX * SCROLL_ANGLE_MULTIPLIER;
Expand All @@ -65,21 +89,29 @@ private void updateScrollStateIfRequired(int newState) {

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
runFlingAnimation(velocityX);
updateScrollStateIfRequired(SCROLL_STATE_SETTLING);
double endAngle = view.getRadiansAngle() - velocityX * FLING_ANGLE_MULTIPLIER;
if (snapToMarks) {
endAngle = (float) findNearestMarkAngle(endAngle);
}
playSettlingAnimation(endAngle);
return true;
}

private void runFlingAnimation(float velocity) {
int duration = (int) Math.abs(velocity * FLING_DURATION_MULTIPLIER);
float startAngle = (float) view.getRadiansAngle();
float endAngle = startAngle - velocity * FLING_ANGLE_MULTIPLIER;
scrollAnimator = ValueAnimator.ofFloat(startAngle, endAngle)
private double findNearestMarkAngle(double angle) {
double step = 2 * PI / view.getMarksCount();
return Math.round(angle / step) * step;
}

private void playSettlingAnimation(double endAngle) {
updateScrollStateIfRequired(SCROLL_STATE_SETTLING);
double startAngle = view.getRadiansAngle();
int duration = (int) (Math.abs(startAngle - endAngle) * SETTLING_DURATION_MULTIPLIER);
settlingAnimator = ValueAnimator.ofFloat((float) startAngle, (float) endAngle)
.setDuration(duration);
scrollAnimator.setInterpolator(INTERPOLATOR);
scrollAnimator.addUpdateListener(flingAnimatorListener);
scrollAnimator.addListener(animatorListener);
scrollAnimator.start();
settlingAnimator.setInterpolator(INTERPOLATOR);
settlingAnimator.addUpdateListener(flingAnimatorListener);
settlingAnimator.addListener(animatorListener);
settlingAnimator.start();
}

private ValueAnimator.AnimatorUpdateListener flingAnimatorListener = new ValueAnimator.AnimatorUpdateListener() {
Expand All @@ -96,10 +128,4 @@ public void onAnimationEnd(Animator animation) {
}
};

void cancelFling() {
if (scrollAnimator != null && scrollAnimator.isRunning()) {
scrollAnimator.cancel();
}
}

}
1 change: 1 addition & 0 deletions library/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
<attr name="showActiveRange" format="boolean"/>
<attr name="endLock" format="boolean"/>
<attr name="onlyPositiveValues" format="boolean"/>
<attr name="snapToMarks" format="boolean"/>
</declare-styleable>
</resources>

0 comments on commit b2bcd4c

Please sign in to comment.