当前位置: > 股票>正文

Android折线图,柱状图,股票走势图,基金走势图

2023-07-18 12:51:39 互联网 未知 股票

Android折线图,柱状图,股票走势图,基金走势图

相信折线图大家都不陌生,有些数据统计,基金股票都是通过通过折线图的方式去展示数据,接下来就介绍一种方法,去通过代码编写一个类似的功能。

首先看一下效果图

编写之前要了解一下怎么样去入手,首先从界面出发,看似复杂的一张折线图,如果放大就会发现其实是有一条条长度、大小不一的直线拼凑而成

在代码中直线的绘制比较简单了,一句代码而已,参数分别为 起始 x、y坐标和结束 x、y 坐标 通过一组组不同的数据不就能拼凑成一张看似复杂的折线了吗,艾玛,讲完了。

其实这里面还是有许多需要注意的地方的,不妨接着看下去。

上面讲完了折线,再讲一下折线下的阴影部分,其实这也没有太复杂,只是不同的绘画,同折线频率一样,一次次拼凑而成。实际中间空隙是不存在的,当然也要看代码中怎么写了,这里添加空隙是为了更直观些。 阴影部分的代码部分也不是很复杂。。和直线差不多,就是需要四条线去画出范围,然后通过 .close() 方法将范围内进行填充 以上就是对界面的解析,接下来是对逻辑的解析。

通过上面的解析图可以看出,每次画线和画背景的时候,下一次的开始坐标都是上一次的结束坐标,这也说明每次数据更新时只需要一组 x、y 数据即可,所以在计算时只需拿到这组数据就行,首先要建一个实体类了 entity,来定义一下 x、y 坐标,这里只写了需要用到的数据。

因为数据展示一般都是即时展示,比如股票、基金,目前股票是三秒进行一次数据刷新,每次刷新都进行一次 onDraw() 进行绘画,就形成了我们看到的分时图实时刷新的效果,这里通过线程每一秒进行一次数据刷新达到类似效果。

因为数据是上下波动的,这里通过随机数的形式进行数据伪造。 要明白一点,折线图是一直向前展示的,所以 X 轴是一直比上一次的数据要大的(如果是反向折线图,那相反),数据也要尽可能与我们的界面相配合,不能说我们的界面高度为 100,你给我的数据是 200,那界面不就混乱了吗,需要对返回的数据进行适配,比如说股票是有涨停与跌停的,当达到某极限值时设置Y轴为当前界面最大值即可。或者规定给我的数据在我界面的承受范围内,在此基础上进行改造。

数据有了,接下来就要进行绘制了,将折线数据给折线View之后,拿到数据之后进行界面重新绘制,这里注意一下哦,不是讲过下一直线的起始坐标为上个直线的结束坐标么,第一条直线的坐标呢,他前面似乎没有直线,不要把第一条线的起始坐标设置为 ( 0,0 )哦,否则你会发现一开始会有一个飞流直下的线,那咋办,还没开始结束了。 你可以把第一条直线想想成一个点,因为最开始是从没有数据到有了第一条数据,那这个第一条数据是开始也是结束。 具体表现在代码中如下: 直线完成了,背景部分也差不多,这里我将背景单独拿出来,根据需求进行判断是否绘制,和其他参数的修改,具体表现在: 这里不用担心,单独设置之后会不会有效果,因为在赋值之后有一个刷新操作,会重新拿起设置的这些值。

为了更直观些,将折线下背景逻辑画出来,加深一下印象,从第一个坐标开始,到第二个,第三个,第四个,最后别忘了回到第一个,然后将该范围内进行颜色填充,就形成了印象部分

以上就是走势图的大体逻辑,接下来将源码贴上,供需要的同学进行参考

目录结构 MainActivity

/** *注释: *分时图绘画 */public class MainActivity extends AppCompatActivity { //存放数据的容器 private ArrayList mTimeList = new ArrayList(); private TimeView tv_view; int startX = 0; boolean isSetData = false;//是否添加数据开关 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取控件 tv_view = findViewById(R.id.tv_view); tv_view.setViewColor(Color.YELLOW,Color.GRAY,R.color.purple_200); tv_view.setShowBgBottom(false); tv_view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { isSetData = !isSetData; } }); //开启线程,每一秒都去设置分时图数据 thread.start(); } @RequiresApi(api = Build.VERSION_CODES.N) private void initData(){ //模拟数据 TimeViewEntity t = new TimeViewEntity(); //设置X轴数据的终止位置,无需设置起始位置,因为每条线的起始位置就是上一条线的终点位置 int stopX = new SplittableRandom().nextInt(startX, startX+10); startX = stopX; t.setStopX(startX); //设置Y轴数据的终止位置,无需设置起始位置,因为每条线的起始位置就是上一条线的终点位置 Random ra = new Random(); int stopY = ra.nextInt(tv_view.getMeasuredHeight()/2); t.setStopY(stopY); //给分时图设置数据 mTimeList.add(t); tv_view.setViewData(mTimeList); } /** * 通过线程来动态设置View达到动画效果 * */ private final Thread thread = new Thread(){ @RequiresApi(api = Build.VERSION_CODES.N) @Override public void run() { while(true){ try { //通过此开关进行伪停止添加数据 if (isSetData){ initData(); } //如果数据终止X的值大于界面宽度停止线程或者其他操作 if (mTimeList.size() > 0 && mTimeList.get(mTimeList.size()-1).getStopX() > tv_view.getMeasuredWidth()){ //清除容器数据,重新添加 startX = 0; mTimeList.clear(); //thread.stop(); //终止线程 } /**休息时间*/ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } };}

TimeView

/** * 作者:zch * 时间:2023/3/18 9:37 * 描述:自定义分时图View */public class TimeView extends View { private Paint paint; private int mCanvasHeight; private int mCanvasWidth; private int mStartY; private int paintColor = 0; private int canvasColor = 0; private int bgColor = 0; private boolean isShowBg = false; private ArrayList mTimeList = new ArrayList(); public TimeView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } //开始绘画逻辑 @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //首先定义画笔 paint = new Paint(); //防锯齿 paint.setAntiAlias(true); //获取画板高度 mCanvasHeight = getMeasuredHeight(); //获取画板宽度 mCanvasWidth = getMeasuredWidth(); //设置画笔颜色 paint.setColor(paintColor == 0 ? Color.YELLOW : paintColor); //设置画板背景 canvas.drawColor(canvasColor == 0 ? Color.GRAY : canvasColor); //设置画笔粗细 paint.setStrokeWidth((float)3); //Y轴的起止都在折线图的四分之一处开始,因为数据的范围是折线图的二分之一 //这样数据波动位置就处于折线图居中位置 mStartY = mCanvasHeight / 4; //画线 drawView(canvas); } /** *注释: *绘画逻辑 */ private void drawView(Canvas canvas){ //如果有数据 if (mTimeList.size() > 0){ int startX = 0,startY = 0; int stopX,stopY; for (int i = 0; i startX = stopX; startY = stopY; } //画线 canvas.drawLine(startX,startY,stopX,stopY,paint); //是否画背景 if (isShowBg){ setDrawBg(startX,startY,stopX,stopY,canvas); } //下次画线的时候的起始位置等于上次画线位置的终止位置 startX = stopX; startY = stopY; } } } /** *注释: * 画折线下背景 */ private void setDrawBg(int tx,int ty,int px,int py,Canvas canvas){ //设置画笔 Paint paint = new Paint(); //防锯齿 paint.setAntiAlias(true); //设置颜色 paint.setColor(bgColor == 0 ? Color.WHITE : bgColor); //画阴影部分 Path bg = new Path(); bg.moveTo(tx, ty); bg.lineTo(tx, mCanvasHeight); bg.lineTo(px, mCanvasHeight); bg.lineTo(px, py); bg.lineTo(tx, ty); bg.close(); //添加到画板上 canvas.drawPath(bg, paint); } /** *注释: * 设置分数图数据,由外部传输 */ public void setViewData(ArrayList m) { this.mTimeList = m; //刷新界面 - 无需在UI线程,在工作线程即可被调用,invalidate()必须在UI线程 postInvalidate(); } /** *注释: *设置分时图背景和画笔颜色 * p - 画笔颜色 * c - 背景颜色 * b - 折线下背景颜色 */ public void setViewColor(int p,int c,int b){ this.paintColor = p; this.canvasColor = c; this.bgColor = b; } /** *注释: * 是否显示折线下的背景 */ public void setShowBgBottom(boolean b){ this.isShowBg = b; }}

TimeViewEntity

/** * 作者:zch * 时间:2023/3/18 10:04 * 描述:分时图数据类 */public class TimeViewEntity { private int stopX; private int stopY; public int getStopX() { return stopX; } public void setStopX(int stopX) { this.stopX = stopX; } public int getStopY() { return stopY; } public void setStopY(int stopY) { this.stopY = stopY; }}

activity_main

以上就是走势图基本用法,千篇一律,下面是在以上基础上做了一些改动,看一下效果图:

这里就不贴代码了,代码写法与上面的基本相似,全部代码上传到 资源了,免C币下载,需要的去下载吧。。 传送门

版权声明: 本站仅提供信息存储空间服务,旨在传递更多信息,不拥有所有权,不承担相关法律责任,不代表本网赞同其观点和对其真实性负责。如因作品内容、版权和其它问题需要同本网联系的,请发送邮件至 举报,一经查实,本站将立刻删除。