这个简单的demo需理解掌握绘制曲线方法、生物节律算法、调用日期控件传递数据即可。
具体实现展示图:
界面自动显示的是当前的日期,为最中间的红线:
可点击更换日期按钮,触动对话框显示日期,对日期进行更改(日期为安卓自带控件):
更改日期后会更新绘图:
具体实现
1.绘制曲线,此处为在github中下载的绘图源码,在此源码的基础上进行修改。在安卓工程文件中定义为CustomCurveChat.java,以下是代码分步描述:
①安卓的绘图继承View,并重写它的onDraw( Canvas canvas)。
public class CustomCurveChart extends View {
②对绘制曲线的一些需要值和画笔方法进行声明。
// 坐标单位
private String[] xLabel;
private String[] yLabel;
// 曲线数据
private List<double[]> dataList;
private List<Integer> colorList;
private boolean showValue;
// 默认边距
private int margin = 20;
// 距离左边偏移量
private int marginX = 30;
// 原点坐标
private int xPoint;
private int yPoint;
// X,Y轴的单位长度
private int xScale;
private int yScale;
// 画笔
private Paint paintAxes;
private Paint paintCoordinate;
private Paint paintTable;
private Paint paintCurve;
private Paint paintRectF;
private Paint paintValue;
private Paint paintToday;
③定义方法(?),获取相关资源。
Context类:通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent信息等。
public CustomCurveChart(Context context, String[] xLabel, String[] yLabel, List<double[]> dataList, List<Integer> colorList, boolean showValue) {
super(context);
this.xLabel = xLabel;
this.yLabel = yLabel;
this.dataList = dataList;
this.colorList = colorList;
this.showValue = showValue;
}
public CustomCurveChart(Context context) {
super(context);
}
④初始化数据值和画笔。
/**
* 初始化数据值和画笔
*/
public void init() {
xPoint = margin + marginX;
yPoint = this.getHeight() - margin;
xScale = (this.getWidth() - 2 * margin - marginX) / (xLabel.length - 1);
yScale = (this.getHeight() - 2 * margin) / (yLabel.length - 1);
paintAxes = new Paint();
paintAxes.setStyle(Paint.Style.STROKE);
paintAxes.setAntiAlias(true);
paintAxes.setDither(true);
paintAxes.setColor(ContextCompat.getColor(getContext(), R.color.color14));
paintAxes.setStrokeWidth(4);
paintCoordinate = new Paint();
paintCoordinate.setStyle(Paint.Style.STROKE);
paintCoordinate.setDither(true);
paintCoordinate.setAntiAlias(true);
paintCoordinate.setColor(ContextCompat.getColor(getContext(), R.color.color14));
paintCoordinate.setTextSize(15);
...//省略
}
⑤重写onDraw,进行绘图
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(ContextCompat.getColor(getContext(), R.color.color1));
init();
drawTable(canvas, paintTable);
drawAxesLine(canvas, paintAxes);
drawCoordinate(canvas, paintCoordinate);
drawToday(canvas,paintToday);
for (int i = 0; i < dataList.size(); i++) {
System.out.println();
drawCurve(canvas, paintCurve, dataList.get(i), colorList.get(i));
if (showValue) {
drawValue(canvas, paintRectF, dataList.get(i), colorList.get(i));
}
}
}
⑥定义绘制方法
/*** 绘制坐标轴*/
private void drawAxesLine(Canvas canvas, Paint paint){}
/*** 绘制表格*/
private void drawTable(Canvas canvas, Paint paint){}
/*** 绘制今日 中间竖线*/
private void drawToday(Canvas canvas, Paint paint){}
...//省略
2.主Activity: RhythmActivity.java
①定义一个线性布局用于绘制曲线图,一个按钮点击触发显示对话框,全局变量用于存储日期变量,展示选择日期和显示今日数值的方法,初始化绘图的方法。
public class RhythmActivity extends AppCompatActivity {
private LinearLayout customCurveChart1;
int mYear, mMonth, mDay;
Button btn;
TextView dateDisplay;
final int DATE_DIALOG = 1;
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rhythm);
customCurveChart1 = (LinearLayout) findViewById(R.id.customCurveChart1);
btn = (Button) findViewById(R.id.change_date);
dateDisplay = (TextView) findViewById(R.id.today_date);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog(DATE_DIALOG);
}
});
final Calendar ca = Calendar.getInstance();
mYear = ca.get(Calendar.YEAR);
mMonth = ca.get(Calendar.MONTH);
mDay = ca.get(Calendar.DAY_OF_MONTH);
display();
String birth = set_birthDay();
initCurveChart1(birth);
}
②重写onCreateDialog,当被触发时id为1,创建DatePickerDialog对象(DatePicker日历UI组件)。
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DATE_DIALOG:
return new DatePickerDialog(this, mdateListener, mYear, mMonth, mDay);
}
return null;
}
③设置展示日期的格式,显示当前日期或修改后的日期。
public void display() {
Calendar curDate = Calendar.getInstance();
curDate.set(mYear, mMonth, mDay);
String date = formatter.format(curDate.getTime());
dateDisplay.setText(date);
}
④更改日期数据获取和更新。
private DatePickerDialog.OnDateSetListener mdateListener = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
mYear = year;
mMonth = monthOfYear;
mDay = dayOfMonth;
display();
String birth1 = set_birthDay();
initCurveChart1(birth1);
}
};
⑤初始化曲线图数据,此处需要用到计算生物节律以及绘制的算法。
智力周期33天,情绪周期28天,体力周期23天。计算从出生到目前日期的总天数,再计算各总天数除以周期的余数,最后对应绘制正弦曲线。
此处是以目前日期为中心,往前和后各延15天,总共绘制31天的图。
主要算法:
private void initCurveChart1(String birthday) {
double[] physical = new double [31];
double[] mood = new double [31];
double[] brains = new double [31];
String[] xLabel = new String[31];
String[] yLabel = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};
Calendar curDate = Calendar.getInstance();
curDate.set(mYear, mMonth, mDay);
String date = formatter.format(curDate.getTime());
long howDays = 0;
howDays = getHowDaysFromBirthday(birthday,date);
//Log.v("tag",""+howDays);
if (howDays <= 0) {
return;
}
else {
for (int i = -15; i<= 15; i++){
Calendar calendar = Calendar.getInstance();
calendar.set(mYear, mMonth, mDay);
int a_physical = (int)(howDays + i) % 23;
physical[i+15] = getY(a_physical,23);
int a_mood = (int)((howDays + i) % 28);
mood[i+15] = getY(a_mood,28);
int a_brains = (int)((howDays + i) % 33);
brains[i+15] = getY(a_brains,33);
calendar.add(Calendar.DATE,+i);
xLabel[i+15] = String.valueOf(calendar.get(Calendar.DAY_OF_MONTH));
calendar.clear();
}
TextView tvp = (TextView) findViewById(R.id.today_physical);
tvp.setText(String.valueOf(savetwoY(physical[15])));
TextView tvm = (TextView) findViewById(R.id.today_mood);
tvm.setText(String.valueOf(savetwoY(mood[15])));
TextView tvb = (TextView) findViewById(R.id.today_brains);
tvb.setText(String.valueOf(savetwoY(brains[15])));
List<double[]> data = new ArrayList<>();
List<Integer> color = new ArrayList<>();
data.add(brains);
color.add(R.color.color13);
data.add(mood);
color.add(R.color.color14);
data.add(physical);
color.add(R.color.colorPrimary);
customCurveChart1.removeAllViews();
customCurveChart1.addView(new CustomCurveChart(this, xLabel, yLabel, data, color, false));
}
}
计算总天数,正弦函数转换
private long getHowDaysFromBirthday(String from, String to) {
if (from == null || to == null || to.equals("") || from.equals("")) {
return -1;
}
try {
Date date1 = formatter.parse(from);
Date date2 = formatter.parse(to);
long howDays = (date2.getTime()-date1.getTime())/(60*60*1000*24);
return howDays;
} catch (Exception e) {
return 0;
}
}
private double getY (int phase, int cycle){
double y = Math.sin(2 * Math.PI / cycle * (phase)) * 50 + 50;
return y;
}
整个项目代码已上传至github:CurveChartTest