Android学习 画图 (一) 球

1.画一个球,在遇到四周的墙壁会反弹。

package com.example.draw2d;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.view.View;

public class Draw2D extends Activity {
        
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(new BallView(this));
    }



    /**
     * 定义一个View,用来显示球
     * @author siqi
     *
     */
    public class BallView extends View {
        private Ball ball = new Ball();
        private BallThread ballThread = new BallThread(this);
        
        public BallView(Context context) {
            super(context);
            
            /**
             * 启动线程
             */
            ballThread.start();
        }

        public Ball getBall() {
            return ball;
        }
        
        /**
         * onDraw在每次View被刷新的时候执行。
         */
        @Override
        protected void onDraw(Canvas canvas) {
            ball.draw(canvas);
            super.onDraw(canvas);
        }
    }
    

    /**
     * 定义一个线程来刷新View,处理球的运动
     * @author siqi
     *
     */
    public class BallThread extends Thread {
        /**
         * 当bAlive是false的时候退出线程
         */
        private boolean bAlive = true;
        
        private BallView ballView;
        
        /**
         * 球运动的速度
         */
        private int speed = 3;
        /**
         * x方向的运动速度,正表示向右,负表示向左
         */
        private int xDir = speed;
        /**
         * y方向的运动速度,正表示向下,负表示向上
         */
        private int yDir = speed;
        
        /**
         * 我们需要在线程里面刷新view,和获取view中的那个球对象
         * 所以我们需要传入view
         * @param view
         */
        public BallThread(BallView view) {
            this.ballView = view;
        }
        
        /**
         * 线程运行
         */
        @Override
        public void run() {
            /**
             * 我们想要获取view的宽度和高度,但是在activity
             * setContentView(new BallView(this)); 后,获取的宽度和长度
             * 有可能为0,设置view需要大约200ms的时间。所以在这里,我们用一个
             * 循环,直到view准备好。
             */
            while(ballView.getWidth()<1) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            /**
             * 获取view的长度和宽度(不包括标题栏(有标题的那个)和通知栏(有信号图标的那个))
             */
            int screenWidth = ballView.getWidth();
            int screenHeight = ballView.getHeight();
            /**
             * 获取球的宽度
             */
            int ballW = ballView.getBall().getRect().width();
            /**
             * 球下一个运动位置
             */
            int xNext, yNext;
            /**
             * 设置循环,我们需要有一个手段,能够结束线程,所以我们定义了bAlive
             * 当bAlive为false的时候,退出。
             */
            while(bAlive) {
                try {
                    /**
                     * 刷新一次view的显示后,都等待30ms。当图像每秒刷新30次的时候,
                     * 大部分人的眼睛就已经认为图像是连续的了,1000ms/30 = 33.33ms,在这里
                     * 省略成30。 
                     */
                    Thread.sleep(30);
                    /**
                     * 获取球当前位置,范围
                     */
                    Rect ballRect = ballView.getBall().getRect();
                    /**
                     * 按照X,Y方向的速度,下一个位置
                     */
                    xNext = ballRect.left + xDir;
                    yNext = ballRect.top + yDir;
                    
                    /**
                     * 表示撞到了右边/左边的墙壁
                     */
                    if(xNext>=screenWidth-ballW || xNext<0) {
                        xDir = -1 * xDir;    //转向
                        xNext = ballRect.left + xDir;
                    }
                    
                    /**
                     * 表示撞到了下边/上边的墙壁
                     */
                    if(yNext>=screenHeight-ballW || yNext<0) {
                        yDir = -1 * yDir;
                        yNext = ballRect.top + yDir;
                    }
                    /**
                     * 更新球的位置
                     */
                    ballView.ball.move(xNext, yNext);
                    
                    /**
                     * 通知View,重画View
                     */
                    ballView.post(new Runnable() {
                        @Override
                        public void run() {
                            ballView.invalidate();
                        }
                    });
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        
        /**
         * 调用destory,我们把bAlive设置成false,这样
         * run()里面的循环就不会再继续。线程在执行完成后退出。
         */
        @Override
        public void destroy() {
            bAlive = false;
        }
    }

    /**
     * 定义球的类
     * @author siqi
     *
     */
    public class Ball {
        
        private ShapeDrawable mBall;
        public Ball() {
            this.mBall = createBall(10);
        }

        public Ball(int r) {
            this.mBall = createBall(r);
        }
        
        public Rect getRect() {
            if (this.mBall == null) {
                return null;
            } else {
                return this.mBall.getBounds();
            }
        }
        
        /**
         * 创建一个球的绘图对象(Drawable),如果不用着色器的话,画出来的
         * 球很难看,没有立体感。
         * @param r 球的半径
         * @return 返回球的绘图对象
         */
        private ShapeDrawable createBall(float r) {
            //直径
            float diameter = 2 * r;
            //用椭圆模板创建一个绘图对象
            ShapeDrawable drawable = new ShapeDrawable(new OvalShape());
            //设置球的颜色和深颜色,在这里,我们设置的是绿色RGB(128,255,30)
            //RGB值可以通过windows画图程序->颜色(菜单)->编辑颜色->自定义颜色得到
            int red = 128;
            int green = 225;
            int blue = 30;
            int color = 0xff000000 | red << 16 | green << 8 | blue;
            //RGB各个颜色的值越小,颜色越黑(深)
            int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4;
            
            //得到绘图对象的画笔
            Paint paint = drawable.getPaint();
            //创建着色器
            RadialGradient gradient = new RadialGradient(r, r,
                    r, color, darkColor, Shader.TileMode.CLAMP);
            //设置着色器
            paint.setShader(gradient);
            //设置绘图对象区域
            //注意,在android中(0,0,150,1)表示一条x轴范围为0-149,y=0的直线;并不像有些语言
            //的实现,有些语言中(0,0,150,1)表示一个矩形,X范围:0-150,Y范围0-1。
            drawable.setBounds(0, 0, (int)diameter, (int)diameter);
            
            return drawable;
        }
        
        /**
         * 将球移动到指定位置
         * @param x 球的最左边X坐标,不是中心X坐标
         * @param y 球的最上边Y坐标,不是中心Y坐标
         */
        public void move(int x, int y) {
            Rect rectOld = this.mBall.getBounds();
            Rect rectNew = new Rect(rectOld);
            
            int relativeX = x - rectOld.left;
            int relativeY = y - rectOld.top;
            
            rectNew.left = rectNew.left + relativeX;
            rectNew.right = rectNew.right + relativeX;
            rectNew.top = rectNew.top + relativeY;
            rectNew.bottom = rectNew.bottom + relativeY;
            
            this.mBall.setBounds(rectNew);
        }
        
        /**
         * 在给定的画布上画球
         * @param canvas 画布
         */
        public void draw(Canvas canvas) {
            this.mBall.draw(canvas);
        }
    }
    
}



运行效果:




源代码下载: http://dom4j-android.googlecode.com/files/Draw2D.zip

参考的资料:

1.API Demo: com.example.android.apis.animation.AnimationCloning.java

2.http://developer.android.com/guide/topics/graphics/overview.html

你可能感兴趣的:(android,android,画图,运动,球)