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

时间:2011-12-08 15:51:11

标签: android 2d

我正在尝试在屏幕上旋转2个圆圈。按下按钮,一个圆圈顺时针旋转,其他圆圈逆时针旋转。两者都会旋转90度然后停止,直到下一个按钮点击 它的工作,但它看起来非常糟糕。而不是同时旋转,第一个圆圈旋转,然后旋转第二个圆圈 我读到了关于动画但我发现的所有例子都展示了如何旋转整个画布。可能我不是在寻找合适的地方,并且有办法以某种方式将动画分配给对象 我在下面添加了我的代码。我很抱歉它不是真正的SSCCE,但是当我的自定义SurfaceView是主要活动下的内部类时,我遇到了错误。

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

package sscce.android.rotation;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;

public class SscceRotationActivity extends Activity implements OnClickListener {

    private MySurfaceView mySurfaceView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.btnClockwise).setOnClickListener(this);
        findViewById(R.id.btnCounterClockwise).setOnClickListener(this);
        mySurfaceView = (MySurfaceView) (findViewById(R.id.surfaceView1));
    }

    public void onClick(View arg0) {

        switch (arg0.getId()) {
        case R.id.btnClockwise:
            mySurfaceView.rotate(true);
            break;
        case R.id.btnCounterClockwise:
            mySurfaceView.rotate(false);
            break;
        }
    }
}

自定义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);
                    }
                }
            }
        }
    }
}

布局

<?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>

2 个答案:

答案 0 :(得分:2)

我想建议使用矩阵的不同旋转方法。代码看起来像

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

这种方法的优点是非常简单,不需要额外的类和API,它与您使用OpenGL的方法类似。

答案 1 :(得分:1)

如果用 rotator1 / 2.start()

替换 rotator1 / 2.run()行,您将获得更多成功