在自定义视图中为Drawable设置动画

时间:2011-10-08 13:28:38

标签: android animation view drawable

我正在尝试在自定义视图中为ShapeDrawable设置动画。但我不确定完成此任务的最佳方法是什么。

我是否应该尝试在路径上绘制一个棋子并致电invalidate()直到它到达目的地广场?或者是否有一些更好的方法可能使用AsyncTask或Handler?

这是我的代码,我省略了很多方法和变量,以使其可读。

public class CheckerBoard extends View {

    public enum State implements Parcelable {
        EMPTY(0), WHITE(1), BLACK(2);
    }

        private final State[][] boardStates = new State[SIZE][SIZE];

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(bgColor);
        for (int y = 0; y < SIZE; y++) {
            for (int x = 0; x < SIZE; x++) {
                if ((y % 2 == 0 && x % 2 != 0) || (y % 2 != 0 && x % 2 == 0)) {
                    drawRect(x, y, canvas);
                    drawPawn(x, y, canvas);
                }
            }
        }
    }

    private void drawRect(int x, int y, Canvas c) {
    }

    private void drawPawn(int x, int y, Canvas c) {
    }

    private void init() {
        setupBoard();
        pawnLinePaint.setStyle(Paint.Style.STROKE);
        wPawnDrawable.getPaint().setColor(wColor);
        wPawnDrawable.getPaint().setShadowLayer(tileSize + 2, 4, 4, Color.GRAY);
        bPawnDrawable.getPaint().setColor(bColor);
        bPawnDrawable.getPaint().setShadowLayer(tileSize + 2, 4, 4, Color.GRAY);
        playerState = startState;
    }

    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int x = (int) (event.getX() / tileSize);
                int y = (int) (event.getY() / tileSize);
                if (selection[0] >= 0) { // A tile is already selected
                    if (isValidMove(selection[0], selection[1], x, y)) {
                        makeMove(x, y);
                        clearSelection();
                        switchPlayer();
                        invalidate();
                    }

                } else { // New selection
                    if (isValidSelection(x, y)) {
                        selection[0] = x;
                        selection[1] = y;
                        invalidate();
                    }
                }

                return true;
            default:
                return super.onTouchEvent(event);
        }
    }

    private void makeMove(int x, int y) {
        // Move the pawn to the new square
        boardStates[y][x] = boardStates[selection[1]][selection[0]];
        // Old square is now empty
        boardStates[selection[1]][selection[0]] = State.EMPTY;  
    }

    private void switchPlayer() {
        playerState = playerState == State.WHITE ? State.BLACK : State.WHITE;
    }

    public CheckerBoard(Context context) {
        super(context);
        init();
    }

    public CheckerBoard(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CheckerBoard(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }


    private class Pawn extends ShapeDrawable {
        public Pawn() {
            super(new OvalShape());
        }

        public void drawWithCircles(Canvas canvas, float x, float y){
            super.draw(canvas);
            canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding,
                    pawnLinePaint);
            canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding * 6,
                    pawnLinePaint);
            canvas.drawCircle(x * tileSize + pawnDiameter, y * tileSize + pawnDiameter, pawnDiameter - pawnPadding * 8,
                    pawnLinePaint);
        }
    }

}

感谢您的帮助。

疫病

1 个答案:

答案 0 :(得分:1)

您应该为您的应用程序创建两个线程。一个线程是UI线程,它只在当前状态下绘制电路板。另一个线程是游戏引擎或动画线程,它可以移动棋盘上的项目。

第一个线程以您想要的帧速率运行,第二个线程运行速度要快得多。这样你实际上不必自己处理动画,因为UI线程只是按照当前的方式绘制板。在您的引擎线程中,您可以更新游戏,棋盘,棋子,线程的每个循环的状态。

以这种方式做事有几个好处。首先,如果Engine线程在某种计算中陷入困境,那么游戏的帧速率将不会下降。其次,它允许您以一种使调试更容易的方式将绘图从游戏中抽象出来。

以进度条为例。假设您尝试使用进度条创建文件上传器,但只有一个线程。因此,您启动进度条,然后开始上传文件。如果上传过程被阻止,那么您必须等待文件完成上传才能更新进度条,实际上使进度条无效。但是如果你用两个线程做到这一点,那么你可以设置它,这样一个线程只是根据一些常见变量更新进度条图形。另一个步骤负责执行操作并更新进度变量。

查看以下链接以获取更多信息:

http://obviam.net/index.php/the-android-game-loop/

http://www.rbgrn.net/content/54-getting-started-android-game-development

http://www.helloandroid.com/tutorials/using-threads-and-progressdialog