android 股票K线图

简介: 现在在手上的是一个证券资讯类型的app,其中有涉及到股票行情界面,行情中有K线图等,看到网上很多人在求这方面的资料,所以我特地写了一个demo在此处给大家分享一下。 下面是做出来的效果图: 这个 界面 是如何画出来的我就不做介绍了,大家可以去下载项目源码。 背景图是利用canvas先画出一个矩形,然后再画几根虚线,均线图

现在在手上的是一个证券资讯类型的app,其中有涉及到股票行情界面,行情中有K线图等,看到网上很多人在求这方面的资料,所以我特地写了一个demo在此处给大家分享一下。

下面是做出来的效果图:




这个 界面 是如何画出来的我就不做介绍了,大家可以去下载项目源码。

背景图是利用canvas先画出一个矩形,然后再画几根虚线,均线图是通过path来绘制的,总之图的绘制是很简单的,我就不在这里作介绍了,大家可以去github下载源码看看。涉及到均线、最高价、最低价、收盘价、开盘价的概念大家可以百度一下。

我再这里要介绍的是计算问题:

大家可以看到分时图、日K、月K的左边的成交价格都是不一样的,而我们的k线都是通过这个价格来绘制的,也就是说价格是时刻变动,那么我们的k线绘制也是变动的。假设我们要计算分时图中价格为25.69的那一分钟应该如何画,画在屏幕中的哪一个位置,那么这个应该怎么画呢,价格是变动的,画的位置也是变动的,但是有一点我们屏幕的大小是不变的。所以我们可以通过背景图的高度来计算某个价格的线图应该从哪个地方开始画。我们可以计算出一个像素点对应多少个价格,分析图如下:

价格和像素形成个一个比例计算是:double   heightScale = (endY - startY)/(highPrice - lowPrice);

所以价格25.69应该是画在mStartY = (float) (startY+ (highPrice - 25.69) * heightScale);

这个明白了之后其他的原理都是一样的,我就不介绍了,下面是部分代码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     protected void drawKChatBackGround() {  
  3.         Rect dirty = new Rect(left, kChartTop, right, KChartbottom);  
  4.         // 画背景图的矩形  
  5.         mCanvas.drawRect(dirty, LineGrayPaint);  
  6.         PathEffect effects = new DashPathEffect(new float[] { 5555 }, 1);  
  7.         LineGrayPaint.setPathEffect(effects);  
  8.         Path path = new Path();  
  9.         int y = kChartTop + 15;  
  10.         // 画上面的虚线  
  11.         path.moveTo(left, y );  
  12.         path.lineTo(right, y );  
  13.         String text = getPriceText(highPrice);  
  14.         int textHeight = (int) (textGrayPaint.descent() - textGrayPaint.ascent());  
  15.         mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2 ,textGrayPaint);  
  16.         double max = highPrice - lowPrice;  
  17.         if (max > 10){  
  18.             // 分成四等分  
  19.             // 画中间的三根虚线  
  20.             int n = 4;  
  21.             double sper = (highPrice - lowPrice) / 4;// 每一等分代表的价格  
  22.             for(int i=1;i<n;i++){  
  23.                 y  =  i*((KChartbottom - kChartTop)/n) + kChartTop;  
  24.                 path.moveTo(left, y);  
  25.                 path.lineTo(right,y);  
  26.                 text = getPriceText(highPrice - i*sper);  
  27.                 mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);  
  28.             }  
  29.         }else{  
  30.             // 分成两等分  
  31.             // 画中间的虚线  
  32.             y = (KChartbottom - kChartTop)/2 + kChartTop;  
  33.             path.moveTo(left, y);  
  34.             path.lineTo(right, y);  
  35.             text = getPriceText(highPrice - (highPrice - lowPrice) / 2);  
  36.             mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);  
  37.         }  
  38.         // 画下面的虚线  
  39.         y = KChartbottom - 15;  
  40.         path.moveTo(left, y);  
  41.         path.lineTo(right, y);  
  42.         text = getPriceText(lowPrice);  
  43.         mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2,textGrayPaint);  
  44. //      // 画等分的虚线和下面的日期  
  45.         for (int i = num - 1; i > 0; i--) {  
  46.             int x = left + perWidth * i;  
  47.             path.moveTo(x, kChartTop);  
  48.             path.lineTo(x, KChartbottom);  
  49.             perXPoint[i - 1] = x;  
  50.         }  
  51.         mCanvas.drawPath(path, LineGrayPaint);  
  52.     }  

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     protected void drawMAChart() {  
  3.         // 画均线  
  4.         Path path5 = new Path();  
  5.         Path path10 = new Path();  
  6.         Path path20 = new Path();  
  7.         double heightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice);  
  8.         int maStart = left;  
  9.         float maStartY;  
  10.         path5.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue5()) * heightScale));  
  11.         path10.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue10()) * heightScale));  
  12.         path20.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue20()) * heightScale));  
  13.           
  14.         for(SingleStockInfo info:infos){  
  15.             maStart += per * perHalf;// 每一天实际所占的数据是4/6,左右边距各1/6   
  16.             maStartY = (float) (kChartTop + (highPrice - info.getMaValue5()) * heightScale);  
  17.             path5.lineTo(maStart, maStartY);  
  18.             maStartY = (float) (kChartTop + (highPrice - info.getMaValue10()) * heightScale);  
  19.             path10.lineTo(maStart, maStartY);  
  20.             maStartY = (float) (kChartTop + (highPrice - info.getMaValue20()) * heightScale);  
  21.             path20.lineTo(maStart, maStartY);  
  22.             maStart += per * perHalf;  
  23.         }  
  24.           
  25.         Paint paint = new Paint();  
  26.         paint.setColor(Color.BLUE);  
  27.         paint.setAntiAlias(true);  
  28.         paint.setStrokeWidth(2);  
  29.         paint.setStyle(Style.STROKE);  
  30.         mCanvas.drawPath(path5, paint);  
  31.         paint.setColor(Color.MAGENTA);  
  32.         mCanvas.drawPath(path10, paint);  
  33.         paint.setColor(Color.GREEN);  
  34.         mCanvas.drawPath(path20, paint);  
  35.     }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 下面的柱形图 
  3.      */  
  4.     @Override  
  5.     protected void drawPillarsChart(int flag) {  
  6.         LineGrayPaint.setPathEffect(null);  
  7.         Rect dirty = new Rect(left, pillarsChartTop, right, pillarsChartbottom);  
  8.         // 画背景图的矩形  
  9.         mCanvas.drawRect(dirty, LineGrayPaint);  
  10.           
  11.         int y = pillarsChartTop + (pillarsChartbottom - pillarsChartTop)/2;  
  12.         mCanvas.drawLine(left,y,right, y, LineGrayPaint);  
  13.           
  14.         // 中间的值  
  15.         String totalCount = getPriceText(maxCount/2/10000);  
  16.         float maginLeft = left - textGrayPaint.measureText(totalCount)- 5;  
  17.         mCanvas.drawText(totalCount, maginLeft, y,textGrayPaint);  
  18.         // 上面的值  
  19.         totalCount = getPriceText(maxCount/10000);  
  20.         maginLeft = left - textGrayPaint.measureText(totalCount)- 5;  
  21.         mCanvas.drawText(totalCount, maginLeft, pillarsChartTop,textGrayPaint);  
  22.         // 下面的值  
  23.         totalCount = "万手";  
  24.         maginLeft = left - textGrayPaint.measureText(totalCount) - 5;  
  25.         mCanvas.drawText(totalCount, maginLeft, pillarsChartbottom,textGrayPaint);  
  26.         int pStart = left;  
  27.         float pStartY;  
  28.         double heightScale = (pillarsChartbottom - pillarsChartTop)/maxCount;  
  29.         Paint paint = new Paint();  
  30.         paint.setAntiAlias(true);  
  31.         paint.setStyle(Paint.Style.FILL);  
  32.         if (flag == StockService.FLAG){  
  33.             for(MinuteInfo info:minuteInfos){  
  34.                 pStart += per * per16;// 每一天实际所占的数据是4/6,加上1/6  
  35.                 pStartY = (float) (pillarsChartTop + (maxCount - info.getVolume()) * heightScale);  
  36.                 dirty = new Rect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2);  
  37.                 paint.setColor(info.getColor());  
  38.                 // 画背景图的矩形  
  39.                 mCanvas.drawRect(dirty, paint);  
  40.                 pStart += per * per56;// 右边的间距 5/6  
  41.             }  
  42.         }else{  
  43.             for(SingleStockInfo info:infos){  
  44.                 pStart += per * per16;// 每一天实际所占的数据是4/6,加上1/6  
  45.                 pStartY = (float) (pillarsChartTop + (maxCount - info.getTotalCount()) * heightScale);  
  46.                 dirty = new Rect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2);  
  47.                 paint.setColor(info.getColor());  
  48.                 // 画背景图的矩形  
  49.                 mCanvas.drawRect(dirty, paint);  
  50.                 pStart += per * per56;// 右边的间距 5/6  
  51.             }  
  52.         }  
  53.     }  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 分时图 
  3.      */  
  4.     @Override  
  5.     public void drawHoursChart(){  
  6.         double heightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice);  
  7.         int cLeft = left;  
  8.         int cTop = 0;  
  9.         Path path = new Path();  
  10.         path.moveTo(cLeft, KChartbottom-2);  
  11.         int position = 0;  
  12.         int perPointX = perXPoint[position];// 记录第一条垂直虚线的x坐标  
  13.         for(MinuteInfo info:minuteInfos){  
  14.             cLeft += per * per16;  
  15.             cTop = (int) (kChartTop + (highPrice - info.getNow()) * heightScale);  
  16.             path.lineTo(cLeft + per * per26, cTop);  
  17.             if (cLeft >= perPointX){  
  18.                 // 恰好画到第一条垂直虚线的地方,需要画下面的时间  
  19.                 String text = KChartUtil.getMinute(info.getMinute());  
  20.                 float textWidth = textGrayPaint.measureText(text);  
  21.                 int textHeight = (int) (textGrayPaint.descent()- textGrayPaint.ascent());  
  22.                 mCanvas.drawText(text, perPointX - textWidth/2, KChartbottom + textHeight, textGrayPaint);  
  23.                 if (!(position == perXPoint.length-1)){  
  24.                     Log.e(TAG, perPointX+"----------"+info.getMinute()+"---"+text);  
  25.                     perPointX = perXPoint[++position];  
  26.                 }  
  27.             }  
  28.             cLeft += per * per56;// 右边的间距 5/6  
  29.         }  
  30.         path.lineTo(cLeft, KChartbottom-2);  
  31.         Paint LinePaint = new Paint();  
  32.         LinePaint.setColor(Color.BLUE);  
  33.         LinePaint.setAntiAlias(true);  
  34.         LinePaint.setStrokeWidth(1);  
  35.         LinePaint.setStyle(Style.STROKE);  
  36. //      LinePaint.setStyle(Style.STROKE);  
  37.         mCanvas.drawPath(path, LinePaint);  
  38.         LinePaint.setAlpha(50);  
  39.         LinePaint.setStyle(Style.FILL);  
  40.         mCanvas.drawPath(path, LinePaint);  
  41.     }  

需要的请给我留言
目录
打赏
0
0
0
2
498
分享
相关文章
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
42 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
171 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
54 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
103 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
42 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
84 19
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
105 14
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
    15
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    18
  • 3
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    15
  • 4
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    4
  • 5
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    2
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    7
  • 7
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    4
  • 8
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    2
  • 9
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    12
  • 10
    Android实战经验之Kotlin中快速实现MVI架构
    9
  • 1
    android FragmentManager 删除所有Fragment 重建
    18
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    31
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    36
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    43
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    147
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    47
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    59
  • 8
    Android历史版本与APK文件结构
    164
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    48
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    42
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等