Android的api中没有直接提供气球和信息窗口的控件的实现,所以时常要开发带信息窗口的气球实现类,这时需要自定义一个气球overlay来继com.google.android.maps.Overlay

类,overlay就是可以自定义绘制的覆盖在地图上面的一个层。下面是代码:

 

    1. package morgen.mstx;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.List;  
    5. import android.view.MotionEvent;  
    6. import com.google.android.maps.GeoPoint;  
    7. import com.google.android.maps.MapView;  
    8. import com.google.android.maps.Overlay;  
    9. import com.google.android.maps.Projection;  
    10. import android.graphics.*;  
    11.   
    12. class MyBallonOverlay extends Overlay{  
    13. final static int picWidth=20;  //气球图的宽度  
    14. final static int picHeight=34; //气球图的高度  
    15. final static int arcR=8;//信息窗口的圆角半径  
    16.       
    17. static MyBallonOverlay currentBallon=null;//表示当前选中的气球  
    18.     String msg;      
    19.       
    20. boolean showWindow=false;  
    21.       
    22. //此气球对应的经纬度  
    23.      
    24. public MyBallonOverlay(GeoPoint gp,String msg){  
    25. this.gp=gp;  
    26. this.msg=msg;  
    27.     }  
    28.       
    29. public GeoPoint getGeoPoint(){//获得该气球的经纬度GeoPoint  
    30. return gp;  
    31.     }  
    32.       
    33. @Override  
    34. public boolean onTouchEvent(MotionEvent event, MapView mv) {  
    35. if(currentBallon!=null&¤tBallon!=this){  
    36. //若当前气球不为空且不是自己,什么都不做  
    37. return false;  
    38.         }  
    39. if(event.getAction() == MotionEvent.ACTION_DOWN){  
    40. //若在气球上按下则设置当前气球为自己,且当前状态为在气球上            
    41. int x=(int)event.getX();  
    42. int y=(int)event.getY();  
    43.             Point p= getPoint(mv);  
    44.               
    45. int xb=p.x-picWidth/2;  
    46. int yb=p.y-picHeight;  
    47.               
    48. if(x>=xb&&x<xb+picWidth&&y>=yb&&y<yb+picHeight){  
    49. //若在自己这个气球上按下则设置自己为当前气球                  
    50. this;  
    51. return true;  
    52.             }  
    53.         }  
    54. else if (event.getAction() == MotionEvent.ACTION_MOVE) {  
    55. //移动事件返回当前气球状态 若当前在气球上则返回true 屏蔽其他移动事件  
    56. return currentBallon!=null;  
    57.         }              
    58. else if (event.getAction() == MotionEvent.ACTION_UP) {  
    59. //获取触控笔位置  
    60. int x=(int)event.getX();  
    61. int y=(int)event.getY();  
    62.               
    63. //获取气球在屏幕上的坐标范围  
    64.             Point p= getPoint(mv);               
    65. int xb=p.x-picWidth/2;  
    66. int yb=p.y-picHeight;             
    67.               
    68. if(currentBallon==this&&x>=xb&&x<xb+picWidth&&y>=yb&&y<yb+picHeight){  
    69. //若当前气球为自己且在当前气球上抬起触控则显示当前气球内容      
    70. //显示完内容后清空当前气球  
    71. null;       
    72.                 showWindow=!showWindow;  
    73.                   
    74.                 List<Overlay> overlays = mv.getOverlays();  
    75. this);//删除此气球再添加  
    76. this);//此气球就位于最上面了  
    77. for(Overlay ol:overlays){//清除其他气球的showWindow标记  
    78. if(ol instanceof MyBallonOverlay){  
    79. if(ol!=this){  
    80. false;  
    81.                         }                           
    82.                     }  
    83.                 }  
    84. return true;  
    85.             }  
    86. else if(currentBallon==this){  
    87. //若当前气球为自己但抬起触控不再自己上则清空气球状态并返回true  
    88. null;  
    89. return true;                  
    90.             }              
    91.         }  
    92. return false;  
    93.     }  
    94. @Override  
    95. public void draw(Canvas canvas, MapView mapView, boolean shadow) {              
    96. //将经纬度翻译成屏幕上的XY坐标  
    97.         Point p= getPoint(mapView);                
    98. //在坐标指定位置绘制气球  
    99. 2, p.y-picHeight, null);  
    100.           
    101. if(showWindow){//如果showWindow为true则显示信息窗口  
    102. 160);  
    103.         }  
    104. //调用父类绘制  
    105. super.draw(canvas, mapView, shadow);  
    106.     }  
    107.       
    108. public Point getPoint(MapView mapView){//将经纬度翻译成屏幕上的XY坐标  
    109.         Projection projettion = mapView.getProjection();  
    110. new Point();  
    111.         projettion.toPixels(gp, p);  
    112. return p;  
    113.     }  
    114.       
    115. public void drawWindow(Canvas canvas,Point p,int winWidth){//绘制信息窗口的方法  
    116. int charSize=15;  
    117. int textSize=16;  
    118. int leftRightPadding=2;  
    119.           
    120. //为信息分行  
    121. int lineWidth=winWidth-leftRightPadding*2;//每行的宽度  
    122. int lineCharCount=lineWidth/(charSize);    //每行字符数  
    123. //扫描整个信息字符串分行  
    124. new ArrayList<String>();  
    125. "";  
    126. for(int i=0;i<msg.length();i++){              
    127. char c=msg.charAt(i);  
    128. if(c!='\n'){  
    129.                 currentRow=currentRow+c;  
    130.             }  
    131. else{  
    132. if(currentRow.length()>0){  
    133.                     alRows.add(currentRow);  
    134.                 }                  
    135. "";  
    136.             }  
    137. if(currentRow.length()==lineCharCount){  
    138.                 alRows.add(currentRow);  
    139. "";  
    140.             }  
    141.         }  
    142. if(currentRow.length()>0){  
    143.             alRows.add(currentRow);  
    144.         }  
    145. int lineCount=alRows.size();//总行数  
    146. int winHeight=lineCount*(charSize)+2*arcR;//窗体高度  
    147. //创建paint对象  
    148. new Paint();  
    149. true);  
    150.         paint.setTextSize(textSize);      
    151. //绘制 信息窗体圆角矩形  
    152. 255, 255,251,239);  
    153. int x1=p.x-winWidth/2;  
    154. int y1=p.y-picHeight-winHeight-1;  
    155. int x2=x1+winWidth;  
    156. int y2=y1+winHeight;          
    157. new RectF(x1,y1,x2,y2);          
    158.         canvas.drawRoundRect(r, arcR, arcR, paint);  
    159. 255,198,195,198);  
    160.         paint.setStyle(Paint.Style.STROKE);  
    161. 2);  
    162.         canvas.drawRoundRect(r, arcR, arcR, paint);  
    163.           
    164. //循环绘制每行文字  
    165. 0);  
    166. 255, 10, 10, 10);          
    167. int lineY=y1+arcR+charSize;  
    168. for(String lineStr:alRows){      
    169. System.out.println("lineStr"+lineStr);          
    170. for(int j=0;j<lineStr.length();j++){  
    171. "";  
    172.                 canvas.drawText(colChar, x1+leftRightPadding+j*charSize, lineY, paint);  
    173.             }  
    174.             lineY=lineY+charSize;  
    175.         }  
    176.     }  
    177. }

     

    上述的draw方法完成了在指定的未知绘制气球图片,并根据气球信息窗口的标志值来决定是否调用drawWindow方法来绘制气球对应的信息窗口。这个自定义的气球可以服务于

    大部分涉及到谷歌地图的应用,我有很多应用的涉及到了这些代码,很是实用