rotate dial in limited degrees

六眼飞鱼酱① 提交于 2019-12-06 23:56:10

问题


All
I want rotate image in particular angle as like below image. I have code for rotation but it rotate 360 degree but I want it only for particular degrees and get the selected number which is upper side of dial.


below is my code. My custom View this work fine but lake of perfomance.

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;
    }

}


I want 0-9 according to user selection & also allow user rotation to 0-9 not more rotation.

I have also check another code this is below.

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:


I do not understand your problem. The code below rotate the image 48 degrees.

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);



回答2:


Hi Girish there is a class Named RotateAnimation by using this class u can easily do it

     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:


I would like to first know what will be there for deployment? Does it allow manipulation Evenets? if yes then you get handle ManipulationStatring and ManipulationDelta Event to rotate the element.
If the same is not the case where Manipulation is not available then you can try RenderTransformation property with RorateTransform of the element is you are working with WPf.




回答4:


I was able to achieve this by doing few of the following tweaks on your code

  1. Making user click exactly on the arrow always to get the initial angle at which the arrow is placed, in your case 90 degree, else return false

  2. Also save the angle at which the user removed his finger and use that angle as the initial value for his next touch ,like if he placed arrow at 100 deg make that his initial touch position to activate rotation again

  3. Now for checking his answer take the angle at which your numbers 0 to 9 are placed ,im guessing your values take 120 deg from 0 to 9, divide that angle by 10, you can easily find out what angle represents what value and get your result

Also touching exactly at 90deg to begin rotation is very irritating, so always check for value which is bw 90+4 and 90-4 to begin, but always use the 90 as your start angle



来源:https://stackoverflow.com/questions/14067633/rotate-dial-in-limited-degrees

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!