Android自定义View——实现理财类APP七日年化收益折线图效果
2016-07-13 18:37
711 查看
这段时间的自定义View学习,学会了绘制柱状图、绘制折线图、绘制进度控件,那我们今天就来聊聊另外一种自定义的View,这就是我们常见的七日年化收益折线图效果。先看看长什么样。
这就是效果图了,元素相对而言还是比较多的,这里有线、柱状图、文字、折线、点等等。看起来好像很复杂,但是呢,只要一步一步的实现,那还是可以达到这种效果的,之前我们说过的, 自定义View,就像是在photo shop里面画图,想要什么就画什么,我们可以有很多的画笔工具,也可以有很多的图层。
先看看我们这一次用到哪些变量。
注释标记的也是够详细了,为了大家能够看得懂,也为了提高的博客质量,我们注意到,这里有文字,有数量,基本涵盖了我们这里索要用到的所有的变量。
下面开始初始化操作。
这里主要就是给画笔初始化,可以看到每一个画笔的颜色、宽度都是不一样的,值的注意的是,这里面的画笔并没有设置镂空样式。
接下来我们看看怎么去赋值,老规矩,我们还是选择在onSizeChange()里面进行赋值,代码如下:
跟之前的不一样,我们以前所要用的宽度跟高度,直接就是使用方法里的,但是现在我们没有这么做,例如:(float)(getWidth()-getWidth()*0.1);我们进行了一定的处理,这样可以提高页面的舒适性,提高用户体验。
好了,准备工作做好了,接下来看看onDraw方法里面的操作,代码如下:
哟呵,怎么这么简单,就三个东西?对的,就是这么简单粗暴,从名字中也可以看出,第一个是绘制矩形,第二个绘制线,第三个就是绘制折线。是不是很快呢,下面看看具体的实现方式。
第一个方法:
第二个:
这里的代码相对较多,我专门加了许多的注释,可以用心的看看。
第三个绘制折线:
这里的绘制折线包括绘制线、点、文字、还有文字的转换、但是这个转换可以根据自己的需求来进行定制。
最后向外面暴露一个方法,用于更新坐标。
文字的转换我这里用一个自己的类去处理了,代码如下:
以上就是逻辑的实现过程了。最后,我把所有代码贴上来:
AnnualyieldView.java
MainActivity.java
布局文件activity_main.xml:
还有一个用于转换的类,Math.java
以上就是代码的全部内容,我记得我大学的老实说,不懂的地方就自己多敲代码,多了就懂了,虽然那时候我不认同,但是现在觉得还是有一定道理,都是一样过来的,现在希望能够跟大家一起进步。
最后我附上源码:
这就是效果图了,元素相对而言还是比较多的,这里有线、柱状图、文字、折线、点等等。看起来好像很复杂,但是呢,只要一步一步的实现,那还是可以达到这种效果的,之前我们说过的, 自定义View,就像是在photo shop里面画图,想要什么就画什么,我们可以有很多的画笔工具,也可以有很多的图层。
先看看我们这一次用到哪些变量。
private Paint mTextPaint, mLinePaint,mPathPaint,mPointPaint; //柱状图的宽度 private float mPaintRectWidth; //路径 private Path mPath; //高跟宽 private float mWidth, mHeight; //柱状图的数量 private final float mCount = 6; //偏移量 private final float offsets=1; private float mRectHeight; //x轴的坐标 private List<Float> xline=new ArrayList<Float>(); //Y轴的坐标 private List<Float> yline=new ArrayList<Float>(); //左边文字 private float []x={2.46f,2.45f,2.44f,2.43f,2.42f,2.41f,2.40f}; //底部文字 private String [] day={"07-01","07-02","07-03","07-04","07-05","07-06","07-07"};
注释标记的也是够详细了,为了大家能够看得懂,也为了提高的博客质量,我们注意到,这里有文字,有数量,基本涵盖了我们这里索要用到的所有的变量。
下面开始初始化操作。
private void initView() { //绘制线和文字的颜色 mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setColor(Color.parseColor("#cccccc")); mTextPaint.setTextSize(25); mTextPaint.setStrokeWidth(1); //绘制折线图的点 mPointPaint= new Paint(); mPointPaint.setAntiAlias(true); mPointPaint.setColor(Color.parseColor("#000000")); mPointPaint.setTextSize(25); mPointPaint.setStrokeWidth(5); //绘制柱状图的画笔 mLinePaint = new Paint(); mLinePaint.setAntiAlias(true); //绘制折线图的画笔 mPathPaint= new Paint(); mPathPaint.setAntiAlias(true); mPathPaint.setColor(Color.parseColor("#ff0000")); mPathPaint.setStyle(Style.STROKE); //折线图的路径 mPath=new Path(); }
这里主要就是给画笔初始化,可以看到每一个画笔的颜色、宽度都是不一样的,值的注意的是,这里面的画笔并没有设置镂空样式。
接下来我们看看怎么去赋值,老规矩,我们还是选择在onSizeChange()里面进行赋值,代码如下:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth=(float)(getWidth()-getWidth()*0.1); mHeight=(float)(getHeight()-getHeight()*0.1); mRectHeight=(float)(getHeight()-getHeight()*0.1); mPaintRectWidth=(float) (mWidth*0.8/mCount); mLinePaint.setStrokeWidth(mPaintRectWidth); }
跟之前的不一样,我们以前所要用的宽度跟高度,直接就是使用方法里的,但是现在我们没有这么做,例如:(float)(getWidth()-getWidth()*0.1);我们进行了一定的处理,这样可以提高页面的舒适性,提高用户体验。
好了,准备工作做好了,接下来看看onDraw方法里面的操作,代码如下:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); onDrawRect(canvas); onDrawLine(canvas); canvasPath(canvas); }
哟呵,怎么这么简单,就三个东西?对的,就是这么简单粗暴,从名字中也可以看出,第一个是绘制矩形,第二个绘制线,第三个就是绘制折线。是不是很快呢,下面看看具体的实现方式。
第一个方法:
//绘制6个矩形 private void onDrawRect(Canvas canvas) { for (int i = 0; i < 7; i++) { if (i%2==0) { mLinePaint.setColor(Color.parseColor("#eeeeee")); }else { mLinePaint.setColor(Color.parseColor("#ece1f3")); } float left =(float) (mWidth * 0.4 / 2 + mPaintRectWidth * i + offsets); float right=(float) (mWidth * 0.4 / 2 + mPaintRectWidth* (i + 1)); canvas.drawRect(left,(float)(mRectHeight*0.01),right, mHeight, mLinePaint); } }
第二个:
//绘制网格线 private void onDrawLine(Canvas canvas){ //第一条线 canvas.drawLine(mPaintRectWidth-mPaintRectWidth/2, (float)(mRectHeight*0.01), getWidth(), (float)(mRectHeight*0.01), mTextPaint); //定义这里高度 float height; //横七条 for (float i = 0; i < 7; i++) { //从上到下 if (i==0) { height=i; }else { height=mRectHeight*(i/6); float size=mTextPaint.measureText(x[(int)i]+""); //绘制线 canvas.drawLine(mPaintRectWidth+mPaintRectWidth/2, height, getWidth(), height, mTextPaint); //绘制左边Y轴的文字 canvas.drawText(x[(int)i]+"", (float)(mPaintRectWidth-mPaintRectWidth*0.35), height+size/5, mTextPaint); } } //竖七条 canvas.drawLine((float) (mPaintRectWidth-mPaintRectWidth/2),0, (float) (mPaintRectWidth-mPaintRectWidth/2), mHeight, mTextPaint); for (float i = 0; i < 7; i++) { //从左到右 canvas.drawLine((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i),0, (float) (mWidth * 0.4 / 2 + mPaintRectWidth * i), mHeight, mTextPaint); //绘制底边的日期文字 canvas.drawText(day[(int) i], (float) (mWidth * 0.34 / 2 + mPaintRectWidth * i), (float)(mHeight+mHeight*0.1), mTextPaint); //准备好下面折线图的X轴坐标 xline.add((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i)); } //折线图的第一个点 xline.add((float) (mPaintRectWidth-mPaintRectWidth/2)); }
这里的代码相对较多,我专门加了许多的注释,可以用心的看看。
第三个绘制折线:
//绘制折线路径 public void canvasPath(Canvas canvas){ for (int j = 0; j < yline.size(); j++) { float x=xline.get(j); float y =yline.get(j); float aftery=Math.initData(y); if (j==0) { mPath.moveTo(x,aftery ); }else{ mPath.lineTo(x,aftery ); } canvas.drawPoint(x, aftery, mPointPaint); float size=mPointPaint.measureText(y+""); canvas.drawText(y+"", (float)(x-size/2), (float)(aftery+size*0.25), mPointPaint); } canvas.drawPath(mPath, mPathPaint); }
这里的绘制折线包括绘制线、点、文字、还有文字的转换、但是这个转换可以根据自己的需求来进行定制。
最后向外面暴露一个方法,用于更新坐标。
//用于设置Y轴的坐标值 public void setDataY( List<Float> yline) { this.yline.clear(); this.yline=yline; } //一个更新UI的方法 public void invalidata(){ invalidate(); }
文字的转换我这里用一个自己的类去处理了,代码如下:
public static float initData(float a){ if (2.40f<=a&&a<2.41f) { a=540f-540f/(a/0.01f); }else if(2.41f<=a&&a<2.42f){ a=480f-480f/(a/0.01f); }else if (2.42f<=a&&a<2.43f) { a=360f-360f/(a/0.01f); }else if (2.43f<=a&&a<2.44f) { a=270f-270f/(a/0.01f); }else if (2.44f<=a&&a<2.45f) { a=180f-180f/(a/0.01f); }else if (2.45f<=a&&a<2.46f) { a=90f-90f/(a/0.01f); } return a; }
以上就是逻辑的实现过程了。最后,我把所有代码贴上来:
AnnualyieldView.java
/**
* 小瓶盖 2016年7月13日18:08:28
*
* @author Android自定义View——实现理财类APP七日年化收益折线图效果
*
*相关博客地址 http://blog.csdn.net/qq_25193681 */
public class AnnualyieldView extends View {
private Paint mTextPaint, mLinePaint,mPathPaint,mPointPaint;
//柱状图的宽度
private float mPaintRectWidth;
//路径
private Path mPath;
//高跟宽
private float mWidth, mHeight;
//柱状图的数量
private final float mCount = 6;
//偏移量
private final float offsets=1;
private float mRectHeight;
//x轴的坐标
private List<Float> xline=new ArrayList<Float>();
//Y轴的坐标
private List<Float> yline=new ArrayList<Float>();
//左边文字
private float []x={2.46f,2.45f,2.44f,2.43f,2.42f,2.41f,2.40f};
//底部文字
private String [] day={"07-01","07-02","07-03","07-04","07-05","07-06","07-07"};
public AnnualyieldView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public AnnualyieldView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public AnnualyieldView(Context context) {
super(context);
initView();
}
private void initView() { //绘制线和文字的颜色 mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setColor(Color.parseColor("#cccccc")); mTextPaint.setTextSize(25); mTextPaint.setStrokeWidth(1); //绘制折线图的点 mPointPaint= new Paint(); mPointPaint.setAntiAlias(true); mPointPaint.setColor(Color.parseColor("#000000")); mPointPaint.setTextSize(25); mPointPaint.setStrokeWidth(5); //绘制柱状图的画笔 mLinePaint = new Paint(); mLinePaint.setAntiAlias(true); //绘制折线图的画笔 mPathPaint= new Paint(); mPathPaint.setAntiAlias(true); mPathPaint.setColor(Color.parseColor("#ff0000")); mPathPaint.setStyle(Style.STROKE); //折线图的路径 mPath=new Path(); }
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth=(float)(getWidth()-getWidth()*0.1);
mHeight=(float)(getHeight()-getHeight()*0.1);
mRectHeight=(float)(getHeight()-getHeight()*0.1);
mPaintRectWidth=(float) (mWidth*0.8/mCount);
mLinePaint.setStrokeWidth(mPaintRectWidth);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
onDrawRect(canvas);
onDrawLine(canvas);
canvasPath(canvas);
}
//绘制6个矩形
private void onDrawRect(Canvas canvas) {
for (int i = 0; i < 7; i++) {
if (i%2==0) {
mLinePaint.setColor(Color.parseColor("#eeeeee"));
}else {
mLinePaint.setColor(Color.parseColor("#ece1f3"));
}
float left =(float) (mWidth * 0.4 / 2 + mPaintRectWidth * i + offsets);
float right=(float) (mWidth * 0.4 / 2 + mPaintRectWidth* (i + 1));
canvas.drawRect(left,(float)(mRectHeight*0.01),right, mHeight, mLinePaint);
}
}
//绘制网格线
private void onDrawLine(Canvas canvas){
//第一条线
canvas.drawLine(mPaintRectWidth-mPaintRectWidth/2, (float)(mRectHeight*0.01), getWidth(), (float)(mRectHeight*0.01), mTextPaint);
//定义这里高度
float height;
//横七条
for (float i = 0; i < 7; i++) {
//从上到下
if (i==0) {
height=i;
}else {
height=mRectHeight*(i/6);
float size=mTextPaint.measureText(x[(int)i]+"");
//绘制线
canvas.drawLine(mPaintRectWidth+mPaintRectWidth/2, height, getWidth(), height, mTextPaint);
//绘制左边Y轴的文字
canvas.drawText(x[(int)i]+"", (float)(mPaintRectWidth-mPaintRectWidth*0.35), height+size/5, mTextPaint);
}
}
//竖七条
canvas.drawLine((float) (mPaintRectWidth-mPaintRectWidth/2),0, (float) (mPaintRectWidth-mPaintRectWidth/2), mHeight, mTextPaint);
for (float i = 0; i < 7; i++) {
//从左到右
canvas.drawLine((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i),0, (float) (mWidth * 0.4 / 2 + mPaintRectWidth * i), mHeight, mTextPaint);
//绘制底边的日期文字
canvas.drawText(day[(int) i], (float) (mWidth * 0.34 / 2 + mPaintRectWidth * i), (float)(mHeight+mHeight*0.1), mTextPaint);
//准备好下面折线图的X轴坐标
xline.add((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i));
}
//折线图的第一个点
xline.add((float) (mPaintRectWidth-mPaintRectWidth/2));
}
//绘制折线路径
public void canvasPath(Canvas canvas){
for (int j = 0; j < yline.size(); j++) {
float x=xline.get(j);
float y =yline.get(j);
float aftery=Math.initData(y);
if (j==0) {
mPath.moveTo(x,aftery );
}else{
mPath.lineTo(x,aftery );
}
canvas.drawPoint(x, aftery, mPointPaint);
float size=mPointPaint.measureText(y+"");
canvas.drawText(y+"", (float)(x-size/2), (float)(aftery+size*0.25), mPointPaint);
}
canvas.drawPath(mPath, mPathPaint);
}
//用于设置Y轴的坐标值
public void setDataY( List<Float> yline) {
this.yline.clear();
this.yline=yline;
}
//一个更新UI的方法
public void invalidata(){
invalidate();
}
}
MainActivity.java
/** * 小瓶盖 2016年7月13日18:08:28 * * @author Android自定义View——实现理财类APP七日年化收益折线图效果 * *相关博客地址 http://blog.csdn.net/qq_25193681 */ public class MainActivity extends Activity { private AnnualyieldView annualyieldView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); annualyieldView=(AnnualyieldView) findViewById(R.id.line); initdata(); } private void initdata() { List<Float> yline=new ArrayList<Float>(); yline.add(2.420123f); yline.add(2.444122f); yline.add(2.45359f); yline.add(2.4206f); yline.add(2.4357f); yline.add(2.4228f); yline.add(2.4350f); annualyieldView.setDataY(yline); } }
布局文件activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.annualyield.MainActivity" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="10dip" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#888888" android:textSize="18sp" android:text="七日年化收益率(%)" /> <com.example.annualyield.AnnualyieldView android:id="@+id/line" android:layout_width="match_parent" android:layout_height="200dip" android:layout_marginTop="10dip" android:layout_marginBottom="10dip" /> </LinearLayout> </RelativeLayout>
还有一个用于转换的类,Math.java
/** * 小瓶盖 2016年7月13日18:08:28 * * @author Android自定义View——实现理财类APP七日年化收益折线图效果 * *相关博客地址 http://blog.csdn.net/qq_25193681 */ public class Math { public static float initData(float a){ if (2.40f<=a&&a<2.41f) { a=540f-540f/(a/0.01f); }else if(2.41f<=a&&a<2.42f){ a=480f-480f/(a/0.01f); }else if (2.42f<=a&&a<2.43f) { a=360f-360f/(a/0.01f); }else if (2.43f<=a&&a<2.44f) { a=270f-270f/(a/0.01f); }else if (2.44f<=a&&a<2.45f) { a=180f-180f/(a/0.01f); }else if (2.45f<=a&&a<2.46f) { a=90f-90f/(a/0.01f); } return a; } }
以上就是代码的全部内容,我记得我大学的老实说,不懂的地方就自己多敲代码,多了就懂了,虽然那时候我不认同,但是现在觉得还是有一定道理,都是一样过来的,现在希望能够跟大家一起进步。
最后我附上源码:
相关文章推荐
- 小米推送收不到通知
- MUI移动端页面跳转
- android杀死进程
- 干货分享,iOS日志颜色分类 丰富你的控制台 简直不要太好用 墙裂推荐
- Android4.2中应用接收开机广播(android.intent.action.BOOT_COMPLETED)失败的原因
- Android.mk中引用第3方动态库
- 【Android】MediaRecorder/MediaPlayer实现录音与播放录音
- android ndk开发爬坑之无法解析的符号
- android 开发连接真机录制视频(转GIF,方便演示)
- Android基础知识---EditView属性名称及描述
- Android如何正确获得View的宽和高
- Android的资源类型之Drawable
- ios 音视频实现边播边缓存的思路和解决方案 (转)
- 手机APP开发之车牌识别SDK移植
- iOS-沙盒机制
- Android6.0系统获getMacAddress()取Wifi和蓝牙Mac地址返回02:00:00:00:00:00解决办法
- [Android5.1]ContentProvider的Binder通信分析
- Android源代码分析--Preference之自动通话录音
- Android.util.Log 关于Android开发中打印log
- php判断网页 是否是 Android webview加载