Android——自定义View类(一 )

来源:互联网 发布:nginx module 编写 编辑:程序博客网 时间:2024/06/10 17:36
 

Android——自定义View类(一 )

分类: Android 4846人阅读 评论(4) 收藏 举报
androidfloatradiobuttonrandombuttonthread

在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(),重绘界面。来实现效果

[java] view plaincopy
  1. package com.androidclub.elfman.homework3;  
  2. import java.util.ArrayList;  
  3. import java.util.Random;  
  4. import android.app.Activity;  
  5. import android.content.Context;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Color;  
  8. import android.graphics.Paint;  
  9. import android.graphics.Paint.Style;  
  10. import android.os.Bundle;  
  11. import android.view.View;  
  12. public class Main extends Activity {  
  13.     TheScreen mScreen;  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         //mScreen是自定义的View  
  18.         mScreen = new TheScreen(this);  
  19.         setContentView(mScreen);  
  20.     }  
  21.       
  22.     //为避免在程序退出后线程仍在进行,造成不必要的系统资源浪费,在Activity退出是时候,主动将线程停止  
  23.     @Override  
  24.     public void onDestroy()  
  25.     {  
  26.         mScreen.stopDrawing();  
  27.         super.onDestroy();  
  28.     }  
  29. }  
  30. /** 
  31.  * 自定义的View类,为两个球的碰撞模拟 
  32.  * @author windy 
  33.  * 
  34.  */  
  35. class TheScreen extends View  
  36. {  
  37.       
  38.     private static final String TAG = "Draw";  
  39.     //界面主线程的控制变量  
  40.     private boolean drawing = false;  
  41.     //储存当前已有的球的信息  
  42.     private ArrayList<Circle> circles;  
  43.     private Paint mPaint;  
  44.     //两个球的运动范围  
  45.     public static final int WIDTH = 300;  
  46.     public static final int HEIGHT = 400;  
  47.     public static final double PI = 3.14159265;  
  48.     Paint mPaint2 = new Paint();  
  49.     public TheScreen(Context context)  
  50.     {  
  51.         super(context);  
  52.         circles = new ArrayList<Circle>();  
  53.         //加入了两个球  
  54.         circles.add(new Circle());  
  55.         circles.add(new Circle(203010));  
  56.         mPaint = new Paint();  
  57.         mPaint.setColor(Color.YELLOW);  
  58.         mPaint.setAntiAlias(true);  
  59.         mPaint2.setStyle(Style.STROKE);  
  60.         mPaint2.setColor(Color.RED);  
  61.         mPaint2.setAntiAlias(true);  
  62.         //启动界面线程,开始自动更新界面  
  63.         drawing = true;  
  64.         new Thread(mRunnable).start();  
  65.     }  
  66.       
  67.     private Runnable mRunnable = new Runnable() {  
  68.         //界面的主线程  
  69.         @Override  
  70.         public void run() {  
  71.             while( drawing )  
  72.             {  
  73.                 try {  
  74.                     //更新球的位置信息  
  75.                     update();  
  76.                     //通知系统更新界面,相当于调用了onDraw函数  
  77.                     postInvalidate();  
  78.                     //界面更新的频率,这里是每30ms更新一次界面  
  79.                     Thread.sleep(30);  
  80.                     //Log.e(TAG, "drawing");  
  81.                 } catch (InterruptedException e) {  
  82.                     e.printStackTrace();  
  83.                 }  
  84.             }  
  85.         }  
  86.     };  
  87.       
  88.     public void stopDrawing()  
  89.     {  
  90.         drawing = false;  
  91.     }  
  92.       
  93.       
  94.     @Override  
  95.     public void onDraw(Canvas canvas)  
  96.     {  
  97.         //在canvas上绘上边框  
  98.         canvas.drawRect(00, WIDTH, HEIGHT, mPaint2);  
  99.         //在canvas上绘上球  
  100.         for( Circle circle : circles)  
  101.         {  
  102.             canvas.drawCircle(circle.x, circle.y, circle.radius, mPaint);  
  103.         }  
  104.     }  
  105.       
  106.     //界面的逻辑函数,主要检查球是否发生碰撞,以及更新球的位置  
  107.     private void update()  
  108.     {  
  109.         if( circles.size()>1)  
  110.         {  
  111.             forint i1=0; i1<circles.size()-1; i1++)  
  112.             {  
  113.                 //当两个球发生碰撞,交换两个球的角度值  
  114.                 forint i2=i1+1; i2<circles.size(); i2++)  
  115.                     if( checkBumb(circles.get(i1),circles.get(i2)))  
  116.                     {  
  117.                         circles.get(i1).changeDerection(circles.get(i2));  
  118.                     }  
  119.             }  
  120.               
  121.         }  
  122.         //更新球的位置  
  123.         for( Circle circle: circles)  
  124.             circle.updateLocate();  
  125.     }  
  126.       
  127.     private boolean checkBumb(Circle c1, Circle c2)  
  128.     {  
  129.         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);           
  130.     }  
  131.       
  132.     /** 
  133.      * 自定义的View的内部类,存储每一个球的信息 
  134.      * @author windy 
  135.      * 
  136.      */  
  137.     class Circle  
  138.     {  
  139.         float x=50;  
  140.         float y=70;  
  141.         double angle= (new Random().nextFloat())*2*PI;;  
  142.         int speed=4;  
  143.         int radius=10;  
  144.           
  145.         public Circle() {  
  146.         }  
  147.           
  148.         public Circle( float x, float y, int r )  
  149.         {  
  150.             this.x = x;  
  151.             this.y = y;  
  152.             radius = r;  
  153.         }  
  154.           
  155.         //利用三角函数计算出球的新位置值,当与边界发生碰撞时,改变球的角度  
  156.         public void updateLocate()  
  157.         {  
  158.             x = x+ (float)(speed *Math.cos(angle));  
  159.             //Log.v(TAG, Math.cos(angle)+"");  
  160.             y = y+ (float)(speed *Math.sin(angle));  
  161.             //Log.v(TAG, Math.cos(angle)+"");  
  162.             if( (x+radius)>=WIDTH )  
  163.             {  
  164.                 if( angle >=0 && angle <= (PI/2))  
  165.                     angle = PI - angle;  
  166.                 if( angle > 1.5 * PI && angle <= 2*PI)  
  167.                     angle = 3 * PI - angle;               
  168.             }  
  169.             if( x-radius <=0 )  
  170.             {  
  171.                 if( angle >= PI && angle <= 1.5*PI )  
  172.                     angle = 3*PI - angle;  
  173.                 if( angle >= PI/2 && angle < PI)  
  174.                     angle = PI - angle;  
  175.             }  
  176.             if( y-radius<=0 || y+radius>=HEIGHT)  
  177.                 angle = 2*PI - angle;  
  178.               
  179.         }  
  180.         //两球交换角度  
  181.         public void changeDerection(Circle other)  
  182.         {  
  183.             double temp = this.angle;  
  184.             this.angle = other.angle;  
  185.             other.angle = temp;  
  186.         }  
  187.     }  
  188. }  
 

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

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

0 0