從0開始在Android下開發生活方向盤應用(自繪雷達圖)


    在30天敏捷生活(1):意識你的生活方向盤敏捷個人:你有自己的生活方向盤嗎?中提到生活方向盤是敏捷個人的一個重要工具,之前發不過圖片和Excel格式的方向盤工具。

但現在是移動時代,所以利用空閑時間也編寫了一個Android應用,效果圖如下。這是我在Android下開發的第一個應用,所以本篇將介紹一下如何從0開始在Android開發這個應用。

下載SDK http://developer.android.com/sdk/index.html

我是在windows下開發,所以下載了installer_r18-windows.exe

安裝SDK

運行上一步下載的installer_r18-windows.exe,然后運行SDK Manager下載你需要版本的SDK。2.3的是常用的 ,我手機是2.2的,所以我還下載了一個2.2版本的。

安裝ADT Plugin for Eclipse

https://dl-ssl.google.com/android/eclipse/下載,具體如何使用Eclipse這里就不說了

 

以上把開發環境都准備好了,現在開始新建一個項目,取名AgileMe。Android的基本概念和常識這里也不介紹了,大家網上可以找到很多。在開始之前,簡單介紹一下方向盤應用的需求。

需求

方向盤分為8個維度,每個維度采用10分制打分,每個維度的分值區域是我們生活的飽滿度。程序初始化后,我們可以通過直接在各維度點擊來設定維度的分值,系統自動重繪方向盤圖形。當然,支持數據保存是必要地:)

思路

之前找過有沒有直接的雷達圖控件,發現還沒有發現好用的。因為繪制這個圖也簡單,所以干脆自己操刀從頭開始。這個圖元也少,所以可以不必像工作中那樣關注性能。

  1. 繪制靜態的雷達格線
  2. 繪制文字:這里需要按照角度來設定文字的對齊方式,否則左邊的文字可能就要壓線了
  3. 繪制分值點
  4. 對分值區域進行着色繪制
  5. 為了能夠響應點擊操作,對每一個分值刻度周圍都條件一個小矩形Region,這樣可以響應onTouch事件來判斷打幾分

代碼也不復雜,主要就是根據想繪制的點進行計算,然后再drawText、drawLine等參數中傳遞正確即可。數據上主要是通過設定了很多對應的數組(維度點、刻度值、區域等)。具體代碼如下:

  1 public class LifeWheelRadarGraph extends View {
  2     private int count = 8;
  3     private float angle = 360/count;    
  4     private int point_radius = 5;   //畫點的半徑
  5     private int regionwidth = 40;   //選擇分值小區域寬度
  6     private int valueRulingCount = 5;      //畫等分值線
  7     private int radius;
  8     private int centerX;
  9     private int centerY;
 10     private String[] titles = {"工作","財富","健康","娛樂","家庭","社交","精神","貢獻"};
 11     
 12     private Point[] pts;  //維度端點
 13     private Region[] regions;       //打分點區域
 14     private float[] regionValues;   //打分點分數
 15     private Path valuePath;
 16     private float[] values = {8,6,8,6,6,6,4,5}; //各維度分值
 17     private int maxValue = 10;
 18     private Point[] value_pts;  //維度端點    
 19     private Paint paint;
 20     private Paint valuePaint;
 21     
 22     public float[] getValues() {
 23         return values;
 24     }
 25     
 26     public void setValues(float[] values) {
 27         Assert.assertTrue("傳遞的values數組大小不是"+count, values.length == count);
 28         this.values = values;
 29     }
 30     
 31     public LifeWheelRadarGraph(Context context) {
 32         super(context);
 33         init();    
 34     }
 35     
 36     private void init() {
 37         paint = new Paint();
 38         valuePaint = new Paint();
 39         pts = new Point[count];
 40         value_pts = new Point[count];
 41         valuePath = new Path();
 42         for(int i=0; i<count; i++) {
 43             pts[i] = new Point();
 44             value_pts[i] = new Point();
 45         }
 46         
 47         regionValues = new float[count*valueRulingCount*2];
 48         regions = new Region[count*valueRulingCount*2];   
 49         for(int i=0; i<regions.length; i++) {
 50             regions[i] = new Region();
 51         }
 52 
 53     }
 54 
 55     public LifeWheelRadarGraph(Context context, AttributeSet attrs) {   
 56         super(context, attrs);
 57         init();
 58     }   
 59   
 60     public LifeWheelRadarGraph(Context context, AttributeSet attrs, int defStyle) {   
 61         super(context, attrs, defStyle);   
 62         init();
 63     }  
 64 
 65     @Override
 66     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 67         radius = Math.min(h, w)/2 - 40;
 68         centerX = w/2;
 69         centerY = h/2;
 70         
 71         for(int i=0; i<count; i++)
 72         {
 73             pts[i].x = centerX+(int)(radius*Math.cos(Math.toRadians(angle*i)));
 74             pts[i].y = centerY-(int)(radius*Math.sin(Math.toRadians(angle*i)));
 75             
 76             for(int j=1; j<=valueRulingCount*2; j++)
 77             {
 78                 int x = centerX + (pts[i].x-centerX)/(valueRulingCount*2)*j;
 79                 int y = centerY + (pts[i].y-centerY)/(valueRulingCount*2)*j;
 80                 regions[i*valueRulingCount*2+j-1].set(x-regionwidth/2, y-regionwidth/2, x+regionwidth/2, y+regionwidth/2);   
 81                 regionValues[i*valueRulingCount*2+j-1] = j;
 82             }            
 83         }                
 84         postInvalidate();
 85         super.onSizeChanged(w, h, oldw, oldh);
 86     }
 87     
 88     @Override
 89     public boolean onTouchEvent(MotionEvent event) {
 90         int action = event.getAction();
 91         float x = event.getX();
 92         float y = event.getY();
 93         
 94         switch(event.getAction()) 
 95         {
 96         case MotionEvent.ACTION_DOWN:
 97             for(int i = 0; i<regions.length; i++)
 98             {
 99                 if (regions[i].contains((int)x, (int)y))
100                 {
101                     values[(int)(i/(valueRulingCount*2))] = regionValues[i];
102                     break;
103                 }
104             }
105             invalidate();
106             break;
107         case MotionEvent.ACTION_MOVE:
108 
109             break;
110         case MotionEvent.ACTION_UP:
111 
112             break;
113         }
114         return super.onTouchEvent(event); 
115     }
116    
117    
118     @Override
119     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
120         // TODO Auto-generated method stub
121         return super.onKeyLongPress(keyCode, event);
122     }
123     
124     @Override
125     protected void onDraw(Canvas canvas) {
126         /* 設置畫布的顏色 */
127         canvas.drawColor(Color.WHITE);
128 
129         paint.setAntiAlias(true);
130         //畫邊框線
131         paint.setColor(Color.GRAY);      
132         paint.setStyle(Paint.Style.FILL_AND_STROKE);
133         for(int i=0; i<count; i++)
134         {
135             int end = i+1 == count? 0:i+1;
136 
137             for(int j=1; j<=valueRulingCount; j++)
138             {
139                 canvas.drawLine(centerX+(pts[i].x-centerX)/5*j, centerY+(pts[i].y-centerY)/5*j, 
140                         centerX+(pts[end].x-centerX)/5*j, centerY+(pts[end].y-centerY)/5*j,  paint);
141             }
142             
143             canvas.drawLine(centerX, centerY, pts[i].x, pts[i].y, paint);            
144         }
145         
146         //寫文字
147         paint.setTextSize(20);
148         paint.setColor(Color.BLACK);
149         FontMetrics fontMetrics = paint.getFontMetrics();
150         float fontHegiht = -fontMetrics.ascent;
151         for(int i=0; i<count; i++)
152         {
153             if ((angle * i == 90.0) || (angle * i == 270.0))
154                 paint.setTextAlign(Align.CENTER);
155             else if ((angle * i < 90) || (angle * i > 270))
156                 paint.setTextAlign(Align.LEFT);
157             else if ((angle * i > 90) || (angle * i < 270))
158                 paint.setTextAlign(Align.RIGHT);
159             
160             if (angle * i == 270.0)
161                 canvas.drawText(titles[i], pts[i].x, pts[i].y+fontHegiht, paint);
162             else
163                 canvas.drawText(titles[i], pts[i].x, pts[i].y, paint);
164         }        
165 
166         //畫方向盤分值區域
167         for(int i=0; i<count; i++)
168         {
169             value_pts[i].x = (int)(centerX + (pts[i].x-centerX) * values[i]/maxValue);
170             value_pts[i].y = (int)(centerY + (pts[i].y-centerY) * values[i]/maxValue);
171         }
172         
173         valuePath.reset();
174         valuePaint.setAntiAlias(true);
175         valuePaint.setColor(Color.BLUE);  
176         valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);        
177         for(int i = 0; i< pts.length; i++)
178         {
179             //給valuePath賦值
180             if (i == 0)
181                 valuePath.moveTo(value_pts[i].x, value_pts[i].y);
182             else
183                 valuePath.lineTo(value_pts[i].x, value_pts[i].y);
184             //畫取分圓圈
185             canvas.drawCircle(value_pts[i].x, value_pts[i].y, point_radius, paint);
186         }
187         valuePaint.setAlpha(150);     
188         canvas.drawPath(valuePath, valuePaint);
189     }
190 }

保存方向盤分值

最后我們還要保存分值,這里使用了簡單的SharedPreferences

public class AgileMeActivity extends Activity {
     private LifeWheelRadarGraph graph = null;
     private SharedPreferences settings;
     
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        graph = (LifeWheelRadarGraph)findViewById(R.id.lifeWheelRadarGraph1);
        // Restore preferences   
        settings = getSharedPreferences("LifeWheel", 0);
        String valueStr = settings.getString("values", "8,6,8,6,6,6,4,5");
        try {
            String[] valuesStr = valueStr.split(",");
            float[] values = new float[valuesStr.length];
            for(int i = 0; i <valuesStr.length; i++)
                values[i] = Float.parseFloat(valuesStr[i]);
            
            graph.setValues(values);
        } catch (Exception e) {
        }
    }
    
    protected void onStop(){   
        super.onStop();    
        SharedPreferences.Editor editor = settings.edit();
        float[] values = graph.getValues();
        String valueStr= "";
        for(int i=0; i <values.length; i++)
            valueStr =  valueStr + "," + values[i];
        valueStr = valueStr.substring(1);
        editor.putString("values", valueStr);   
        editor.commit();            
    }
}

 

 應用下載

#敏捷個人# 生活方向盤#工具#Android應用提供下載 通過@微盤 分享文件"AgileMe.apk" http://t.cn/zWvgPgO

 

推薦:你可能需要的在線電子書

我的微博:http://weibo.com/openexpressapp

敏捷個人sina圍裙:http://q.t.sina.com.cn/135484    

歡迎轉載,轉載請注明:轉載自敏捷個人網站


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM