вращать циферблат в ограниченных градусах

Все
Я хочу повернуть изображение под определенным углом, как показано ниже. У меня есть код для поворота, но он вращается на 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;
        }
    }

person Girish Bhutiya    schedule 28.12.2012    source источник
comment
Вы решили проблему? Можете ли вы поделиться своим решением? Спасибо.   -  person Jerikc XIONG    schedule 04.06.2014


Ответы (4)


Я не понимаю вашей проблемы. Код ниже поворачивает изображение на 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);
person Simon Schubert    schedule 28.12.2012
comment
да, я знаю, но мой код работает нормально, но он вращает изображение на 360 градусов, но я хочу перемещать изображение в соответствии с поворотом пользователя только в определенной степени. В моем изображении поворот изображения только от 1 до 10. - person Girish Bhutiya; 28.12.2012

Привет, Гриш, есть класс с именем RotateAnimation, использующий этот класс u может легко сделать это

     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);
person Panchal Amit    schedule 29.12.2012

Я хотел бы сначала узнать, что там будет для развертывания? Позволяет ли он манипулировать Eventets? если да, то вы получаете дескриптор события ManipulationStatring и ManipulationDelta для поворота элемента.
Если это не тот случай, когда манипуляция недоступна, вы можете попробовать свойство RenderTransformation с RorateTransform элемента, если вы работаете с WPf.

person Hiren Desai    schedule 07.01.2013

Я смог добиться этого, выполнив несколько следующих изменений в вашем коде.

  1. Заставить пользователя щелкнуть точно по стрелке всегда, чтобы получить начальный угол, под которым расположена стрелка, в вашем случае 90 градусов, иначе вернуть false

  2. Также сохраните угол, под которым пользователь убрал палец, и используйте этот угол в качестве начального значения для своего следующего касания, например, если бы он поместил стрелку на 100 градусов, чтобы его начальное положение касания снова активировало вращение.

  3. Теперь для проверки его ответа возьмите угол, под которым расположены ваши числа от 0 до 9, я предполагаю, что ваши значения принимают 120 градусов от 0 до 9, разделите этот угол на 10, вы можете легко узнать, какой угол представляет какое значение и получить ваш результат

Также очень раздражает прикосновение точно к 90 градусам для начала вращения, поэтому всегда проверяйте значение bw 90+4 и 90-4 для начала, но всегда используйте 90 градусов в качестве начального угла Исходная позиция 0   Перемещено на 60 градусов

person Ujju    schedule 13.04.2015