Android實現(xiàn)動態(tài)曲線繪制
我們在安卓開發(fā)中,有時會用到統(tǒng)計圖表的功能,而曲線繪制是其中比較典型的一種,一般是利用給定的坐標點集和安卓自帶的繪圖模塊進行繪制,直接得到的是一張完整的靜態(tài)的曲線圖。但有時,我們需要動態(tài)繪制一些曲線圖,就像我們打開電腦的任務(wù)管理器,里面有一個CPU使用記錄的動態(tài)變化的帶網(wǎng)格的曲線圖,對于這一類的曲線繪制,安卓SDK自帶的繪圖模塊貌似就不那么好用了。
在這里,我就利用Handler+timer機制和第三方開發(fā)包achartengine實現(xiàn)動態(tài)繪制安卓手機充放電曲線的應(yīng)用。
1、下載第三方開發(fā)包achartengine,也就是jar包,可以在網(wǎng)上找到下載源,我下載的是achartengine-1.1.0.jar;
2、在創(chuàng)建的應(yīng)用工程文件中引入該jar包,以Eclipse為例方法是:在包資源管理器目錄中右鍵單擊已創(chuàng)建的項目名稱——>構(gòu)建路徑——>配置構(gòu)建路徑——>Java構(gòu)建路徑——>庫——>外部JAR,然后找到achartengine包的存放路徑,找到achartengine-1.1.0.jar文件,點擊打開即完成了該包的引用,這時會在項目目錄下出現(xiàn)一個名為引用的庫文件,里面就是我們剛才引入的jar包。
3、接下來就可以按正常步驟開發(fā)該應(yīng)用了,需要注意的是:需要在主類中引入jar中繪圖需要的庫文件,如下:
import org.achartengine.ChartFactory; ? ?import org.achartengine.GraphicalView; ? ?import org.achartengine.chart.PointStyle; ? ?import org.achartengine.model.XYMultipleSeriesDataset; ? ?import org.achartengine.model.XYSeries; ? ?import org.achartengine.renderer.XYMultipleSeriesRenderer; ? ?import org.achartengine.renderer.XYSeriesRenderer;
同時需要在AndroidManifest.xml文件中加上語句:
<application ? ?android:icon="@drawable/ic_launcher" ? ?android:label="@string/app_name" > <activity android:name="org.achartengine.GraphicalActivity" />
4、接下來需要定義一些繪圖的變量和樣式:
private XYSeries series; ? ? ? ? ? ? ? private XYMultipleSeriesDataset mDataset; ? ? ? ? ? ? ? private GraphicalView chart; ? ? ? ? ? ? ? private XYMultipleSeriesRenderer renderer; ? ? ? ? ? ? ? private Context context, context1; ? ? ? ? ? ? ? private int addX = -1, addY; ? ? ? ? ? ? ? int[] xv = new int[720];// X軸數(shù)組元素個數(shù) ? ? ? ? ? ? ? int[] yv = new int[720];// Y軸數(shù)組元素個數(shù) ? ? ? ?? ? ? ? ? ? ? ? ? ? context = getApplicationContext(); ? ? ? ? ? ? ? // 這里獲得main界面上的布局,下面會把圖表畫在這個布局里面 ? ? ? ? ? ? ? LinearLayout layout = (LinearLayout) findViewById(R.id.linearLayout1); ? ? ? ? ? ? ? // 這個類用來放置曲線上的所有點,是一個點的集合,根據(jù)這些點畫出曲線 ? ? ? ? ? ? ? series = new XYSeries(title); ? ? ? ? ? ? ? // 創(chuàng)建一個數(shù)據(jù)集的實例,這個數(shù)據(jù)集將被用來創(chuàng)建圖表 ? ? ? ? ? ? ? mDataset = new XYMultipleSeriesDataset(); ? ? ? ? ? ? ? // 將點集添加到這個數(shù)據(jù)集中 ? ? ? ? ? ? ? mDataset.addSeries(series); ? ? ? ? ? ? ? // 以下都是曲線的樣式和屬性等等的設(shè)置,renderer相當(dāng)于一個用來給圖表做渲染的句柄 ? ? ? ? ? ? ? int color = Color.GREEN; ? ? ? ? ? ? ? PointStyle style = PointStyle.CIRCLE; ? ? ? ? ? ? ? renderer = buildRenderer(color, style, true); ? ? ? ? ? ? ? ? // 設(shè)置好圖表的樣式(橫軸時間分鐘值,縱軸電壓毫伏值) ? ? ? ? ? ? ? setChartSettings(renderer, "X", "Y", 0, 240, 3400, 4400, Color.WHITE,Color.WHITE); ? ? ? ? ? ? ? // 生成圖表 ? ? ? ? ? ? ? chart = ChartFactory.getLineChartView(context, mDataset, renderer); ? ? ? ? ? ? ? // 將圖表添加到布局中去 ? ? ? ? ? ? ? layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); ? ? ? ? ? ? ? ? ?protected XYMultipleSeriesRenderer buildRenderer(int color,PointStyle style, boolean fill)// 配置繪圖屬性 ? ? ? ? ? ? ? { ? ? ? ? ? ? ? XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(); ? ? ? ? ? ? ? // 設(shè)置圖表中曲線本身的樣式,包括顏色、點的大小以及線的粗細等 ? ? ? ? ? ? ? XYSeriesRenderer r = new XYSeriesRenderer(); ? ? ? ? ? ? ? r.setColor(color); ? ? ? ? ? ? ? r.setPointStyle(style); ? ? ? ? ? ? ? r.setFillPoints(fill); ? ? ? ? ? ? ? r.setLineWidth((float) 1);// 線粗尺寸 ? ? ? ? ? ? ? renderer.addSeriesRenderer(r); ? ? ? ? ? ? ? return renderer; } ? protected void setChartSettings(XYMultipleSeriesRenderer renderer, String xTitle, String yTitle, double xMin, double xMax, double yMin, double yMax, int axesColor, int labelsColor) { // 有關(guān)對圖表的渲染可參看api文檔 renderer.setChartTitle(title); renderer.setXTitle(xTitle); renderer.setYTitle(yTitle); renderer.setXAxisMin(xMin); renderer.setXAxisMax(xMax); renderer.setYAxisMin(yMin); renderer.setYAxisMax(yMax); renderer.setAxesColor(axesColor); renderer.setLabelsColor(labelsColor); renderer.setShowGrid(true); renderer.setGridColor(Color.GREEN);// 曲線顏色 renderer.setXLabels(20); renderer.setYLabels(10); renderer.setChartTitle("時間/電壓變化曲線圖");// 圖表名稱 renderer.setXTitle("時間(min)");// 橫坐標名稱 renderer.setYTitle("電壓(mv)");// 縱坐標名稱 renderer.setYLabelsAlign(Align.RIGHT); renderer.setPointSize((float) 1.5);// 設(shè)置點的大小 renderer.setShowLegend(false); renderer.setPanEnabled(true, false);// 設(shè)置滑動,這邊是橫向可以滑動,縱向不可滑動 renderer.setZoomEnabled(true, false);// 設(shè)置縮放,橫向可以,縱向不可以 // renderer.setZoomLimits(new double[] { 0, 720, 3400, 4400 });//設(shè)置縮放的范圍 // renderer.setPanLimits(new double[] { -0.5, 720, 3400, 4400 // });//設(shè)置拉動的范圍 }
5、動態(tài)繪制的實現(xiàn):動態(tài)繪制主要需要實現(xiàn)兩方面的內(nèi)容,一是更新繪圖的方法、二是動態(tài)繪圖時間任務(wù)的定義。
1)更新繪圖方法:
private void updateChart()// 更新繪圖方法</strong> { // 設(shè)置好下一個需要增加的節(jié)點 addX = (int) (addX + 1); addY = BatteryV; // 移除數(shù)據(jù)集中舊的點集 mDataset.removeSeries(series); // 判斷當(dāng)前點集中到底有多少點,因為屏幕總共只能容納240個,所以當(dāng)點數(shù)超過240時,長度永遠是240 int length = series.getItemCount(); if (length > 720) { length = 720; } // 將舊的點集中x和y的數(shù)值取出來放入backup中,并且將x的值加1,造成曲線向右平移的效果 for (int i = 0; i < length; i++) { xv[i] = (int) series.getX(i); yv[i] = (int) series.getY(i); } // 點集先清空,為了做成新的點集而準備 series.clear(); // 將新產(chǎn)生的點首先加入到點集中,然后在循環(huán)體中將坐標變換后的一系列點都重新加入到點集中 // 這里可以試驗一下把順序顛倒過來是什么效果,即先運行循環(huán)體,再添加新產(chǎn)生的點 series.add(addX, addY); for (int k = 0; k < length; k++) { series.add(xv[k], yv[k]); } // 在數(shù)據(jù)集中添加新的點集 mDataset.addSeries(series); // 視圖更新,沒有這一步,曲線不會呈現(xiàn)動態(tài) // 如果在非UI主線程中,需要調(diào)用postInvalidate(),具體參考api chart.invalidate(); }
2)時間任務(wù)定義:
handler = new Handler() { @Override public void handleMessage(Message msg) { // 刷新圖表 updateChart();// 電壓變化曲線刷新 updateChart1();// 電量變化曲線刷新 super.handleMessage(msg); } }; task = new TimerTask()// 刷新繪圖計時任務(wù)配置 { @Override public void run() { Message message = new Message(); message.what = 1; handler.sendMessage(message); } }; timer.schedule(task, 0, 60000);// 以一分鐘為時間間隔運行?
再發(fā)一下完整的代碼:
主類:
package com.cfzz.vcd; ? import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import org.achartengine.ChartFactory; import org.achartengine.GraphicalView; import org.achartengine.chart.PointStyle; import org.achartengine.model.XYMultipleSeriesDataset; import org.achartengine.model.XYSeries; import org.achartengine.renderer.XYMultipleSeriesRenderer; import org.achartengine.renderer.XYSeriesRenderer; ? //import com.cfzz.vqcd.R; ? //import com.cfzz.wy.R; ? import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Paint.Align; import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PowerManager; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import android.view.View.OnClickListener; ? public class VoltageChangeDraw extends Activity { ? ?? ?// protected static final Activity Activity = null; ?? ?private PowerManager.WakeLock wl; ?? ?private Timer timer = new Timer(); ?? ?private long mExitTime = 0; ?? ?private TimerTask task, task1; ?? ?private Handler handler; ?? ?private String title = "Signal Strength"; ?? ?private XYSeries series, series1; ?? ?private XYMultipleSeriesDataset mDataset, mDataset1; ?? ?private GraphicalView chart, chart1; ?? ?private XYMultipleSeriesRenderer renderer, renderer1; ?? ?private Context context, context1; ?? ?private int addX = -1, addY; ?? ?private int addX1 = -1, addY1; ?? ?private Button button; ?? ?int[] xv = new int[720];// X軸數(shù)組元素個數(shù) ?? ?int[] yv = new int[720];// Y軸數(shù)組元素個數(shù) ?? ?int[] xv1 = new int[720];// X軸數(shù)組元素個數(shù) ?? ?int[] yv1 = new int[720];// Y軸數(shù)組元素個數(shù) ?? ?public TextView TV; ?? ?// ScreenShot screenShot = new ScreenShot(); ?? ?private int BatteryN; // 目前電量 ?? ?private int BatteryV; // 電池電壓 ?? ?// private double BatteryT; //電池溫度 ?? ?private String BatteryStatus; // 電池狀態(tài) ?? ?private String BatteryTemp; // 電池使用情況 ? ?? ?/** Called when the activity is first created. */ ?? ?@Override ?? ?public void onCreate(Bundle savedInstanceState) { ?? ??? ?super.onCreate(savedInstanceState); ?? ??? ?getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, ?? ??? ??? ??? ?WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); ?? ??? ?setContentView(R.layout.main); ?? ??? ?this.button = (Button) this.findViewById(R.id.my_button);// 截圖按鍵定義 ?? ??? ?// 截圖按鍵監(jiān)聽 ?? ??? ?this.button.setOnClickListener(new OnClickListener() { ?? ??? ??? ?public void onClick(View v) { ?? ??? ??? ??? ?SimpleDateFormat sdf = new SimpleDateFormat( ?? ??? ??? ??? ??? ??? ?"yyyy-MM-dd_HH-mm-ss", Locale.US);// 日期格式名定義 ? ?? ??? ??? ??? ?String fname = "/sdcard/" + sdf.format(new Date()) + ".png";// 存儲路徑及文件名定義 ? ?? ??? ??? ??? ?View view = v.getRootView(); ? ?? ??? ??? ??? ?view.setDrawingCacheEnabled(true); ? ?? ??? ??? ??? ?view.buildDrawingCache(); ? ?? ??? ??? ??? ?Bitmap bitmap = view.getDrawingCache(); ? ?? ??? ??? ??? ?if (bitmap != null) { ?? ??? ??? ??? ??? ?System.out.println("bitmap got!"); ? ?? ??? ??? ??? ??? ?try { ? ?? ??? ??? ??? ??? ??? ?FileOutputStream out = new FileOutputStream(fname); ? ?? ??? ??? ??? ??? ??? ?bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);// 圖片格式及質(zhì)量輸出 ? ?? ??? ??? ??? ??? ??? ?System.out.println("file" + fname + "output done."); ? ?? ??? ??? ??? ??? ?} catch (Exception e) { ? ?? ??? ??? ??? ??? ??? ?e.printStackTrace(); ? ?? ??? ??? ??? ??? ?} ? ?? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ?System.out.println("bitmap is NULL!"); ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?}); ?? ??? ?// MyTag可以隨便寫,可以寫應(yīng)用名稱等 ?? ??? ?PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); ?? ??? ?// 換成PowerManager.SCREEN_DIM_WAKE_LOCK會變暗) ?? ??? ?PowerManager.WakeLock wl = pm.newWakeLock( ?? ??? ??? ??? ?PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyTest"); ?? ??? ?wl.acquire();// 開啟屏幕常亮 ? ?? ??? ?TV = (TextView) findViewById(R.id.TV);// 電池信息打印控件定義 ? ?? ??? ?// 注冊一個系統(tǒng) BroadcastReceiver,作為訪問電池計量之用,這個不能直接在AndroidManifest.xml中注冊 ?? ??? ?registerReceiver(mBatInfoReceiver, new IntentFilter( ?? ??? ??? ??? ?Intent.ACTION_BATTERY_CHANGED)); ? ?? ??? ?context = getApplicationContext(); ?? ??? ?context1 = getApplicationContext();// 圖2 ?? ??? ?// 這里獲得main界面上的布局,下面會把圖表畫在這個布局里面 ?? ??? ?LinearLayout layout = (LinearLayout) findViewById(R.id.linearLayout1); ? ?? ??? ?// 這個類用來放置曲線上的所有點,是一個點的集合,根據(jù)這些點畫出曲線 ?? ??? ?series = new XYSeries(title); ?? ??? ?series1 = new XYSeries(title);// 圖2 ?? ??? ?// 創(chuàng)建一個數(shù)據(jù)集的實例,這個數(shù)據(jù)集將被用來創(chuàng)建圖表 ?? ??? ?mDataset = new XYMultipleSeriesDataset(); ?? ??? ?mDataset1 = new XYMultipleSeriesDataset(); ?? ??? ?// 將點集添加到這個數(shù)據(jù)集中 ?? ??? ?mDataset.addSeries(series); ?? ??? ?mDataset1.addSeries(series1);// 圖2 ?? ??? ?// 以下都是曲線的樣式和屬性等等的設(shè)置,renderer相當(dāng)于一個用來給圖表做渲染的句柄 ?? ??? ?int color = Color.GREEN; ?? ??? ?int color1 = Color.RED; ?? ??? ?PointStyle style = PointStyle.CIRCLE; ?? ??? ?renderer = buildRenderer(color, style, true); ?? ??? ?renderer1 = buildRenderer(color1, style, true);// 圖2 ? ?? ??? ?// 設(shè)置好圖表的樣式(橫軸時間分鐘值,縱軸電壓毫伏值) ?? ??? ?setChartSettings(renderer, "X", "Y", 0, 240, 3400, 4400, Color.WHITE, ?? ??? ??? ??? ?Color.WHITE); ?? ??? ?setChart1Settings(renderer1, "X", "Y", 0, 240, 0, 100, Color.WHITE, ?? ??? ??? ??? ?Color.WHITE); ?? ??? ?// 生成圖表 ?? ??? ?chart = ChartFactory.getLineChartView(context, mDataset, renderer); ?? ??? ?chart1 = ChartFactory.getLineChartView(context1, mDataset1, renderer1);// 圖2 ?? ??? ?</span><span style="font-size:12px;">// 將圖表添加到布局中去,此處的縱向尺寸設(shè)置存在一些問題,當(dāng)兩張圖都設(shè)置<span style="font-family: Arial, Helvetica, sans-serif;">WRAP_CONTENT</span>時,在實際界面上只顯示第一張圖,在這里可根據(jù)手 ? ? ? ? ? ? ? ? ?// </span><span style="font-family: Arial, Helvetica, sans-serif;">機屏幕的大小設(shè)置具</span><span style="font-family: Arial, Helvetica, sans-serif;">體的數(shù)值(像素點個數(shù)),可以保證兩張圖都能顯示在屏幕上 </span><span style="font-size:14px;">?? ??? ?layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT)); ?? ??? ?layout.addView(chart1, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT)); ?? ??? ?// layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT, ?? ??? ?// 400));//525 ?? ??? ?// layout.addView(chart1, new LayoutParams(LayoutParams.FILL_PARENT, ?? ??? ?// 400));//圖2 525 ?? ??? ?// 這里的Handler實例將配合下面的Timer實例,完成定時更新圖表的功能 ?? ??? ?handler = new Handler() { ?? ??? ??? ?@Override ?? ??? ??? ?public void handleMessage(Message msg) { ?? ??? ??? ??? ?// 刷新圖表 ?? ??? ??? ??? ?updateChart();// 電壓變化曲線刷新 ?? ??? ??? ??? ?updateChart1();// 電量變化曲線刷新 ?? ??? ??? ??? ?super.handleMessage(msg); ? ?? ??? ??? ?} ?? ??? ?}; ? ?? ??? ?task = new TimerTask()// 刷新繪圖計時任務(wù)配置 ?? ??? ?{ ?? ??? ??? ?@Override ?? ??? ??? ?public void run() { ?? ??? ??? ??? ?Message message = new Message(); ?? ??? ??? ??? ?message.what = 1; ?? ??? ??? ??? ?handler.sendMessage(message); ?? ??? ??? ?} ?? ??? ?}; ?? ??? ?timer.schedule(task, 0, 60000);// 以一分鐘為時間間隔運行 ? ?? ??? ?task1 = new TimerTask()// 保存繪圖計時任務(wù)配置 ?? ??? ?{ ?? ??? ??? ?@Override ?? ??? ??? ?public void run() { ?? ??? ??? ??? ?if (BatteryStatus == "充滿電" ?? ??? ??? ??? ??? ??? ?|| (BatteryStatus == "放電狀態(tài)" && BatteryN == 1))// 充/放電完成條件設(shè)定 ?? ??? ??? ??? ?{ ?? ??? ??? ??? ??? ?button.callOnClick();// 保存曲線圖按鍵觸發(fā) ?? ??? ??? ??? ??? ?timer.cancel(); // 停止計時功能 ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?}; ?? ??? ?timer.schedule(task1, 0, 10000);// 以十秒鐘為時間間隔運行 ?? ?} ? ?? ?@Override ?? ?public void onDestroy() // 結(jié)束程序聲明 ?? ?{ ?? ??? ?button.callOnClick();// 保存曲線圖按鍵觸發(fā) ?? ??? ?// 當(dāng)結(jié)束程序時關(guān)掉Timer ?? ??? ?timer.cancel(); ?? ??? ?// wl.release(); ?? ??? ?// wl = null; ?? ??? ?super.onDestroy(); ?? ?} ? ?? ?protected XYMultipleSeriesRenderer buildRenderer(int color, ?? ??? ??? ?PointStyle style, boolean fill)// 配置繪圖屬性 ?? ?{ ?? ??? ?XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(); ? ?? ??? ?// 設(shè)置圖表中曲線本身的樣式,包括顏色、點的大小以及線的粗細等 ?? ??? ?XYSeriesRenderer r = new XYSeriesRenderer(); ?? ??? ?r.setColor(color); ?? ??? ?r.setPointStyle(style); ?? ??? ?r.setFillPoints(fill); ?? ??? ?r.setLineWidth((float) 1);// 線粗尺寸 ?? ??? ?renderer.addSeriesRenderer(r); ? ?? ??? ?return renderer; ?? ?} ? ?? ?// 圖2 ?? ?protected XYMultipleSeriesRenderer buildRenderer1(int color1, ?? ??? ??? ?PointStyle style, boolean fill)// 配置繪圖屬性 ?? ?{ ?? ??? ?XYMultipleSeriesRenderer renderer1 = new XYMultipleSeriesRenderer();// 圖2 ?? ??? ?// 設(shè)置圖表中曲線本身的樣式,包括顏色、點的大小以及線的粗細等 ?? ??? ?XYSeriesRenderer r = new XYSeriesRenderer(); ?? ??? ?r.setColor(color1); ?? ??? ?r.setPointStyle(style); ?? ??? ?r.setFillPoints(fill); ?? ??? ?r.setLineWidth((float) 1);// 線粗尺寸 ?? ??? ?renderer1.addSeriesRenderer(r); ? ?? ??? ?return renderer1; ?? ?} ? ?? ?protected void setChartSettings(XYMultipleSeriesRenderer renderer, ?? ??? ??? ?String xTitle, String yTitle, double xMin, double xMax, ?? ??? ??? ?double yMin, double yMax, int axesColor, int labelsColor) { ?? ??? ?// 有關(guān)對圖表的渲染可參看api文檔 ? ?? ??? ?renderer.setChartTitle(title); ?? ??? ?renderer.setXTitle(xTitle); ?? ??? ?renderer.setYTitle(yTitle); ?? ??? ?renderer.setXAxisMin(xMin); ?? ??? ?renderer.setXAxisMax(xMax); ?? ??? ?renderer.setYAxisMin(yMin); ?? ??? ?renderer.setYAxisMax(yMax); ?? ??? ?renderer.setAxesColor(axesColor); ?? ??? ?renderer.setLabelsColor(labelsColor); ?? ??? ?renderer.setShowGrid(true); ?? ??? ?renderer.setGridColor(Color.GREEN);// 曲線顏色 ?? ??? ?renderer.setXLabels(20); ?? ??? ?renderer.setYLabels(10); ?? ??? ?renderer.setChartTitle("時間/電壓變化曲線圖");// 圖表名稱 ?? ??? ?renderer.setXTitle("時間(min)");// 橫坐標名稱 ?? ??? ?renderer.setYTitle("電壓(mv)");// 縱坐標名稱 ?? ??? ?renderer.setYLabelsAlign(Align.RIGHT); ?? ??? ?renderer.setPointSize((float) 1.5);// 設(shè)置點的大小 ?? ??? ?renderer.setShowLegend(false); ?? ??? ?renderer.setPanEnabled(true, false);// 設(shè)置滑動,這邊是橫向可以滑動,縱向不可滑動 ?? ??? ?renderer.setZoomEnabled(true, false);// 設(shè)置縮放,橫向可以,縱向不可以 ?? ??? ?// renderer.setZoomLimits(new double[] { 0, 720, 3400, 4400 });//設(shè)置縮放的范圍 ?? ??? ?// renderer.setPanLimits(new double[] { -0.5, 720, 3400, 4400 ?? ??? ?// });//設(shè)置拉動的范圍 ?? ?} ? ?? ?// 圖2 ?? ?protected void setChart1Settings(XYMultipleSeriesRenderer renderer1, ?? ??? ??? ?String xTitle, String yTitle, double xMin, double xMax, ?? ??? ??? ?double yMin, double yMax, int axesColor, int labelsColor) { ?? ??? ?// 有關(guān)對圖表的渲染可參看api文檔 ? ?? ??? ?renderer1.setChartTitle(title); ?? ??? ?renderer1.setXTitle(xTitle); ?? ??? ?renderer1.setYTitle(yTitle); ?? ??? ?renderer1.setXAxisMin(xMin); ?? ??? ?renderer1.setXAxisMax(xMax); ?? ??? ?renderer1.setYAxisMin(yMin); ?? ??? ?renderer1.setYAxisMax(yMax); ?? ??? ?renderer1.setAxesColor(axesColor); ?? ??? ?renderer1.setLabelsColor(labelsColor); ?? ??? ?renderer1.setShowGrid(true); ?? ??? ?renderer1.setGridColor(Color.GREEN);// 曲線顏色 ?? ??? ?renderer1.setXLabels(20); ?? ??? ?renderer1.setYLabels(10); ?? ??? ?renderer1.setChartTitle("時間/電量變化曲線圖");// 圖表名稱 ?? ??? ?renderer1.setXTitle("時間(min)");// 橫坐標名稱 ?? ??? ?renderer1.setYTitle("電量(%)");// 縱坐標名稱 ?? ??? ?renderer1.setYLabelsAlign(Align.RIGHT); ?? ??? ?renderer1.setPointSize((float) 1.5);// 設(shè)置點的大小 ?? ??? ?renderer1.setShowLegend(false); ?? ??? ?renderer1.setPanEnabled(true, false);// 設(shè)置滑動,這邊是橫向可以滑動,縱向不可滑動 ?? ??? ?renderer1.setZoomEnabled(true, false);// 設(shè)置縮放,橫向可以,縱向不可以 ?? ??? ?// renderer1.setZoomLimits(new double[] { 0, 720, 0, 100 });//設(shè)置縮放的范圍 ?? ??? ?// renderer1.setPanLimits(new double[] { -0.5, 720, 0, 100 });//設(shè)置拉動的范圍 ?? ?} ? ?? ?private void updateChart()// 更新繪圖方法 ?? ?{ ? ?? ??? ?// 設(shè)置好下一個需要增加的節(jié)點 ?? ??? ?addX = (int) (addX + 1); ?? ??? ?addY = BatteryV; ?? ??? ?// 移除數(shù)據(jù)集中舊的點集 ?? ??? ?mDataset.removeSeries(series); ?? ??? ?// 判斷當(dāng)前點集中到底有多少點,因為屏幕總共只能容納240個,所以當(dāng)點數(shù)超過240時,長度永遠是240 ?? ??? ?int length = series.getItemCount(); ?? ??? ?if (length > 720) { ?? ??? ??? ?length = 720; ?? ??? ?} ?? ??? ?// 將舊的點集中x和y的數(shù)值取出來放入backup中,并且將x的值加1,造成曲線向右平移的效果 ?? ??? ?for (int i = 0; i < length; i++) { ?? ??? ??? ?xv[i] = (int) series.getX(i); ?? ??? ??? ?yv[i] = (int) series.getY(i); ?? ??? ?} ?? ??? ?// 點集先清空,為了做成新的點集而準備 ?? ??? ?series.clear(); ? ?? ??? ?// 將新產(chǎn)生的點首先加入到點集中,然后在循環(huán)體中將坐標變換后的一系列點都重新加入到點集中 ?? ??? ?// 這里可以試驗一下把順序顛倒過來是什么效果,即先運行循環(huán)體,再添加新產(chǎn)生的點 ?? ??? ?series.add(addX, addY); ?? ??? ?for (int k = 0; k < length; k++) { ?? ??? ??? ?series.add(xv[k], yv[k]); ?? ??? ?} ?? ??? ?// 在數(shù)據(jù)集中添加新的點集 ?? ??? ?mDataset.addSeries(series); ? ?? ??? ?// 視圖更新,沒有這一步,曲線不會呈現(xiàn)動態(tài) ?? ??? ?// 如果在非UI主線程中,需要調(diào)用postInvalidate(),具體參考api ?? ??? ?chart.invalidate(); ?? ?} ? ?? ?// 圖2 ?? ?private void updateChart1()// 更新繪圖方法 ?? ?{ ? ?? ??? ?// 設(shè)置好下一個需要增加的節(jié)點 ?? ??? ?addX1 = (int) (addX1 + 1); ?? ??? ?addY1 = BatteryN; ?? ??? ?// 移除數(shù)據(jù)集中舊的點集 ?? ??? ?mDataset1.removeSeries(series1); ?? ??? ?// 判斷當(dāng)前點集中到底有多少點,因為屏幕總共只能容納240個,所以當(dāng)點數(shù)超過240時,長度永遠是240 ?? ??? ?int length1 = series1.getItemCount(); ?? ??? ?if (length1 > 720) { ?? ??? ??? ?length1 = 720; ?? ??? ?} ?? ??? ?// 將舊的點集中x和y的數(shù)值取出來放入backup中,并且將x的值加1,造成曲線向右平移的效果 ?? ??? ?for (int j = 0; j < length1; j++) { ?? ??? ??? ?xv1[j] = (int) series1.getX(j); ?? ??? ??? ?yv1[j] = (int) series1.getY(j); ?? ??? ?} ?? ??? ?// 點集先清空,為了做成新的點集而準備 ?? ??? ?series1.clear(); ? ?? ??? ?// 將新產(chǎn)生的點首先加入到點集中,然后在循環(huán)體中將坐標變換后的一系列點都重新加入到點集中 ?? ??? ?// 這里可以試驗一下把順序顛倒過來是什么效果,即先運行循環(huán)體,再添加新產(chǎn)生的點 ?? ??? ?series1.add(addX1, addY1); ?? ??? ?for (int l = 0; l < length1; l++) { ?? ??? ??? ?series1.add(xv1[l], yv1[l]); ?? ??? ?} ?? ??? ?// 在數(shù)據(jù)集中添加新的點集 ?? ??? ?mDataset1.addSeries(series1); ? ?? ??? ?// 視圖更新,沒有這一步,曲線不會呈現(xiàn)動態(tài) ?? ??? ?// 如果在非UI主線程中,需要調(diào)用postInvalidate(),具體參考api ?? ??? ?chart1.invalidate(); ?? ?} ? ?? ?/* 創(chuàng)建電池狀態(tài)廣播接收器 */ ?? ?public BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() { ?? ??? ?public void onReceive(Context context, Intent intent) { ?? ??? ??? ?String action = intent.getAction(); ? ?? ??? ??? ?// 如果捕捉到的action是ACTION_BATTERY_CHANGED, 就運行onBatteryInfoReceiver() ? ?? ??? ??? ?if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { ?? ??? ??? ??? ?BatteryN = intent.getIntExtra("level", 0); // 目前電量 ?? ??? ??? ??? ?BatteryV = intent.getIntExtra("voltage", 0); // 電池電壓 ?? ??? ??? ??? ?// BatteryT = intent.getIntExtra("temperature", 0); //電池溫度 ? ?? ??? ??? ??? ?switch (intent.getIntExtra("status", ?? ??? ??? ??? ??? ??? ?BatteryManager.BATTERY_STATUS_UNKNOWN)) { ?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_CHARGING: ?? ??? ??? ??? ??? ?BatteryStatus = "充電狀態(tài)"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_DISCHARGING: ?? ??? ??? ??? ??? ?BatteryStatus = "放電狀態(tài)"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_NOT_CHARGING: ?? ??? ??? ??? ??? ?BatteryStatus = "未充電"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_FULL: ?? ??? ??? ??? ??? ?BatteryStatus = "充滿電"; ? ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_UNKNOWN: ?? ??? ??? ??? ??? ?BatteryStatus = "未知道狀態(tài)"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?} ? ?? ??? ??? ??? ?switch (intent.getIntExtra("health", ?? ??? ??? ??? ??? ??? ?BatteryManager.BATTERY_HEALTH_UNKNOWN)) { ?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_UNKNOWN: ?? ??? ??? ??? ??? ?BatteryTemp = "未知錯誤"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_GOOD: ?? ??? ??? ??? ??? ?BatteryTemp = "狀態(tài)良好"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_DEAD: ?? ??? ??? ??? ??? ?BatteryTemp = "電池沒有電"; ? ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: ?? ??? ??? ??? ??? ?BatteryTemp = "電池電壓過高"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_OVERHEAT: ?? ??? ??? ??? ??? ?BatteryTemp = "電池過熱"; ?? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ?} ?? ??? ??? ??? ?TV.setText("目前電量為" + BatteryN + "% --- " + BatteryStatus + "\n" ?? ??? ??? ??? ??? ??? ?+ "電壓為" + BatteryV + "mV ----- " + BatteryTemp); ? ?? ??? ??? ?} ?? ??? ?} ? ?? ?}; ? ?? ?@Override ?? ?public boolean onKeyDown(int keyCode, KeyEvent event)// 程序按返回鍵退出處理 ?? ?{ ?? ??? ?switch (keyCode) { ?? ??? ?case KeyEvent.KEYCODE_BACK: ?? ??? ??? ?// 雙擊退出 ?? ??? ??? ?// if (isStart == true){isStart = false;}//關(guān)閉前確認頻閃是否關(guān)閉 ?? ??? ??? ?if ((System.currentTimeMillis() - mExitTime) > 2000) { ?? ??? ??? ??? ?Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show(); ?? ??? ??? ??? ?mExitTime = System.currentTimeMillis(); ?? ??? ??? ?} else { ?? ??? ??? ??? ?// isStart = false; ?? ??? ??? ??? ?finish(); ?? ??? ??? ?} ?? ??? ??? ?return true; ? ?? ??? ?default: ?? ??? ??? ?break; ?? ??? ?} ?? ??? ?return super.onKeyDown(keyCode, event); ?? ?} ? }
布局文件:
<?xml version="1.0" encoding="utf-8"?> ? <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"? ? ? android:id="@+id/linearLayout1" ? ?? ? ? android:orientation="vertical" ? ? ? android:layout_width="fill_parent" ? ? ? android:layout_height="fill_parent" ? ? android:layout_weight="1" ? ? > ? <!-- ?--> <TextView ? ? ? android:id = "@+id/TV"? ? ? ?? ? ? android:layout_width="fill_parent" ? ? ? android:layout_height="wrap_content"? ? ?? ? ? /> ? ?? <Button ? android:text="保存該曲線圖" ? android:textSize="4pt" ? android:id="@+id/my_button" ?? ? android:layout_width="fill_parent" ? android:layout_height="28dp" ? android:layout_alignBottom="@+id/TV"> ? <!--android:layout_alignParentBottom="true"--> ?? </Button> </LinearLayout>
AndroidManifest.xml配置文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ? ? package="com.cfzz.vcd" ? ? android:versionCode="1" ? ? android:versionName="1.0">? ? ?? ? ? <uses-sdk android:minSdkVersion="10" /> ? ? <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/> ? ? <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ? ? <uses-permission android:name="android.permission.WAKE_LOCK" /> ? ? ? <application ? ? ? ? android:icon="@drawable/ic_launcher" ? ? ? ? android:label="@string/app_name" > ? ? ? ? <activity android:name="org.achartengine.GraphicalActivity" /> ? ? ? ? <activity ? ? ? ? ? ? android:name="com.cfzz.vcd.VoltageChangeDraw" ? ? ? ? ? ? android:screenOrientation="portrait" ? ? ? ? ? ? android:label="@string/app_name" > ? ? ? ? ? ? <intent-filter> ? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" /> ? ? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" /> ? ? ? ? ? ? </intent-filter> ? ? ? ? </activity> ? ? </application> ? </manifest>
在該源碼中,我們繪制了兩條曲線,一條是電壓變化曲線,另一條是電量變化曲線,并加一個保存手機屏幕的截圖按鈕和自動保存時間任務(wù)(也可手動保存),用來保存繪制的截圖。
運行結(jié)果圖(充電曲線圖):
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android把商品添加到購物車的動畫效果(貝塞爾曲線)
- Android 曲線圖的繪制示例代碼
- Android利用MPAndroidChart繪制曲線圖表的基礎(chǔ)教程
- Android LineChart繪制多條曲線的方法
- Android編程之canvas繪制各種圖形(點,直線,弧,圓,橢圓,文字,矩形,多邊形,曲線,圓角矩形)
- Android實現(xiàn)價格走勢自定義曲線圖
- Android 利用三階貝塞爾曲線繪制運動軌跡的示例
- android貝塞爾曲線實現(xiàn)波浪效果
- Android貝塞爾曲線初步學(xué)習(xí)第二課 仿QQ未讀消息氣泡拖拽黏連效果
- Android中貝塞爾曲線的繪制方法示例代碼
相關(guān)文章
Android 自定義日期段選擇控件功能(開始時間-結(jié)束時間)
這篇文章主要介紹了Android 自定義日期段選擇控件功能,開始時間-結(jié)束時間。本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04Flutter實現(xiàn)頁面切換后保持原頁面狀態(tài)的3種方法
這篇文章主要給大家介紹了關(guān)于Flutter實現(xiàn)頁面切換后保持原頁面狀態(tài)的3種方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03