Android自定義View實(shí)現(xiàn)天氣預(yù)報(bào)折線(xiàn)圖
本文實(shí)例為大家分享了Android自定義View畫(huà)天氣預(yù)報(bào)折線(xiàn)圖的具體代碼,供大家參考,具體內(nèi)容如下
效果圖如下:
剛開(kāi)始嘗試用第三方畫(huà)曲線(xiàn)的框架來(lái)畫(huà)效果圖,后來(lái)發(fā)現(xiàn)曲線(xiàn)間的陰影當(dāng)有負(fù)數(shù)的度數(shù)的時(shí)候畫(huà)不出來(lái),而且不需要點(diǎn)擊放大、點(diǎn)點(diǎn)可點(diǎn)的效果,用框架顯得很臃腫,所以最后用自定義View來(lái)畫(huà)的折線(xiàn)圖。自定義畫(huà)折線(xiàn)圖的大致思路:這個(gè)圖是有多個(gè)四邊形組成的(4個(gè)點(diǎn)連接起來(lái)就是一個(gè)四邊形),兩邊延伸:添加四個(gè)多余的點(diǎn),將左右的邊距設(shè)置成負(fù)數(shù)即可。
代碼如下:
public class WeatherChartView extends View { ? ? /** ? ? ?* x軸集合 ? ? ?*/ ? ? private float mXAxis[] ; ? ? /** ? ? ?* 白天y軸集合 ? ? ?*/ ? ? private float mYAxisDay[] ; ? ? /** ? ? ?* 夜間y軸集合 ? ? ?*/ ? ? private float mYAxisNight[] ; ? ? /** ? ? ?* x,y軸集合數(shù) ? ? ?*/ ? ? private int LENGTH ; ? ? /** ? ? ?* 白天溫度集合 ? ? ?*/ ? ? private int mTempDay[] ; ? ? /** ? ? ?* 夜間溫度集合 ? ? ?*/ ? ? private int mTempNight[] ; ? ? /** ? ? ?* 控件高 ? ? ?*/ ? ? private int mHeight; ? ? /** ? ? ?* 字體大小 ? ? ?*/ ? ? private float mTextSize; ? ? /** ? ? ?* 圓半徑 ? ? ?*/ ? ? private float mRadius ; ? ? /** ? ? ?* 圓半徑今天 ? ? ?*/ ? ? private float mRadiusToday ; ? ? /** ? ? ?* 文字移動(dòng)位置距離 ? ? ?*/ ? ? private float mTextSpace ; ? ? /** ? ? ?* 線(xiàn)的大小 ? ? ?*/ ? ? private float mStokeWidth ; ? ? /** ? ? ?* 白天折線(xiàn)顏色 ? ? ?*/ ? ? private int mColorDay = Color.parseColor("#ffffff"); ? ? /** ? ? ?* 夜間折線(xiàn)顏色 ? ? ?*/ ? ? private int mColorNight = Color.parseColor("#ffffff");; ? ? /** ? ? ?* 字體顏色 ? ? ?*/ ? ? private int mTextColor = Color.parseColor("#ffffff");; ? ? /** ? ? ?* 屏幕密度 ? ? ?*/ ? ? private float mDensity; ? ? /** ? ? ?* 控件邊的空白空間 ? ? ?*/ ? ? private float mSpace; ? ? @SuppressWarnings("deprecation") ? ? public WeatherChartView(Context context, AttributeSet attrs) { ? ? ? ? super(context, attrs);? ? ? ? ? mDensity = getResources().getDisplayMetrics().density; ? ? ? ? mRadius = 3 * mDensity; ? ? ? ? mRadiusToday = 3 * mDensity; ? ? ? ? //mSpace = 3 * mDensity; ? ? ? ? mTextSpace = 10 * mDensity; ? ? ? ? mStokeWidth = 2 * mDensity; ? ? ? ? mTextSize = BreakRuleTools.dip2px(context, 12); ? ? } ? ? public WeatherChartView(Context context) { ? ? ? ? super(context); ? ? } ? ? @Override ? ? protected void onDraw(Canvas canvas) { ? ? ? ? super.onDraw(canvas); ? ? ? ? if (mHeight == 0) { ? ? ? ? ? ? // 設(shè)置控件高度,x軸集合 ? ? ? ? ? ? setHeightAndXAxis(); ? ? ? ? } ? ? ? ? // 計(jì)算y軸集合數(shù)值 ? ? ? ? computeYAxisValues(); ? ? ? ? // 畫(huà)白天折線(xiàn)圖 ? ? ? ? drawChart(canvas, mColorDay, mTempDay, mYAxisDay, 0); ? ? ? ? // 畫(huà)夜間折線(xiàn)圖 ? ? ? ? drawChart(canvas, mColorNight, mTempNight, mYAxisNight, 1); ? ? } ? ? /** ? ? ?* 計(jì)算y軸集合數(shù)值 ? ? ?*/ ? ? private void computeYAxisValues() { ? ? ? ? // 存放白天最低溫度 ? ? ? ? int minTempDay = mTempDay[0]; ? ? ? ? // 存放白天最高溫度 ? ? ? ? int maxTempDay = mTempDay[0]; ? ? ? ? for (int item : mTempDay) { ? ? ? ? ? ? if (item < minTempDay) { ? ? ? ? ? ? ? ? minTempDay = item; ? ? ? ? ? ? } ? ? ? ? ? ? if (item > maxTempDay) { ? ? ? ? ? ? ? ? maxTempDay = item; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? // 存放夜間最低溫度 ? ? ? ? int minTempNight = mTempNight[0]; ? ? ? ? // 存放夜間最高溫度 ? ? ? ? int maxTempNight = mTempNight[0]; ? ? ? ? for (int item : mTempNight) { ? ? ? ? ? ? if (item < minTempNight) { ? ? ? ? ? ? ? ? minTempNight = item; ? ? ? ? ? ? } ? ? ? ? ? ? if (item > maxTempNight) { ? ? ? ? ? ? ? ? maxTempNight = item; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? // 白天,夜間中的最低溫度 ? ? ? ? int minTemp = minTempNight < minTempDay ? minTempNight : minTempDay; ? ? ? ? // 白天,夜間中的最高溫度 ? ? ? ? int maxTemp = maxTempDay > maxTempNight ? maxTempDay : maxTempNight; ? ? ? ? // 份數(shù)(白天,夜間綜合溫差) ? ? ? ? float parts = maxTemp - minTemp; ? ? ? ? // y軸一端到控件一端的距離 ? ? ? ? float length = mSpace + mTextSize + mTextSpace + mRadius; ? ? ? ? // y軸高度 ? ? ? ? float yAxisHeight = mHeight - length * 2; ? ? ? ? // 當(dāng)溫度都相同時(shí)(被除數(shù)不能為0) ? ? ? ? if (parts == 0) { ? ? ? ? ? ? for (int i = 0; i < LENGTH; i++) { ? ? ? ? ? ? ? ? mYAxisDay[i] = yAxisHeight / 2 + length; ? ? ? ? ? ? ? ? mYAxisNight[i] = yAxisHeight / 2 + length; ? ? ? ? ? ? } ? ? ? ? } else { ? ? ? ? ? ? float partValue = yAxisHeight / parts; ? ? ? ? ? ? for (int i = 0; i < LENGTH; i++) { ? ? ? ? ? ? ? ? mYAxisDay[i] = mHeight - partValue * (mTempDay[i] - minTemp) - length; ? ? ? ? ? ? ? ? mYAxisNight[i] = mHeight - partValue * (mTempNight[i] - minTemp) - length; ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? /** ? ? ?* 畫(huà)折線(xiàn)圖 ? ? ?* ? ? ?* @param canvas 畫(huà)布 ? ? ?* @param color ?畫(huà)圖顏色 ? ? ?* @param temp ? 溫度集合 ? ? ?* @param yAxis ?y軸集合 ? ? ?* @param type ? 折線(xiàn)種類(lèi):0,白天;1,夜間 ? ? ?*/ ? ? private void drawChart(Canvas canvas, int color, int temp[], float[] yAxis, int type) { ? ? ? ? color = Color.parseColor("#ffffff"); ? ? ? ? // 線(xiàn)畫(huà)筆 ? ? ? ? Paint linePaint = new Paint(); ? ? ? ? // 抗鋸齒 ? ? ? ? linePaint.setAntiAlias(true); ? ? ? ? // 線(xiàn)寬 ? ? ? ? linePaint.setStrokeWidth(mStokeWidth); ? ? ? ? linePaint.setColor(color); ? ? ? ? // 空心 ? ? ? ? linePaint.setStyle(Paint.Style.STROKE); ? ? ? ? // 點(diǎn)畫(huà)筆 ? ? ? ? Paint pointPaint = new Paint(); ? ? ? ? pointPaint.setAntiAlias(true); ? ? ? ? pointPaint.setColor(color); ? ? ? ? // 字體畫(huà)筆 ? ? ? ? Paint textPaint = new Paint(); ? ? ? ? textPaint.setAntiAlias(true); ? ? ? ? textPaint.setColor(mTextColor); ? ? ? ? textPaint.setTextSize(mTextSize); ? ? ? ? // 文字居中 ? ? ? ? textPaint.setTextAlign(Paint.Align.CENTER); ? ? ? ? int alpha1 = 102; ? ? ? ? int alpha2 = 255; ? ? ? ? for (int i = 0; i < LENGTH; i++) { ? ? ? ? ? ? // 畫(huà)線(xiàn) ? ? ? ? ? ? if (i < LENGTH - 1) { ? ? ? ? ? ? ? ? // 昨天 ? ? ? ? ? ? ? ? if (i == -1) { ? ? ? ? ? ? ? ? ? ? linePaint.setAlpha(alpha1); ? ? ? ? ? ? ? ? ? ? // 設(shè)置虛線(xiàn)效果 ? ? ? ? ? ? ? ? ? ? linePaint.setPathEffect(new DashPathEffect(new float[]{2 * mDensity, 2 * mDensity}, 0)); ? ? ? ? ? ? ? ? ? ? // 路徑 ? ? ? ? ? ? ? ? ? ? Path path = new Path(); ? ? ? ? ? ? ? ? ? ? // 路徑起點(diǎn) ? ? ? ? ? ? ? ? ? ? path.moveTo(mXAxis[i], yAxis[i]); ? ? ? ? ? ? ? ? ? ? // 路徑連接到 ? ? ? ? ? ? ? ? ? ? path.lineTo(mXAxis[i + 1], yAxis[i + 1]); ? ? ? ? ? ? ? ? ? ? canvas.drawPath(path, linePaint); ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? if(type == 0) { ? ? ? ? ? ? ? ? ? ? ? ? linePaint.setAlpha(76); ? ? ? ? ? ? ? ? ? ? ? ? linePaint.setPathEffect(null); ? ? ? ? ? ? ? ? ? ? ? ? linePaint.setStyle(Paint.Style.FILL);//設(shè)置實(shí)心 ? ? ? ? ? ? ? ? ? ? ? ? Path path = new Path(); ? ? ? ? ? ? ? ? ? ? //Path對(duì)象 ? ? ? ? ? ? ? ? ? ? ? ? path.moveTo(mXAxis[i], mYAxisDay[i]); ? ? ? ? ? ? ? ? ? ? ? ? ? //起始點(diǎn) ? ? ? ? ? ? ? ? ? ? ? ? path.lineTo(mXAxis[i + 1], mYAxisDay[i + 1]); ? ? ? ? ? ? ? ? ? ? ? ? ? //連線(xiàn)到下一點(diǎn) ? ? ? ? ? ? ? ? ? ? ? ? path.lineTo(mXAxis[i + 1], mYAxisNight[i + 1]); ? ? ? ? ? ? ? ? ? ? ?//連線(xiàn)到下一點(diǎn) ? ? ? ? ? ? ? ? ? ? ? ? path.lineTo(mXAxis[i], mYAxisNight[i]); ? ? ? ? ? ? ? ? ? ? ?//連線(xiàn)到下一點(diǎn) ? ? ? ? ? ? ? ? ? ? ? ? path.lineTo(mXAxis[i], mYAxisDay[i]); ? ? ? ? ? ? ? ? ? ? ?//連線(xiàn)到下一點(diǎn) ? ? ? ? ? ? ? ? ? ? ? ? canvas.drawPath(path, linePaint); ? ? ? ? ? ? ? ? ? //繪制任意多邊形 ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? //canvas.drawLine(mXAxis[i], yAxis[i], mXAxis[i + 1], yAxis[i + 1], linePaint); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? // 畫(huà)點(diǎn) ? ? ? ? ? ? if (i != 1) { ? ? ? ? ? ? ? ? // 昨天 ? ? ? ? ? ? ? ? if (i == 0 || i == LENGTH - 1) { ? ? ? ? ? ? ? ? ? ? /*pointPaint.setAlpha(alpha1); ? ? ? ? ? ? ? ? ? ? canvas.drawCircle(mXAxis[i], yAxis[i], mRadius, pointPaint);*/ ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? pointPaint.setAlpha(alpha2); ? ? ? ? ? ? ? ? ? ? canvas.drawCircle(mXAxis[i], yAxis[i], mRadius, pointPaint); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? // 今天 ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? pointPaint.setAlpha(alpha2); ? ? ? ? ? ? ? ? canvas.drawCircle(mXAxis[i], yAxis[i], mRadiusToday, pointPaint); ? ? ? ? ? ? } ? ? ? ? ? ? // 畫(huà)字 ? ? ? ? ? ? // 昨天 ? ? ? ? ? ? if (i == 0 || i == LENGTH - 1) { ? ? ? ? ? ? ? ? /*textPaint.setAlpha(alpha1); ? ? ? ? ? ? ? ? drawText(canvas, textPaint, i, temp, yAxis, type);*/ ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? textPaint.setAlpha(alpha2); ? ? ? ? ? ? ? ? drawText(canvas, textPaint, i, temp, yAxis, type); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? /** ? ? ?* 繪制文字 ? ? ?* ? ? ?* @param canvas ? ?畫(huà)布 ? ? ?* @param textPaint 畫(huà)筆 ? ? ?* @param i ? ? ? ? 索引 ? ? ?* @param temp ? ? ?溫度集合 ? ? ?* @param yAxis ? ? y軸集合 ? ? ?* @param type ? ? ?折線(xiàn)種類(lèi):0,白天;1,夜間 ? ? ?*/ ? ? private void drawText(Canvas canvas, Paint textPaint, int i, int[] temp, float[] yAxis, int type) { ? ? ? ? switch (type) { ? ? ? ? ? ? case 0: ? ? ? ? ? ? ? ? // 顯示白天氣溫 ? ? ? ? ? ? ? ? canvas.drawText(temp[i] + "°", mXAxis[i], yAxis[i] - mRadius - mTextSpace, textPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case 1: ? ? ? ? ? ? ? ? // 顯示夜間氣溫 ? ? ? ? ? ? ? ? canvas.drawText(temp[i] + "°", mXAxis[i], yAxis[i] + mTextSpace + mTextSize, textPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? } ? ? /** ? ? ?* 設(shè)置高度,x軸集合 ? ? ?*/ ? ? private void setHeightAndXAxis() { ? ? ? ? mHeight = getHeight(); ? ? ? ? // 控件寬 ? ? ? ? int width = getWidth(); ? ? ? ? int i = LENGTH - 2; ? ? ? ? // 每一份寬 ? ? ? ? float w = width / (i*2); ? ? ? ? for(int j =0;j<LENGTH;j++){ ? ? ? ? ? ? if(j == 0){ ? ? ? ? ? ? ? ? mXAxis[j] = 0; ? ? ? ? ? ? } else if(j == LENGTH -1){ ? ? ? ? ? ? ? ? mXAxis[j] = width; ? ? ? ? ? ? } else{ ? ? ? ? ? ? ? ? mXAxis[j] = w * (2*j -1); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ?/* mXAxis[0] = 0; ? ? ? ? mXAxis[1] = w; ? ? ? ? mXAxis[2] = w * 3; ? ? ? ? mXAxis[3] = w * 5; ? ? ? ? mXAxis[4] = w * 7; ? ? ? ? mXAxis[5] = w * 9; ? ? ? ? mXAxis[6] = width;*/ ? ? ? ?/* mXAxis[5] = w * 11; ? ? ? ? mXAxis[6] = w * 13;*/ ? ? } ? ? /** ? ? ?* 設(shè)置白天溫度 ? ? ?* ? ? ?* @param tempDay 溫度數(shù)組集合 ? ? ?*/ ? ? public void setTempDay(int[] tempDay) { ? ? ? ? mTempDay = tempDay; ? ? ? ? LENGTH = mTempDay.length; ? ? ? ? mXAxis = new float[LENGTH]; ? ? ? ? mYAxisDay = new float[LENGTH]; ? ? ? ? mYAxisNight = new float[LENGTH]; ? ? ? ? /*mTempDay = new int[LENGTH]; ? ? ? ? mTempNight = new int[LENGTH];*/ ? ? } ? ? /** ? ? ?* 設(shè)置夜間溫度 ? ? ?* ? ? ?* @param tempNight 溫度數(shù)組集合 ? ? ?*/ ? ? public void setTempNight(int[] tempNight) { ? ? ? ? mTempNight = tempNight; ? ? } ? ? /** ? ? ?* 設(shè)置白天曲線(xiàn)的顏色 ? ? ?*/ ? ? public void setColorDay(){} }
布局代碼:
<com.pingan.carowner.weather.view.WeatherChartView ? ? ? ? ? ? android:id="@+id/line_char" ? ? ? ? ? ? android:layout_width="match_parent" ? ? ? ? ? ? android:layout_height="180dp" ? ? ? ? ? ? android:layout_below="@id/weather_over_view_item3" ? ? ? ? ? ? android:layout_centerInParent="true"/>
代碼引用:
// 設(shè)置白天溫度曲線(xiàn) mChartView = (WeatherChartView) findViewById(R.id.line_char); mChartView.setTempDay(highTemp);//highTemp 高溫度集合 // 設(shè)置夜間溫度曲線(xiàn) mChartView.setTempNight(lowTemp);//lowTemp 低溫集合 mChartView.invalidate();
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)創(chuàng)建或升級(jí)數(shù)據(jù)庫(kù)時(shí)執(zhí)行語(yǔ)句
這篇文章主要介紹了Android實(shí)現(xiàn)創(chuàng)建或升級(jí)數(shù)據(jù)庫(kù)時(shí)執(zhí)行語(yǔ)句,是比較實(shí)用的功能,需要的朋友可以參考下2014-08-08Android通過(guò)HttpURLConnection和HttpClient接口實(shí)現(xiàn)網(wǎng)絡(luò)編程
這篇文章主要介紹了Android通過(guò)HttpURLConnection和HttpClient接口實(shí)現(xiàn)網(wǎng)絡(luò)編程的相關(guān)資料,需要的朋友可以參考下2015-02-02Android文本框搜索和清空效果實(shí)現(xiàn)代碼及簡(jiǎn)要概述
在工作過(guò)程中可能會(huì)遇到這樣一個(gè)效果:文本框輸入為空時(shí)顯示輸入的圖標(biāo);不為空時(shí)顯示清空的圖標(biāo),此時(shí)點(diǎn)擊清空?qǐng)D標(biāo)能清空文本框內(nèi)輸入文字,感興趣的你可以了解下哦,或許對(duì)你學(xué)習(xí)android有所幫助2013-02-02Convert WebP to PNG using java
本文主要介紹Convert WebP to PNG using java,這里對(duì) WebP 做了詳細(xì)說(shuō)明,并講解Linux 環(huán)境下WebP 轉(zhuǎn)png格式的示例,有興趣的小伙伴可以參考下2016-08-08android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼
本篇文章主要介紹了android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-07-07Android開(kāi)發(fā)Launcher進(jìn)程啟動(dòng)流程
這篇文章主要為大家介紹了Android開(kāi)發(fā)Launcher進(jìn)程啟動(dòng)流程示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Android自定義view實(shí)現(xiàn)日歷打卡簽到
這篇文章主要為大家詳細(xì)介紹了Android自定義view實(shí)現(xiàn)日歷打卡簽到,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05