前言:对于学生的答题(学习)情况,数据是直观的表现,在实际开发中也需要涉及到大量的数据统计与分析,我们经常通过图表结合来更加直观的展现数据。
接下来,记录一下最近做的一个错题率统计与总成绩排行。整个界面是由上半部分的柱形图来展现错题记录,下半部分则是已提交(答题)人员的成绩排名。主要涉及到的几个点就是调用接口获取后台数据、数据的整理(排序)、数据的展现(包括柱形图与排行列表),我们按照开发的流程来了解。
第一步,界面设计
界面布局比较简单,直接贴代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administrator.parentproject.activity.TJActivity">
<RelativeLayout
android:id="@+id/relative"
style="@style/TitleStyle_Relative">
<ImageView
android:id="@+id/back"
style="@style/TitleStyle_Back"
android:layout_alignParentBottom="true" />
<TextView
android:id="@+id/title_tv"
style="@style/TitleStyle_Text"
android:layout_centerHorizontal="true"
android:singleLine="true"
android:text="错题率" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="6"
android:orientation="horizontal"
android:layout_margin="@dimen/dp_10"
android:background="@color/pink">
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/bar_chart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/dp_20"/>
</LinearLayout>
<LinearLayout
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="5"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:id="@+id/zcjph">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/pink"
android:gravity="center_horizontal"
android:text="姓名"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/pink"
android:gravity="center_horizontal"
android:text="排名"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/pink"
android:gravity="center_horizontal"
android:text="成绩"/>
</LinearLayout>
<ListView
android:id="@+id/zcjph_lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:paddingTop="@dimen/dp_10" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
柱形图使用第三方库MPChartLib实现,这个库支持使用简单支持的样式较多,只不过如果直接导入到项目中的话会比较大,因此建议有时间的话还是熟悉一下代码,从而可以减去无关的代码和资源。这里附上一个网址方便大家熟悉https://blog.csdn.net/guijiaoba/article/details/41444697。
第二步,获取后台数据
我这里起两个请求,一个获取错题率另外一个则获取排名,共同调用一个方法,根据flag区分,
private void httpPost(final String flag) {
if (flag.equals("tj")) {
commitParam = new CommitParam();
commitParam.setToken(token);
commitParam.setId(classPID);
commitParam.setClassPid(id);
map = commitParam.getData();
data = RetrofitBean.getApiApi().getDataExam("get_papers_tongji",map);
}
if (flag.equals("score")) {
data = RetrofitBean.getApiApi().getZYList("get_student_post_papers", token, id, "score");
}
data.enqueue(new SimpleCallBack(flag) {
@Override
protected void showData(int i, String json) {
super.showData(i, json);
Gson gson = new Gson();
if (flag.equals("tj")) {
String result = "";
try {
JSONObject jsonObject = new JSONObject(json);
result = jsonObject.getString("result");
JSONObject rstJson = new JSONObject(result);
Iterator it = rstJson.keys();
Map map = new TreeMap();
while (it.hasNext()) {
String key = it.next().toString();
String value = rstJson.getString(key);
map.put(key, value);
}
Iterator it1 = map.keySet().iterator();
String s = "";
while (it1.hasNext()) {
//it.next()得到的是key,tm.get(key)得到obj
Object obj = it1.next();
s += obj + "-" + map.get(obj).toString() + "+";
}
Log.e("map",s+"");
setDataChart(map);
} catch (JSONException e) {
e.printStackTrace();
}
}
if (flag.equals("score")) {
mDataPg.clear();
PGZY pgzy = gson.fromJson(json, PGZY.class);
mDataPg.addAll(pgzy.getResult());
myListViewAdapter = new MyListViewAdapter(getBaseContext(), mDataPg, "zcjph",0);
zcjphLv.setAdapter(myListViewAdapter);
myListViewAdapter.notifyDataSetChanged();
}
}
});
}
第三步,渲染柱形图数据
private void setDataChart(Map map) {
//mBarData=getData(4,100);
mChart.setOnChartValueSelectedListener(this);
mChart.setDrawBarShadow(false);
mChart.setDrawValueAboveBar(true);
mChart.getDescription().setEnabled(false);
mChart.setMaxVisibleValueCount(100);
mChart.setPinchZoom(false);
mChart.setDrawGridBackground(false);
IAxisValueFormatter xAxisFormatter = new TmAxisValueFormatter(mChart, map);
XAxis xAxis = mChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
//xAxis.setTypeface(mTfLight);
xAxis.setDrawGridLines(false);
xAxis.setGranularity(1f); // only intervals of 1 day
xAxis.setLabelCount(map.size());
xAxis.setValueFormatter(xAxisFormatter);
IAxisValueFormatter custom = new MyAxisValueFormatter();
YAxis leftAxis = mChart.getAxisLeft();
//leftAxis.setTypeface(mTfLight);
leftAxis.setLabelCount(8, false);
leftAxis.setValueFormatter(custom);
leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
leftAxis.setSpaceTop(15f);
leftAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
leftAxis.setAxisMaximum(100f);
YAxis rightAxis = mChart.getAxisRight();
rightAxis.setDrawGridLines(false);
//rightAxis.setTypeface(mTfLight);
rightAxis.setLabelCount(8, false);
rightAxis.setValueFormatter(custom);
rightAxis.setSpaceTop(15f);
rightAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
rightAxis.setAxisMaximum(100f);
Legend l = mChart.getLegend();
l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
l.setDrawInside(false);
l.setForm(Legend.LegendForm.SQUARE);
l.setFormSize(9f);
l.setTextSize(11f);
l.setXEntrySpace(4f);
XYMarkerView mv = new XYMarkerView(this, xAxisFormatter);
mv.setChartView(mChart); // For bounds control
mChart.setMarker(mv);
setDataChartM(map);
mChart.invalidate();
}
private void setDataChartM(Map map) {
{
float start = 1f;
ArrayList<BarEntry> yVals1 = new ArrayList<BarEntry>();
Iterator it1 = map.keySet().iterator();
while (it1.hasNext()) {
//it.next()得到的是key,tm.get(key)得到obj
yVals1.add(new BarEntry(start, Float.parseFloat(map.get(it1.next()).toString())));
start += 1;
}
BarDataSet set1;
if (mChart.getData() != null &&
mChart.getData().getDataSetCount() > 0) {
set1 = (BarDataSet) mChart.getData().getDataSetByIndex(0);
set1.setValues(yVals1);
mChart.getData().notifyDataChanged();
mChart.notifyDataSetChanged();
} else {
set1 = new BarDataSet(yVals1, "错题记录");
set1.setDrawIcons(false);
set1.setColors(ColorTemplate.MATERIAL_COLOR1);
ArrayList<IBarDataSet> dataSets = new ArrayList<IBarDataSet>();
dataSets.add(set1);
BarData data = new BarData(dataSets);
data.setValueTextSize(10f);
//data.setValueTypeface(mTfLight);
data.setBarWidth(0.1f);
mChart.setData(data);
}
}
}
第四步,定义XY轴的格式
public class TmAxisValueFormatter implements IAxisValueFormatter {
private BarLineChartBase<?> chart;
private Map map;
public TmAxisValueFormatter(BarLineChartBase<?> chart) {
this.chart = chart;
}
public TmAxisValueFormatter(BarLineChartBase<?> chart, Map map) {
this.chart = chart;
this.map = map;
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
Iterator iterator=map.keySet().iterator();
int i =0;
String vu = "";
while (iterator.hasNext()){
i++;
Object obj = iterator.next();
if(i==value){
vu=obj.toString();
}
}
return "第"+vu+"题";
}
}
public class MyAxisValueFormatter implements IAxisValueFormatter
{
private DecimalFormat mFormat;
public MyAxisValueFormatter() {
mFormat = new DecimalFormat("###,###,###,##0.0");
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
return (int)value + " %";
}
}
最后,贴上结果图