some weird moving

This commit is contained in:
serso
2011-09-12 22:54:54 +04:00
parent 6ee636bb5d
commit 7702fa3db9
24 changed files with 2061 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.solovyev.android.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.widget.Button;
import android.view.MotionEvent;
import android.content.res.Resources;
import org.jetbrains.annotations.NotNull;
import org.solovyev.util.math.Point2d;
/**
* NOTE: copied from com.android.calculator2.ColorButton
*/
/**
* Button with click-animation effect.
*/
public class ColorButton extends Button {
int CLICK_FEEDBACK_COLOR;
static final int CLICK_FEEDBACK_INTERVAL = 10;
static final int CLICK_FEEDBACK_DURATION = 350;
@NotNull
private Point2d textPosition;
private long mAnimStart;
private Paint mFeedbackPaint;
public ColorButton(Context context, AttributeSet attrs) {
this(context, attrs, true);
}
public ColorButton(Context context, AttributeSet attrs, boolean init) {
super(context, attrs);
if (init) {
init(context);
}
}
protected void init(Context context) {
Resources res = getResources();
CLICK_FEEDBACK_COLOR = res.getColor(org.solovyev.android.calculator.R.color.magic_flame);
mFeedbackPaint = new Paint();
mFeedbackPaint.setStyle(Style.STROKE);
mFeedbackPaint.setStrokeWidth(2);
getPaint().setColor(res.getColor(org.solovyev.android.calculator.R.color.button_text));
mAnimStart = -1;
if (context instanceof FontSizeAdjuster) {
((FontSizeAdjuster) context).adjustFontSize(this);
}
}
@Override
public void onSizeChanged(int w, int h, int oldW, int oldH) {
measureText();
}
protected void measureText() {
Paint paint = getPaint();
if (getText() != null) {
textPosition = getTextPosition(paint, getText());
}
}
private Point2d getTextPosition(@NotNull Paint paint, @NotNull CharSequence text) {
final Point2d result = new Point2d();
result.setX((getWidth() - paint.measureText(text.toString())) / 2);
float height = getHeight() - paint.ascent() - paint.descent();
result.setY(height / 2);
return result;
}
@Override
protected void onTextChanged(CharSequence text, int start, int before, int after) {
measureText();
}
private void drawMagicFlame(int duration, Canvas canvas) {
int alpha = 255 - 255 * duration / CLICK_FEEDBACK_DURATION;
int color = CLICK_FEEDBACK_COLOR | (alpha << 24);
mFeedbackPaint.setColor(color);
canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, mFeedbackPaint);
}
@Override
public void onDraw(Canvas canvas) {
if (mAnimStart != -1) {
int animDuration = (int) (System.currentTimeMillis() - mAnimStart);
if (animDuration >= CLICK_FEEDBACK_DURATION) {
mAnimStart = -1;
} else {
drawMagicFlame(animDuration, canvas);
postInvalidateDelayed(CLICK_FEEDBACK_INTERVAL);
}
} else if (isPressed()) {
drawMagicFlame(0, canvas);
}
CharSequence text = getText();
if (text != null && textPosition != null) {
canvas.drawText(text, 0, text.length(), textPosition.getX(), textPosition.getY(), getPaint());
}
}
public void animateClickFeedback() {
mAnimStart = System.currentTimeMillis();
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
animateClickFeedback();
break;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
invalidate();
break;
}
return result;
}
}

View File

@@ -0,0 +1,184 @@
package org.solovyev.android.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.util.StringUtils;
import org.solovyev.util.math.Point2d;
/**
* User: serso
* Date: 7/17/11
* Time: 10:25 PM
*/
public class DirectionDragButton extends DragButton {
@Nullable
private String textUp;
@Nullable
private String textDown;
@Nullable
private String textMiddle;
@NotNull
private Point2d textUpPosition;
@NotNull
private Point2d textDownPosition;
@NotNull
private TextPaint upDownTextPaint;
public DirectionDragButton(Context context, @NotNull AttributeSet attrs) {
super(context, attrs, false);
init(context, attrs);
}
private void init(@NotNull Context context, @NotNull AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, org.solovyev.android.calculator.R.styleable.DragButton);
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case org.solovyev.android.calculator.R.styleable.DragButton_textUp:
this.textUp = a.getString(attr);
break;
case org.solovyev.android.calculator.R.styleable.DragButton_textDown:
this.textDown = a.getString(attr);
break;
}
}
// backup text
this.textMiddle = String.valueOf(getText());
super.init(context);
}
@Override
protected void measureText() {
super.measureText();
final Paint basePaint = getPaint();
initUpDownTextPaint(basePaint);
if (textUp != null) {
textUpPosition = getTextPosition(upDownTextPaint, basePaint, textUp, 1);
}
if (textDown != null) {
textDownPosition = getTextPosition(upDownTextPaint, basePaint, textDown, -1);
}
if ( textDownPosition != null && textUpPosition != null ) {
if ( textDownPosition.getX() > textUpPosition.getX() ) {
textDownPosition.setX(textUpPosition.getX());
} else {
textUpPosition.setX(textDownPosition.getX());
}
}
}
private Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, float direction) {
final Point2d result = new Point2d();
float width = paint.measureText(text.toString() + " ");
result.setX(getWidth() - width);
float selfHeight = paint.ascent() + paint.descent();
basePaint.measureText(StringUtils.getNotEmpty(getText(), "|"));
float height = getHeight() - basePaint.ascent() - basePaint.descent();
if (direction < 0) {
result.setY(height / 2 - direction * height / 3 + selfHeight);
} else {
result.setY(height / 2 - direction * height / 3);
}
return result;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
initUpDownTextPaint(null);
if (textUp != null && textUpPosition != null) {
canvas.drawText(textUp, 0, textUp.length(), textUpPosition.getX(), textUpPosition.getY(), upDownTextPaint);
}
if (textDown != null && textDownPosition != null) {
canvas.drawText(textDown, 0, textDown.length(), textDownPosition.getX(), textDownPosition.getY(), upDownTextPaint);
}
}
private void initUpDownTextPaint(@Nullable Paint paint) {
if (paint == null) {
paint = getPaint();
}
upDownTextPaint = new TextPaint(paint);
upDownTextPaint.setAlpha(150);
upDownTextPaint.setTextSize(paint.getTextSize() / 2);
}
private String getStyledUpDownText(@Nullable String text) {
return StringUtils.getNotEmpty(text, "&nbsp;");
}
public void setTextUp(@Nullable String textUp) {
this.textUp = textUp;
}
@Nullable
public String getTextUp() {
return textUp;
}
public void setTextDown(@Nullable String textDown) {
this.textDown = textDown;
}
@Nullable
public String getTextDown() {
return textDown;
}
public void setTextMiddle(@Nullable String textMiddle) {
this.textMiddle = textMiddle;
}
@Nullable
public String getTextMiddle() {
return textMiddle;
}
@Nullable
public String getText(@NotNull DragDirection direction) {
final String result;
if (direction == DragDirection.up) {
result = getTextUp();
} else if ( direction == DragDirection.down ) {
result = getTextDown();
} else {
result = null;
}
return result;
}
}

View File

@@ -0,0 +1,89 @@
package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.util.math.Point2d;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class DragButton extends ColorButton {
@Nullable
private Point2d startPoint = null;
@Nullable
private OnDragListener onDragListener;
private final OnTouchListener onTouchListener = new OnTouchListenerImpl();
public DragButton(Context context, @NotNull AttributeSet attrs) {
this(context, attrs, true);
}
public DragButton(Context context, @NotNull AttributeSet attrs, boolean init) {
super(context, attrs, false);
setOnTouchListener(this.onTouchListener);
if ( init ) {
super.init(context);
}
}
public void setOnDragListener(@Nullable OnDragListener onDragListener) {
this.onDragListener = onDragListener;
}
@Nullable
public OnDragListener getOnDragListener() {
return onDragListener;
}
/**
* OnTouchListener implementation that fires onDrag()
*
* @author serso
*
*/
private final class OnTouchListenerImpl implements OnTouchListener {
@Override
public boolean onTouch(@NotNull View v, @NotNull MotionEvent event) {
// processing on touch event
// in order to avoid possible NPEs
final Point2d localStartPoint = startPoint;
final OnDragListener localOnDragListener = onDragListener;
if (localOnDragListener != null) {
// only if onDrag() listener specified
Log.d(String.valueOf(getId()), "onTouch() for: " + getId() + " . Motion event: " + event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// start tracking: set start point
startPoint = new Point2d(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
// stop tracking
if (localStartPoint != null && localOnDragListener.onDrag(DragButton.this, new DragEvent(localStartPoint, event))) {
if (localOnDragListener.isSuppressOnClickEvent()) {
// prevent on click action
setPressed(false);
}
}
startPoint = null;
break;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,9 @@
package org.solovyev.android.view;
public enum DragDirection {
up,
down,
left,
right;
}

View File

@@ -0,0 +1,38 @@
package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull;
import org.solovyev.util.math.Point2d;
import android.view.MotionEvent;
public class DragEvent {
@NotNull
private final Point2d startPoint;
@NotNull
private final MotionEvent motionEvent;
public DragEvent(@NotNull Point2d startPoint, @NotNull MotionEvent motionEvent) {
this.startPoint = startPoint;
this.motionEvent = motionEvent;
}
/**
* @return motion event started at start point
*/
@NotNull
public MotionEvent getMotionEvent() {
return motionEvent;
}
/**
* @return start point of dragging
*/
@NotNull
public Point2d getStartPoint() {
return startPoint;
}
}

View File

@@ -0,0 +1,14 @@
package org.solovyev.android.view;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
/**
* User: serso
* Date: 9/10/11
* Time: 7:21 PM
*/
public interface FontSizeAdjuster {
void adjustFontSize(@NotNull TextView textView);
}

View File

@@ -0,0 +1,22 @@
package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull;
public interface OnDragListener {
/**
*
* @return 'true': if drag event has taken place (i.e. onDrag() method returned true) then click action will be suppresed
*/
boolean isSuppressOnClickEvent();
/**
* @param dragButton drag button object for which onDrag listener was set
* @param event drag event
*
* @return 'true' if drag event occurred, 'false' otherwise
*/
boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event);
}

View File

@@ -0,0 +1,122 @@
package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.DragButtonCalibrationActivity;
import org.solovyev.common.utils.Interval;
import org.solovyev.util.math.MathUtils;
import org.solovyev.util.math.Point2d;
import android.util.Log;
import android.view.MotionEvent;
import java.util.Map;
public class SimpleOnDragListener implements OnDragListener {
@NotNull
public static final Point2d axis = new Point2d(0, 1);
@NotNull
private DragProcessor dragProcessor;
@NotNull
private DragButtonCalibrationActivity.Preferences preferences;
public SimpleOnDragListener(@NotNull DragButtonCalibrationActivity.Preferences preferences) {
this.preferences = preferences;
}
public SimpleOnDragListener(@NotNull DragProcessor dragProcessor, @NotNull DragButtonCalibrationActivity.Preferences preferences) {
this.dragProcessor = dragProcessor;
this.preferences = preferences;
}
public void setPreferences(@NotNull DragButtonCalibrationActivity.Preferences preferences) {
this.preferences = preferences;
}
@Override
public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) {
boolean result = false;
logDragEvent(dragButton, event);
final Point2d startPoint = event.getStartPoint();
final MotionEvent motionEvent = event.getMotionEvent();
// init end point
final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY());
final float distance = MathUtils.getDistance(startPoint, endPoint);
final double angle = Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint));
final double duration = motionEvent.getEventTime() - motionEvent.getDownTime();
final DragButtonCalibrationActivity.Preference distancePreferences = preferences.getPreferencesMap().get(DragButtonCalibrationActivity.PreferenceType.distance);
final DragButtonCalibrationActivity.Preference anglePreferences = preferences.getPreferencesMap().get(DragButtonCalibrationActivity.PreferenceType.angle);
DragDirection direction = null;
for (Map.Entry<DragDirection, DragButtonCalibrationActivity.DragPreference> directionEntry : distancePreferences.getDirectionPreferences().entrySet()) {
if (isInInterval(directionEntry.getValue().getInterval(), distance)) {
for (Map.Entry<DragDirection, DragButtonCalibrationActivity.DragPreference> angleEntry : anglePreferences.getDirectionPreferences().entrySet()) {
if (isInInterval(angleEntry.getValue().getInterval(), (float)angle)) {
direction = angleEntry.getKey();
break;
}
}
}
if (direction != null) {
break;
}
}
if (direction != null) {
final DragButtonCalibrationActivity.Preference durationPreferences = preferences.getPreferencesMap().get(DragButtonCalibrationActivity.PreferenceType.duration);
final DragButtonCalibrationActivity.DragPreference durationDragPreferences = durationPreferences.getDirectionPreferences().get(direction);
if (isInInterval(durationDragPreferences.getInterval(), (float)duration)) {
result = dragProcessor.processDragEvent(direction, dragButton, startPoint, motionEvent);
}
}
return result;
}
private boolean isInInterval(@NotNull Interval interval, float value) {
return interval.getStart() - MathUtils.MIN_AMOUNT <= value && value <= interval.getEnd() + MathUtils.MIN_AMOUNT;
}
@Override
public boolean isSuppressOnClickEvent() {
return true;
}
private void logDragEvent(@NotNull DragButton dragButton, @NotNull DragEvent event) {
final Point2d startPoint = event.getStartPoint();
final MotionEvent motionEvent = event.getMotionEvent();
final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY());
Log.d(String.valueOf(dragButton.getId()), "Start point: " + startPoint + ", End point: " + endPoint);
Log.d(String.valueOf(dragButton.getId()), "Distance: " + MathUtils.getDistance(startPoint, endPoint));
Log.d(String.valueOf(dragButton.getId()), "Angle: " + Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint)));
Log.d(String.valueOf(dragButton.getId()), "Axis: " + axis + " Vector: " + MathUtils.subtract(endPoint, startPoint));
Log.d(String.valueOf(dragButton.getId()), "Total time: " + (motionEvent.getEventTime() - motionEvent.getDownTime()) + " ms");
}
@NotNull
public DragProcessor getDragProcessor() {
return dragProcessor;
}
public void setDragProcessor(@NotNull DragProcessor dragProcessor) {
this.dragProcessor = dragProcessor;
}
public interface DragProcessor {
boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @NotNull Point2d startPoint2d, @NotNull MotionEvent motionEvent);
}
}