(转载)http://blog.csdn.net/lxw1980/article/details/6031978

在Android中,几乎所有能看到的元素都继承自View类。

View类是Android中最基础的类之一。其余的Button,RadioButton,CheckBox等等,都是通过继承View的方法来实现的。

通过继承View,可以很方便地定制出有个性的控件出来。

实现自定义View的最主要的是重写onDraw(Canvas canvas)函数,当每次系统重绘界面的时候,都会调用这个函数,并传下一个Canvas,在这个函数内,应该将这个View所要显示的内容都draw到这个Canvas上,界面显示出来的内容几乎都由这个Canvas来决定。Canvas的具体画法可以很容易查得到,应该说Android内所有函数的命名都是很直观,一目了然的,自己看一下函数名都大概可以明白这个函数是有什么用的。SDK也是查询Android API的最好的工具,多使用些肯定有好处的。

View的显示出来的大小最主要的决定者是Parent Layout,View可以自定义自己的宽高的最小值,但这并不能保证能到达这种最小值,如果Parent本身的大小已经比这个值小了。

View的重绘——系统不会经常去调用View的OnDraw函数,为了能够在View上实现动画效果,比如说游戏(但好像很多游戏是用更高效的SurfaceView为实现的),在主线程是执行完程序的逻辑后,应该要调用postInvalidate(),通知系统去调用onDraw函数去重绘界面,才能将动画的效果给显示出来。

下面的代码是我自己写的一个模拟两个球不断碰撞的View,主要由一个线程来不断更新View内两个球的位置,在发现两个球和墙壁发生碰撞后,改变球的逻辑参数,更新完后,调用postInvalidate(),重绘界面。来实现效果

package robot.com;import java.util.ArrayList;import java.util.Random;import android.app.Activity;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Style;import android.os.Bundle;import android.view.View;public class Main extends Activity {    /** Called when the activity is first created. */    TheScreen mScreen;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);                //mScreen是自定义的View        mScreen = new TheScreen(this);        setContentView(mScreen);    }        //为避免在程序退出后线程仍在进行,造成不必要的系统资源浪费,在Activity退出是时候,主动将线程停止    @Override    public void onDestroy()    {        mScreen.stopDrawing();        super.onDestroy();    }}/** * 自定义的View类,为两个球的碰撞模拟 * @author windy * */class TheScreen extends View{        private static final String TAG = "Draw";    //界面主线程的控制变量    private boolean drawing = false;    //储存当前已有的球的信息    private ArrayList<Circle> circles;    private Paint mPaint;    //两个球的运动范围    public static final int WIDTH = 300;    public static final int HEIGHT = 400;    public static final double PI = 3.14159265;    Paint mPaint2 = new Paint();    public TheScreen(Context context)    {        super(context);        circles = new ArrayList<Circle>();        //加入了两个球        circles.add(new Circle());        circles.add(new Circle(20, 30, 10));        mPaint = new Paint();        mPaint.setColor(Color.YELLOW);        mPaint.setAntiAlias(true);        mPaint2.setStyle(Style.STROKE);        mPaint2.setColor(Color.RED);        mPaint2.setAntiAlias(true);        //启动界面线程,开始自动更新界面        drawing = true;        new Thread(mRunnable).start();    }        private Runnable mRunnable = new Runnable() {        //界面的主线程        @Override        public void run() {            while( drawing )            {                try {                    //更新球的位置信息                    update();                    //通知系统更新界面,相当于调用了onDraw函数                    postInvalidate();                    //界面更新的频率,这里是每30ms更新一次界面                    Thread.sleep(30);                    //Log.e(TAG, "drawing");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    };        public void stopDrawing()    {        drawing = false;    }            @Override    public void onDraw(Canvas canvas)    {        //在canvas上绘上边框        canvas.drawRect(0, 0, WIDTH, HEIGHT, mPaint2);        //在canvas上绘上球        for( Circle circle : circles)        {            canvas.drawCircle(circle.x, circle.y, circle.radius, mPaint);        }    }        //界面的逻辑函数,主要检查球是否发生碰撞,以及更新球的位置    private void update()    {        if( circles.size()>1)        {            for( int i1=0; i1<circles.size()-1; i1++)            {                //当两个球发生碰撞,交换两个球的角度值                for( int i2=i1+1; i2<circles.size(); i2++)                    if( checkBumb(circles.get(i1),circles.get(i2)))                    {                        circles.get(i1).changeDerection(circles.get(i2));                    }            }                    }        //更新球的位置        for( Circle circle: circles)            circle.updateLocate();    }        private boolean checkBumb(Circle c1, Circle c2)    {        return (c1.x-c2.x)*(c1.x-c2.x) + (c1.y-c2.y)*(c1.y-c2.y) <= (c1.radius+c2.radius)*(c1.radius+c2.radius);                }        /**     * 自定义的View的内部类,存储每一个球的信息     * @author windy     *     */    class Circle    {        float x=50;        float y=70;        double angle= (new Random().nextFloat())*2*PI;;        int speed=4;        int radius=10;                public Circle() {        }                public Circle( float x, float y, int r )        {            this.x = x;            this.y = y;            radius = r;        }                //利用三角函数计算出球的新位置值,当与边界发生碰撞时,改变球的角度        public void updateLocate()        {            x = x+ (float)(speed *Math.cos(angle));            //Log.v(TAG, Math.cos(angle)+"");            y = y+ (float)(speed *Math.sin(angle));            //Log.v(TAG, Math.cos(angle)+"");            if( (x+radius)>=WIDTH )            {                if( angle >=0 && angle <= (PI/2))                    angle = PI - angle;                if( angle > 1.5 * PI && angle <= 2*PI)                    angle = 3 * PI - angle;                            }            if( x-radius <=0 )            {                if( angle >= PI && angle <= 1.5*PI )                    angle = 3*PI - angle;                if( angle >= PI/2 && angle < PI)                    angle = PI - angle;            }            if( y-radius<=0 || y+radius>=HEIGHT)                angle = 2*PI - angle;                    }        //两球交换角度        public void changeDerection(Circle other)        {            double temp = this.angle;            this.angle = other.angle;            other.angle = temp;        }    }}

这段代码已经写有注释了,具体下次再介绍了。。。应该不难的看懂的吧。

PS:这是第一次写Blog,感觉写得很不好,没有条理,下次再改进了!!! 睡觉lol

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. Android(安卓)Intent实现页面跳转的方法示例
  4. 【Android开发学习02】Android应用程序的调试
  5. Android与JNI(一)
  6. Android输入子系统之InputReader读取键盘消息过程分析
  7. Android应用程序与SurfaceFlinger服务之间的共享UI元数据(SharedC
  8. Android最佳实践之高效的应用导航
  9. android 焦点问题

随机推荐

  1. Bug!Redis 6.0.8紧急发布,请尽快升级!
  2. 超赞!墙裂推荐一个 MySQL 自动化运维工具!
  3. 介绍一个可以离线查询 IP 来源和 ISP 信
  4. 史上首例!阿里程序员写的这三行代码,被国家
  5. 时间同步、双因子安全验证及自动化安装实
  6. 2021年全新永久有效Phpstorm激活码
  7. tp6 多文件上传
  8. 网络发展遭遇瓶颈期,如何推动SDN/NFV解决
  9. Ansible Playbook详解
  10. 超实用案例:美团终端主动监控平台的建设