Android-如何旋转多个2D图形对象

Android-如何旋转多个2D图形对象,android,2d,Android,2d,我试图在屏幕上旋转两个圆圈。按下按钮时,一个圆圈顺时针旋转,另一个圆圈逆时针旋转。两者都将旋转90度,然后停止,直到单击下一个按钮。 工作正常,但看起来很糟糕。不是同时旋转,而是先旋转一圈,然后旋转第二圈。 我读过关于动画的书,但是我找到的所有例子都展示了如何旋转整个画布。可能我看的地方不对,有一种方法可以将动画以某种方式指定给对象。 我在下面添加了我的代码。我为它不是一个真正的SSCE而道歉,但当我的自定义SurfaceView是主活动下的一个内部类时,我出现了错误 任何关于如何正确执行此操作

我试图在屏幕上旋转两个圆圈。按下按钮时,一个圆圈顺时针旋转,另一个圆圈逆时针旋转。两者都将旋转90度,然后停止,直到单击下一个按钮。
工作正常,但看起来很糟糕。不是同时旋转,而是先旋转一圈,然后旋转第二圈。
我读过关于动画的书,但是我找到的所有例子都展示了如何旋转整个画布。可能我看的地方不对,有一种方法可以将动画以某种方式指定给对象。
我在下面添加了我的代码。我为它不是一个真正的SSCE而道歉,但当我的自定义SurfaceView是主活动下的一个内部类时,我出现了错误

任何关于如何正确执行此操作的建议或指导都非常感谢。 活动

自定义表面视图

package sscce.android.rotation;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView implements
        SurfaceHolder.Callback {

    private Circle circle1;
    private Circle circle2;
    private DrawThread drawThread;

    public MySurfaceView(Context context) {
        super(context);
        initialize();
    }

    public MySurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize();
    }

    private void initialize() {
        getHolder().addCallback(this);
        drawThread = new DrawThread(getHolder(), this);
        setFocusable(true);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        circle1 = new Circle(getWidth() / 2, getHeight() / 2, 50);
        circle2 = new Circle(getWidth() / 2, getHeight() / 2, 80);
        drawThread.setRunning(true);
        drawThread.start();
    }

    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub
    }

    public void surfaceDestroyed(SurfaceHolder arg0) {
        boolean retry = true;
        drawThread.setRunning(false);
        while (retry) {
            try {
                drawThread.join();
                retry = false;
            } catch (InterruptedException e) {
                // we will try it again and again...
            }
        }
    }

    public void onDraw(Canvas canvas) {
        circle2.onDraw(canvas);
        circle1.onDraw(canvas);
    }

    public void rotate(boolean clockWise) {
        Rotator rotator1 = new Rotator(circle1, clockWise);
        Rotator rotator2 = new Rotator(circle2, !clockWise);
        rotator1.run();
        rotator2.run();
    }

    private class Circle {
        private RectF rectF;
        private int rotationAngle = 0;

        MyPaint bluePaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
                Color.BLUE);
        MyPaint redPaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
                Color.RED);
        MyPaint yellowPaint = new MyPaint(1, Paint.Cap.SQUARE,
                Paint.Style.FILL, Color.YELLOW);
        MyPaint greenPaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
                Color.GREEN);
        MyPaint borderPaint = new MyPaint(3, Paint.Cap.SQUARE,
                Paint.Style.STROKE, Color.WHITE);

        public Circle(int centerX, int centerY, int radius) {
            rectF = new RectF(new Rect(centerX - radius, centerY - radius,
                    centerX + radius, centerY + radius));
        }

        public void rotateClockwise() {
            for (int i = 0; i < 90; i++) {
                rotationAngle++;
                if (rotationAngle == 360) {
                    rotationAngle = 0;
                    return;
                }
                try {
                    Thread.sleep(20, 0);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void rotateCounterClockwise() {
            for (int i = 0; i < 90; i++) {
                rotationAngle--;
                if (rotationAngle == 0) {
                    rotationAngle = 360;
                    return;
                }
                try {
                    Thread.sleep(20, 0);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void onDraw(Canvas canvas) {
            canvas.drawArc(rectF, (0 + rotationAngle) % 360, 90, true,
                    bluePaint);
            canvas.drawArc(rectF, (90 + rotationAngle) % 360, 90, true,
                    redPaint);
            canvas.drawArc(rectF, (180 + rotationAngle) % 360, 90, true,
                    yellowPaint);
            canvas.drawArc(rectF, (270 + rotationAngle) % 360, 90, true,
                    greenPaint);
            canvas.drawArc(rectF, 0, 360, true, borderPaint);
        }

        private class MyPaint extends Paint {
            public MyPaint(int strokeWidth, Paint.Cap cap, Paint.Style style,
                    int color) {
                setStrokeWidth(strokeWidth);
                setAntiAlias(true);
                setStrokeCap(cap);
                setStyle(style);
                setColor(color);
            }
        }
    }

    private class Rotator extends Thread {
        private Circle circle;
        private boolean clockwise;

        public Rotator(Circle circle, boolean clockwise) {
            this.circle = circle;
            this.clockwise = clockwise;
        }

        @Override
        public void run() {
            if (clockwise) {
                circle.rotateClockwise();
            } else {
                circle.rotateCounterClockwise();
            }
        }
    }

    private class DrawThread extends Thread {
        private SurfaceHolder surfaceHolder;
        private MySurfaceView surfaceView;
        private boolean run = false;

        public DrawThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
            this.surfaceHolder = surfaceHolder;
            this.surfaceView = surfaceView;
            run = false;
        }

        public void setRunning(boolean run) {
            Log.d("setRunning@DrawThread", "Run status is " + run);
            this.run = run;
        }

        @Override
        public void run() {
            Canvas canvas = null;
            while (run) {
                try {
                    canvas = surfaceHolder.lockCanvas(null);
                    synchronized (surfaceHolder) {
                        surfaceView.onDraw(canvas);
                    }
                } finally {
                    if (canvas != null) {
                        surfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }
}
包sscce.android.rotation;
导入android.content.Context;
导入android.content.DialogInterface;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.Rect;
导入android.graphics.RectF;
导入android.util.AttributeSet;
导入android.util.Log;
导入android.view.SurfaceHolder;
导入android.view.SurfaceView;
公共类MySurfaceView扩展了SurfaceView实现
SurfaceHolder,回拨{
私人圈子1;
私人圈子2;
专用拉丝;
公共MySurfaceView(上下文){
超级(上下文);
初始化();
}
公共MySurfaceView(上下文、属性集属性){
超级(上下文,attrs);
初始化();
}
公共MySurfaceView(上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
初始化();
}
私有void初始化(){
getHolder().addCallback(此);
drawThread=新的drawThread(getHolder(),this);
设置聚焦(真);
}
已创建的公共空白表面(表面持有人){
circle1=新圆(getWidth()/2,getHeight()/2,50);
circle2=新圆(getWidth()/2,getHeight()/2,80);
drawThread.setRunning(真);
drawThread.start();
}
公共无效表面更改(表面更改arg0、int arg1、int arg2、int arg3){
//TODO自动生成的方法存根
}
公共空间表面已覆盖(表面层arg0){
布尔重试=真;
drawThread.setRunning(假);
while(重试){
试一试{
drawThread.join();
重试=错误;
}捕捉(中断异常e){
//我们会一次又一次的尝试。。。
}
}
}
公共空白onDraw(画布){
圆圈2.onDraw(帆布);
圆圈1.onDraw(帆布);
}
公共空心旋转(布尔值顺时针){
旋转器旋转器1=新旋转器(圆圈1,顺时针);
旋转器旋转器2=新旋转器(圆圈2,!顺时针);
rotator1.run();
rotator2.run();
}
私人阶级圈子{
私有RectF-RectF;
私有整数旋转角度=0;
MyPaint bluePaint=新的MyPaint(1,Paint.Cap.SQUARE,Paint.Style.FILL,
颜色(蓝色);
MyPaint redPaint=新的MyPaint(1,Paint.Cap.SQUARE,Paint.Style.FILL,
颜色(红色);
MyPaint yellowPaint=新MyPaint(1,Paint.Cap.SQUARE,
油漆、样式、填充、颜色、黄色);
MyPaint greenPaint=新MyPaint(1,Paint.Cap.SQUARE,Paint.Style.FILL,
颜色(绿色);
MyPaint borderPaint=新的MyPaint(3,Paint.Cap.SQUARE,
油漆、样式、笔划、颜色、白色);
公共圆(整数中心X、整数中心Y、整数半径){
rectF=新rectF(新Rect(centerX-半径,centerY-半径,
中心X+半径,中心Y+半径);
}
公共空间按顺时针旋转(){
对于(int i=0;i<90;i++){
旋转角度++;
如果(旋转角度==360){
旋转角度=0;
返回;
}
试一试{
睡眠(20,0);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
公共空间旋转逆时针(){
对于(int i=0;i<90;i++){
旋转角--;
如果(旋转角度==0){
旋转角度=360;
返回;
}
试一试{
睡眠(20,0);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
公共空白onDraw(画布){
画布绘制弧(矩形,(0+旋转角度)%360,90,真,
蓝漆);
画布绘制弧(矩形,(90+旋转角度)%360,90,真,
红漆);
画布绘制弧(矩形,(180+旋转角度)%360,90,真,
黄色油漆);
画布绘制弧(矩形,(270+旋转角度)%360,90,真,
绿色油漆);
画布.drawArc(rectF,0,360,true,borderPaint);
}
私有类MyPaint扩展了Paint{
公共MyPaint(int strokeWidth、Paint.Cap、Paint.Style、,
int颜色){
设置行程宽度(行程宽度);
setAntiAlias(真);
调整行程盖(盖);
设置样式(样式);
设置颜色(颜色);
}
}
}
私有类旋转器扩展线程{
私人圈子;
私有布尔顺时针;
公共旋转器(圆形,布尔顺时针){
package sscce.android.rotation;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView implements
        SurfaceHolder.Callback {

    private Circle circle1;
    private Circle circle2;
    private DrawThread drawThread;

    public MySurfaceView(Context context) {
        super(context);
        initialize();
    }

    public MySurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize();
    }

    private void initialize() {
        getHolder().addCallback(this);
        drawThread = new DrawThread(getHolder(), this);
        setFocusable(true);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        circle1 = new Circle(getWidth() / 2, getHeight() / 2, 50);
        circle2 = new Circle(getWidth() / 2, getHeight() / 2, 80);
        drawThread.setRunning(true);
        drawThread.start();
    }

    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub
    }

    public void surfaceDestroyed(SurfaceHolder arg0) {
        boolean retry = true;
        drawThread.setRunning(false);
        while (retry) {
            try {
                drawThread.join();
                retry = false;
            } catch (InterruptedException e) {
                // we will try it again and again...
            }
        }
    }

    public void onDraw(Canvas canvas) {
        circle2.onDraw(canvas);
        circle1.onDraw(canvas);
    }

    public void rotate(boolean clockWise) {
        Rotator rotator1 = new Rotator(circle1, clockWise);
        Rotator rotator2 = new Rotator(circle2, !clockWise);
        rotator1.run();
        rotator2.run();
    }

    private class Circle {
        private RectF rectF;
        private int rotationAngle = 0;

        MyPaint bluePaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
                Color.BLUE);
        MyPaint redPaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
                Color.RED);
        MyPaint yellowPaint = new MyPaint(1, Paint.Cap.SQUARE,
                Paint.Style.FILL, Color.YELLOW);
        MyPaint greenPaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
                Color.GREEN);
        MyPaint borderPaint = new MyPaint(3, Paint.Cap.SQUARE,
                Paint.Style.STROKE, Color.WHITE);

        public Circle(int centerX, int centerY, int radius) {
            rectF = new RectF(new Rect(centerX - radius, centerY - radius,
                    centerX + radius, centerY + radius));
        }

        public void rotateClockwise() {
            for (int i = 0; i < 90; i++) {
                rotationAngle++;
                if (rotationAngle == 360) {
                    rotationAngle = 0;
                    return;
                }
                try {
                    Thread.sleep(20, 0);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void rotateCounterClockwise() {
            for (int i = 0; i < 90; i++) {
                rotationAngle--;
                if (rotationAngle == 0) {
                    rotationAngle = 360;
                    return;
                }
                try {
                    Thread.sleep(20, 0);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void onDraw(Canvas canvas) {
            canvas.drawArc(rectF, (0 + rotationAngle) % 360, 90, true,
                    bluePaint);
            canvas.drawArc(rectF, (90 + rotationAngle) % 360, 90, true,
                    redPaint);
            canvas.drawArc(rectF, (180 + rotationAngle) % 360, 90, true,
                    yellowPaint);
            canvas.drawArc(rectF, (270 + rotationAngle) % 360, 90, true,
                    greenPaint);
            canvas.drawArc(rectF, 0, 360, true, borderPaint);
        }

        private class MyPaint extends Paint {
            public MyPaint(int strokeWidth, Paint.Cap cap, Paint.Style style,
                    int color) {
                setStrokeWidth(strokeWidth);
                setAntiAlias(true);
                setStrokeCap(cap);
                setStyle(style);
                setColor(color);
            }
        }
    }

    private class Rotator extends Thread {
        private Circle circle;
        private boolean clockwise;

        public Rotator(Circle circle, boolean clockwise) {
            this.circle = circle;
            this.clockwise = clockwise;
        }

        @Override
        public void run() {
            if (clockwise) {
                circle.rotateClockwise();
            } else {
                circle.rotateCounterClockwise();
            }
        }
    }

    private class DrawThread extends Thread {
        private SurfaceHolder surfaceHolder;
        private MySurfaceView surfaceView;
        private boolean run = false;

        public DrawThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
            this.surfaceHolder = surfaceHolder;
            this.surfaceView = surfaceView;
            run = false;
        }

        public void setRunning(boolean run) {
            Log.d("setRunning@DrawThread", "Run status is " + run);
            this.run = run;
        }

        @Override
        public void run() {
            Canvas canvas = null;
            while (run) {
                try {
                    canvas = surfaceHolder.lockCanvas(null);
                    synchronized (surfaceHolder) {
                        surfaceView.onDraw(canvas);
                    }
                } finally {
                    if (canvas != null) {
                        surfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <sscce.android.rotation.MySurfaceView
        android:id="@+id/surfaceView1"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

        <Button
            android:id="@+id/btnClockwise"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Clockwise" />

        <Button
            android:id="@+id/btnCounterClockwise"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Counter Clockwise" />
    </LinearLayout>

</LinearLayout>
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(cwRotation);
//draw first circle here
canvas.restore();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(ccwRotation);
//draw second circle here
canvas.restore();