Android實(shí)現(xiàn)價(jià)格走勢(shì)自定義曲線圖
本文是引用開(kāi)源圖表庫(kù)框架 MPAndroidChart的LineChart
地址:https://github.com/PhilJay/MPAndroidChart
1.需求:
(1)動(dòng)態(tài)添加RadioButton,點(diǎn)擊改變下面的LineChart數(shù)據(jù)
(2)LineChart繪制價(jià)格走勢(shì)圖,只顯示最低點(diǎn)的小圓點(diǎn)和View,手指滑動(dòng),MarkView數(shù)據(jù)變化。
(3) 服務(wù)端返回端數(shù)據(jù),不是每一天端數(shù)據(jù),但是x軸顯示的必須是每一天的數(shù)據(jù),這里是有我自己處理過(guò)的。返回里需要顯示點(diǎn)的數(shù)組,之前的時(shí)間點(diǎn)顯示的就是第一個(gè)點(diǎn)值。

2.實(shí)現(xiàn)效果:

最低點(diǎn)顯示View和小圓點(diǎn)是自定義的,通過(guò)修改 LineChart的源碼,下面我們來(lái)具體分析代碼
3.代碼分析
(1)布局的xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RadioGroup
android:id="@+id/mRadioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30px"
android:orientation="horizontal"
android:visibility="gone">
</RadioGroup>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="vertical">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/mLineChart"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/detailMinTimeTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50px"
android:layout_weight="1"
android:textColor="#B5B5B5"
android:textSize="24px" />
<TextView
android:id="@+id/detailMaxTimeTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="30px"
android:layout_weight="1"
android:gravity="right"
android:textColor="#B5B5B5"
android:textSize="24px" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
這里主要是添加以一個(gè)RadioGroup和一個(gè)LineChart
接下來(lái)是MainActivity.class
private void addViewForGroup(final List<JsonData.HistoricalPrice> list) {
for (int i = 0; i < list.size(); i++) {
final RadioButton view = (RadioButton) LayoutInflater.from(MainActivity.this)
.inflate(R.layout.item_gr_add_but_layout, mRadioGroup, false);
view.setId(i);
view.setText(list.get(i).getTitle());
if (i==0){
view.performClick();
radioGroupTextChange(list.get(0).getData(), list.get(0).getTitle());
mLineCharWidget = new LineChartWidget(MainActivity.this,
list.get(0).getData(), mLineChart, setMinPrice(list.get(0).getData()));
}
mRadioGroup.addView(view);
}
mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton button = (RadioButton) findViewById(checkedId);
button.setText(list.get(checkedId).getTitle());
for (int i = 0; i < list.size(); i++) {
if (button.getText().toString().equals(list.get(i).getTitle())) {
radioGroupTextChange(list.get(i).getData(), list.get(i).getTitle());
if (mLineCharWidget == null) {
mLineCharWidget = new LineChartWidget(MainActivity.this,
list.get(i).getData(), mLineChart, setMinPrice(list.get(i).getData()));
} else {
mLineCharWidget.updateLineChar(list.get(i).getData(), setMinPrice(list.get(i).getData()));
}
}
}
}
});
}
注意:這里的LineChartWidget是我自己封裝的一個(gè)LineChart,包括LineChart初始化,數(shù)據(jù)的處理,已經(jīng)手勢(shì)的一些操作
簡(jiǎn)單的說(shuō)一下思路,因?yàn)?Linechart的x,y都是自定義的,但是我這里只自定義的y軸,是把x隱藏起來(lái)的,x軸只顯示最開(kāi)始的點(diǎn)和結(jié)束的點(diǎn),所以我這里有點(diǎn)投機(jī),自己設(shè)置點(diǎn)兩個(gè)textview來(lái)顯示的
Linechart的點(diǎn)一設(shè)置都是統(tǒng)一所有點(diǎn)都設(shè)置的,但是需求上是得只在最低點(diǎn)顯示,并還要繪制一個(gè)view先初始化 View,然后解析數(shù)據(jù),
JsonData jsonDetail = new Gson().fromJson(jsonStr.toString(), new TypeToken<JsonData>() {
}.getType());
if (jsonDetail.getHistorical_price() != null && jsonDetail.getHistorical_price().size() > 0) {
setGroupLay(jsonDetail.getHistorical_price());
}
再根據(jù)解析的數(shù)據(jù)動(dòng)態(tài)添加RadioButton
初始化LineChart
private void initLineChar() {
List<JsonData.HistoricalPrice.HistoricalPriceData.DataList> datalist
= removeDuplicteData(mHistoricalPrice.getData_list());
//設(shè)置手勢(shì)滑動(dòng)事件
mLineChar.setOnChartGestureListener(this);
//設(shè)置數(shù)值選擇監(jiān)聽(tīng)
mLineChar.setOnChartValueSelectedListener(this);
//后臺(tái)繪制
mLineChar.setDrawGridBackground(false);
//設(shè)置描述文本
mLineChar.getDescription().setEnabled(false);
mLineChar.setTouchEnabled(true); // 設(shè)置是否可以觸摸
mLineChar.setDragEnabled(true);// 是否可以拖拽
mLineChar.setScaleXEnabled(true); //是否可以縮放 僅x軸
mLineChar.setScaleYEnabled(true); //是否可以縮放 僅y軸
mLineChar.setPinchZoom(true); //設(shè)置x軸和y軸能否同時(shí)縮放。默認(rèn)是否
mLineChar.setDragDecelerationFrictionCoef(0.99f);
mLineChar.getAxisRight().setEnabled(false);
// 默認(rèn)動(dòng)畫
mLineChar.animateX(2500);
setMakeList(removeDuplicteData(datalist));
initMark(makeList, Long.valueOf(mHistoricalPrice.getStart_time()));
initXAxis(datalist.size(), xAxisValuesStr);
initYAxis();
initLegend();
setLineCharData(makeList);
}
設(shè)置markView
private void setMakeList(List<JsonData.HistoricalPrice.HistoricalPriceData.DataList> datalist) {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dBegin = format.parse(format.format(Long.valueOf(mHistoricalPrice.getStart_time()) * 1000));
Date dEnd = format.parse(format.format(Long.valueOf(mHistoricalPrice.getEnd_time()) * 1000));
float prices = 0;
List<Date> listDate = getDatesBetweenTwoDate(dBegin, dEnd);
if (datalist.size() >= listDate.size()) {
makeList.clear();
makeList.addAll(datalist);
} else {
for (int i = 0; i < listDate.size(); i++) {
JsonData.HistoricalPrice.HistoricalPriceData.DataList data
= new JsonData.HistoricalPrice.HistoricalPriceData.DataList();
for (int j = 0; j < datalist.size(); j++) {
if (TimeToString(DateToTimestamp(listDate.get(i))).equals(TimeToString(Long.valueOf(datalist.get(j).getPrice_drop_time())))) {
data.setPrice_drop_time(datalist.get(j).getPrice_drop_time());
data.setPrice_new(datalist.get(j).getPrice_new());
prices = (datalist.get(j).getPrice_new());
} else {
data.setPrice_drop_time(DateToTimestamp(listDate.get(i)) + "");
data.setPrice_new(prices);
}
}
makeList.add(data);
}
}
} catch (ParseException e) {
e.printStackTrace();
}
}
這里是設(shè)置LineChart里面的數(shù)據(jù)
private void setData(ArrayList<Entry> values) {
LineDataSet set1 = null;
if (mLineChar.getData() != null && mLineChar.getData().getDataSetCount() > 0) {
set1 = (LineDataSet) mLineChar.getData().getDataSetByIndex(0);
set1.setValues(values);
mLineChar.getData().notifyDataChanged();
mLineChar.notifyDataSetChanged();
} else {
// 創(chuàng)建一個(gè)數(shù)據(jù)集,并給它一個(gè)類型
if (set1 == null) {
set1 = new LineDataSet(values, "價(jià)格曲線圖");
set1.setColor(Color.rgb(27, 198, 181));
set1.setCircleColor(Color.BLACK);
set1.setLineWidth(1f);
set1.setCircleRadius(3f);
set1.setDrawCircleHole(false);
set1.setValueTextSize(9f);
set1.setDrawFilled(true);
set1.setFormLineWidth(1f);
set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
set1.setHighlightEnabled(true); //允許突出顯示DataSet
set1.setDrawHighlightIndicators(false); // 取消點(diǎn)擊線上的點(diǎn)展示十字標(biāo)識(shí)
set1.setDrawValues(true); // 不展示線上面點(diǎn)的值
//是否顯示小圓點(diǎn)
set1.setDrawCircles(false);
//修改源碼 自定義的參數(shù),可以顯示最低點(diǎn)的View
set1.setLowDrawCircles(true);
set1.setCircleColors(Color.rgb(27, 198, 181));//27, 198, 181
//頂點(diǎn)設(shè)置值
set1.setDrawValues(false);
set1.setFillColor(Color.rgb(203, 242, 238));
}
//修改源碼 自定義的參數(shù),可以顯示最低點(diǎn)的View
set1.setLowNumbers(minData);
ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
//添加數(shù)據(jù)集
dataSets.add(set1);
//創(chuàng)建一個(gè)數(shù)據(jù)集的數(shù)據(jù)對(duì)象
LineData data = new LineData(dataSets);
//設(shè)置數(shù)據(jù)
mLineChar.setData(data);
}
}
這里是在源碼里新加的地方
//修改源碼 自定義的參數(shù),可以顯示最低點(diǎn)的View set1.setLowDrawCircles(true); set1.setLowNumbers(minData);
源碼修改部分:
1.在LineDataSet添加2個(gè)參數(shù),復(fù)寫ILineDataSet新加的方法
//是否顯示最低點(diǎn)的小圓點(diǎn) private boolean mDrawLowCircle = false; //最低點(diǎn)對(duì)應(yīng)的具體值 private float mLowNumbers = 100f;
2.在ILineDataSet接口中添加2個(gè)方法
boolean isLowDrawCirclesEnabled(); float getLowNumbers();
3.修改源碼LineChartRenderer這個(gè)類的 drawValues(Canvas c)方法中,這里是設(shè)置最低點(diǎn)顯示的View,這個(gè)方法中添加判斷:
//設(shè)置最低點(diǎn)顯示的自定義view
if (dataSet.isLowDrawCirclesEnabled()) {
if (entry.getY() == dataSet.getYMin()) {
//設(shè)置在左邊
if (x < 100) {
locationcode = 1;
} else { // 默認(rèn)在右邊
locationcode = 0;
}
appCustomDrawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, x,
y - valOffset, Color.WHITE);
break;
}
}
private int locationcode = 0;
//設(shè)置最低點(diǎn)顯示的text和text的背景框
private void appCustomDrawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
// Paint.FontMetrics fm = new Paint.FontMetrics();
mValuePaint.setColor(Color.rgb(27, 198, 181));
// mValuePaint.getFontMetrics(fm);
y = (y + Utils.convertDpToPixel(30));
switch (locationcode) {
case 0:
RectF rectF = new RectF((x - Utils.convertDpToPixel(35)), (y - Utils.convertDpToPixel(23)),
(x + Utils.convertDpToPixel(5)), y);
c.drawRoundRect(rectF, 10, 10, mValuePaint);
mValuePaint.setColor(color);
c.drawText("¥" + formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x - Utils.convertDpToPixel(15), y - Utils.convertDpToPixel(10), mValuePaint);
break;
case 1:
RectF rectF1 = new RectF(x + Utils.convertDpToPixel(5), (y - Utils.convertDpToPixel(23)), x + Utils.convertDpToPixel(45), y);
c.drawRoundRect(rectF1, 10, 10, mValuePaint);
mValuePaint.setColor(color);
c.drawText("¥" + formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x + Utils.convertDpToPixel(27), y - Utils.convertDpToPixel(10), mValuePaint);
break;
}
}
在drawCircles(Canvas c)方法中添加判斷:則可以顯示最低點(diǎn)的小圓點(diǎn)了。
//顯示最低點(diǎn)的小圓點(diǎn)
if (dataSet.isLowDrawCirclesEnabled()) {
if (e.getY() == dataSet.getYMin()) {
Bitmap circleBitmap = imageCache.getBitmap(j);
c.drawBitmap(circleBitmap, mCirclesBuffer[0] - circleRadius, mCirclesBuffer[1] - circleRadius, null);
break;
}
}
好了,所有功能的關(guān)鍵部分已經(jīng)講完了。大家不懂的可以留言提問(wèn),或者自己下載源碼看看:
github項(xiàng)目地址:https://github.com/Songyan992/LineChartStudy
源碼下載地址:LineChartStudy_jb51.rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android編程實(shí)現(xiàn)任務(wù)管理器的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)任務(wù)管理器的方法,涉及Android針對(duì)程序與進(jìn)程操作的相關(guān)技巧,需要的朋友可以參考下2015-12-12
Android自定義控件ScrollView實(shí)現(xiàn)上下滑動(dòng)功能
這篇文章主要為大家詳細(xì)介紹了Android自定義控件ScrollView實(shí)現(xiàn)上下滑動(dòng)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
Android 判斷SIM卡是中國(guó)移動(dòng)\中國(guó)聯(lián)通\中國(guó)電信(移動(dòng)運(yùn)營(yíng)商)
本文給帶來(lái)兩種方法來(lái)判斷sim卡是屬于哪個(gè)運(yùn)營(yíng)商的,要實(shí)現(xiàn)此功能我們需要先獲取手機(jī)的imsi碼然后在判斷,對(duì)此功能感興趣的朋友一起通過(guò)本文學(xué)習(xí)吧2016-09-09
Android獲取、更改包名的小技巧分享(超實(shí)用)
這篇文章主要給大家分享介紹了關(guān)于利用Android更改包名的一個(gè)小技巧,通過(guò)這個(gè)方法大家可以很方便的修改包名,再也不用為頻繁修改包名而感到頭疼,文中還給大家分享利一個(gè)android獲取手機(jī)所有應(yīng)用包名的方法,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
ListView-添加item的事件監(jiān)聽(tīng)實(shí)例
下面小編就為大家?guī)?lái)一篇ListView-添加item的事件監(jiān)聽(tīng)實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
Android給自定義按鍵添加廣播和通過(guò)廣播給當(dāng)前焦點(diǎn)輸入框賦值
這篇文章主要介紹了Android給自定義按鍵添加廣播和通過(guò)廣播給當(dāng)前焦點(diǎn)輸入框賦值的相關(guān)資料,需要的朋友可以參考下2016-10-10

