以有限度数旋转表盘
Posted
技术标签:
【中文标题】以有限度数旋转表盘【英文标题】:rotate dial in limited degrees 【发布时间】:2012-12-13 14:35:36 【问题描述】:所有 我想以特定角度旋转图像,如下图所示。我有旋转代码,但它旋转 360 度,但我只想要特定度数并获得选定的数字,它位于表盘的上方。
下面是我的代码。 我的自定义查看这项工作很好,但性能湖。
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class MyDialView extends View implements OnGestureListener
private static Bitmap bimmap;
private static Paint paint;
private static Rect bounds;
private int totalNicks = 100;
private int currentNick = 0;
private GestureDetector gestureDetector;
private float dragStartDeg = Float.NaN;
float dialerWidth = 0,dialerHeight = 0;
private static Paint createDefaultPaint()
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
return paint;
private float xyToDegrees(float x, float y)
float distanceFromCenter = PointF.length((x - 0.5f), (y - 0.5f));
if (distanceFromCenter < 0.1f
|| distanceFromCenter > 0.5f) // ignore center and out of bounds events
return Float.NaN;
else
return (float) Math.toDegrees(Math.atan2(x - 0.5f, y - 0.5f));
public final float getRotationInDegrees()
return (360.0f / totalNicks) * currentNick;
public final void rotate(int nicks)
currentNick = (currentNick + nicks);
if (currentNick >= totalNicks)
currentNick %= totalNicks;
else if (currentNick < 0)
currentNick = (totalNicks + currentNick);
Log.e("Current nick", String.valueOf(currentNick));
if((currentNick > 80 || currentNick < 20))
invalidate();
public MyDialView(Context context, AttributeSet attrs)
super(context, attrs);
bimmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.out_round);
paint = createDefaultPaint();
gestureDetector = new GestureDetector(getContext(), this);
dialerWidth = bimmap.getWidth() /2.0f;
dialerHeight = bimmap.getHeight() / 2.0f;
bounds = new Rect();
@Override
protected void onDraw(Canvas canvas)
canvas.getClipBounds(bounds);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
//
canvas.translate(bounds.left, bounds.top);
float rotation = getRotationInDegrees();
canvas.rotate(rotation, dialerWidth, dialerHeight);
canvas.drawBitmap(bimmap, 0,0,null);
//canvas.rotate(- rotation, dialerWidth, dialerHeight);
//
canvas.restore();
@Override
public boolean onTouchEvent(MotionEvent event)
if (gestureDetector.onTouchEvent(event))
return true;
else
return super.onTouchEvent(event);
//Gesture detector methods
@Override
public boolean onDown(MotionEvent e)
float x = e.getX() / ((float) getWidth());
float y = e.getY() / ((float) getHeight());
dragStartDeg = xyToDegrees(x, y);
//Log.d("deg = " , ""+dragStartDeg);
if (! Float.isNaN(dragStartDeg))
return true;
else
return false;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
return false;
@Override
public void onLongPress(MotionEvent e)
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY)
if (! Float.isNaN(dragStartDeg))
float currentDeg = xyToDegrees(e2.getX() / getWidth(),
e2.getY() / getHeight());
if (! Float.isNaN(currentDeg))
float degPerNick = 360.0f / totalNicks;
float deltaDeg = dragStartDeg - currentDeg;
final int nicks = (int) (Math.signum(deltaDeg)
* Math.floor(Math.abs(deltaDeg) / degPerNick));
if (nicks != 0)
dragStartDeg = currentDeg;
rotate(nicks);
return true;
else
return false;
@Override
public void onShowPress(MotionEvent e)
@Override
public boolean onSingleTapUp(MotionEvent e)
return false;
我想要根据用户选择 0-9 并且还允许用户旋转到 0-9 而不是更多的旋转。
我还检查了下面的另一个代码。
dialer = (ImageView) findViewById(R.id.imageView_ring);
dialer.setOnTouchListener(new MyOnTouchListener());
dialer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
@Override
public void onGlobalLayout()
// method called more than once, but the values only need to be initialized one time
if (dialerHeight == 0 || dialerWidth == 0)
dialerHeight = dialer.getHeight();
dialerWidth = dialer.getWidth();
// resize
Matrix resize = new Matrix();
resize.postScale((float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getWidth(), (float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getHeight());
imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false);
// translate to the image view's center
float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2;
float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2;
matrix.postTranslate(translateX, translateY);
dialer.setImageBitmap(imageScaled);
dialer.setImageMatrix(matrix);
Log.e("Rotation degree :"+rotationDegrees, String.valueOf(tickNumber));
);
int tickNumber = 0;
private void rotateDialer(float degrees)
//System.out.println("Rotation Done :: "+rotationDone);
// if(!rotationDone)
this.rotationDegrees += degrees;
this.rotationDegrees = this.rotationDegrees % 360;
tickNumber = (int)this.rotationDegrees*100/360;
// It could be negative
if (tickNumber > 0) tickNumber = 100 - tickNumber;
//this.rotationDegrees = Math.abs(rotationDegrees);
this.tickNumber = Math.abs(tickNumber);
if(tickNumber < 20 || tickNumber > 80)
Log.e("Rotation degree :"+rotationDegrees, String.valueOf(tickNumber));
matrix.postRotate(degrees, dialerWidth / 2, dialerHeight / 2);
dialer.setImageMatrix(matrix);
//
/**
* @return The angle of the unit circle with the image view's center
*/
private double getAngle(double xTouch, double yTouch)
double delta_x = xTouch - (dialerWidth) /2;
double delta_y = (dialerHeight) /2 - yTouch;
double radians = Math.atan2(delta_y, delta_x);
double dx = xTouch - dWidth;
double dy = (dHeight - ((dialerHeight) /2)) - yTouch;
double dRadi = Math.atan2(dy, dx);
//Log.e("MY degree", String.valueOf( Math.toDegrees(dRadi)));
//return Math.toDegrees(dRadi);
return Math.toDegrees(radians);
/**
* Simple implementation of an @link OnTouchListener for registering the dialer's touch events.
*/
private class MyOnTouchListener implements OnTouchListener
private double startAngle;
@Override
public boolean onTouch(View v, MotionEvent event)
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
// reset the touched quadrants
/*for (int i = 0; i < quadrantTouched.length; i++)
quadrantTouched[i] = false;
*/
//allowRotating = false;
startAngle = getAngle(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
/*double rotationAngleRadians = Math.atan2(event.getX() - (dialer.getWidth() / 2 ), ( (dialer.getHeight() / 2 ) - event.getY()));
double angle = (int) Math.toDegrees(rotationAngleRadians);
Log.i("gg", "rotaion angle"+angle);*/
double currentAngle = getAngle(event.getX(), event.getY());
//if(currentAngle < 130 || currentAngle < 110)
//Log.e("Start angle :"+startAngle, "Current angle:"+currentAngle);
rotateDialer((float) (startAngle - currentAngle));
startAngle = currentAngle;
//
//Log.e("MOVE start Degree:"+startAngle, "Current Degree :"+currentAngle);
break;
case MotionEvent.ACTION_UP:
//allowRotating = true;
break;
// set the touched quadrant to true
//quadrantTouched[getQuadrant(event.getX() - (dialerWidth / 2), dialerHeight - event.getY() - (dialerHeight / 2))] = true;
//detector.onTouchEvent(event);
return true;
【问题讨论】:
问题解决了吗?你能分享你的解决方案吗?谢谢。 【参考方案1】:我不明白你的问题。下面的代码将图像旋转 48 度。
ImageView dialer = (ImageView) findViewById(R.id.imageView_ring);
int degrees = 48;
Matrix matrix = new Matrix();
matrix.setRotate(degrees);
Bitmap bmpBowRotated = Bitmap.createBitmap(imageOrginal, 0, 0, imageOrginal.getWidth(),imageOrginal.getHeight(), matrix, false);
dialer.setImageBitmap(bmpBowRotated);
【讨论】:
是的,我知道,但我的代码工作正常,但它可以 360 度旋转图像,但我只想根据用户旋转特定度数移动图像。在我的图像中,仅将图像旋转 1 到 10。【参考方案2】:嗨 Girish 有一个名为 RotateAnimation 的类,通过使用这个类你可以轻松做到
look Example like
RotateAnimation r = new RotateAnimation(0f, -90f,200,200); // HERE
r.setStartOffset(1000);
r.setDuration(1000);
r.setFillAfter(true); //HERE
animationSet.addAnimation(r);
【讨论】:
【参考方案3】:我想先了解部署的内容是什么?它允许操纵事件吗?如果是,那么您将处理 ManipulationStatring 和 ManipulationDelta 事件来旋转元素。 如果 Manipulation 不可用的情况并非如此,那么您可以尝试 RenderTransformation 属性和元素的 RorateTransform 是否正在使用 WPf。
【讨论】:
【参考方案4】:我可以通过对您的代码进行以下一些调整来实现这一点
让用户准确点击箭头总是以获得放置箭头的初始角度,在您的情况下为 90 度,否则返回 false
还保存用户移开手指的角度,并将该角度用作下一次触摸的初始值,例如,如果他将箭头置于 100 度,则表示他的初始触摸再次激活旋转的位置
现在检查他的答案,取你的数字 0 到 9 的角度,我猜你的值从 0 到 9 取 120 度,将该角度除以 10,你可以很容易地找到找出什么角度代表什么价值,得到你的结果同样以 90 度准确触摸开始旋转非常烦人,因此请始终检查 bw 90+4 和 90-4 的值以开始旋转,但始终使用 90 作为开始角度
【讨论】:
以上是关于以有限度数旋转表盘的主要内容,如果未能解决你的问题,请参考以下文章
想问一个关于数学旋转的问题,就是在直角坐标系中,某个点绕原点旋转某个度数,应该怎么求出旋转后的度数
在 JavaScript 中旋转人脸 (Node.js 10)