我
只想以特定角度旋转图像,如下图所示。我有旋转代码,但它旋转 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;
}
}