热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android版的股票行情K线图开发

这篇文章主要介绍了Android版的股票行情K线图开发,感兴趣的小伙伴们可以参考一下

现在在手上的是一个证券资讯类型的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);

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

@Override 
  protected void drawKChatBackGround() { 
    Rect dirty = new Rect(left, kChartTop, right, KChartbottom); 
    // 画背景图的矩形 
    mCanvas.drawRect(dirty, LineGrayPaint); 
    PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1); 
    LineGrayPaint.setPathEffect(effects); 
    Path path = new Path(); 
    int y = kChartTop + 15; 
    // 画上面的虚线 
    path.moveTo(left, y ); 
    path.lineTo(right, y ); 
    String text = getPriceText(highPrice); 
    int textHeight = (int) (textGrayPaint.descent() - textGrayPaint.ascent()); 
    mCanvas.drawText(text,left - textGrayPaint.measureText(text) - 5,y + textHeight/2 ,textGrayPaint); 
    double max = highPrice - lowPrice; 
    if (max > 10){ 
      // 分成四等分 
      // 画中间的三根虚线 
      int n = 4; 
      double sper = (highPrice - lowPrice) / 4;// 每一等分代表的价格 
      for(int i=1;i 0; i--) { 
      int x = left + perWidth * i; 
      path.moveTo(x, kChartTop); 
      path.lineTo(x, KChartbottom); 
      perXPoint[i - 1] = x; 
    } 
    mCanvas.drawPath(path, LineGrayPaint); 
  } 

@Override 
  protected void drawMAChart() { 
    // 画均线 
    Path path5 = new Path(); 
    Path path10 = new Path(); 
    Path path20 = new Path(); 
    double heightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice); 
    int maStart = left; 
    float maStartY; 
    path5.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue5()) * heightScale)); 
    path10.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue10()) * heightScale)); 
    path20.moveTo(maStart, (float) (kChartTop + (highPrice - infos.get(0).getMaValue20()) * heightScale)); 
     
    for(SingleStockInfo info:infos){ 
      maStart += per * perHalf;// 每一天实际所占的数据是4/6,左右边距各1/6  
      maStartY = (float) (kChartTop + (highPrice - info.getMaValue5()) * heightScale); 
      path5.lineTo(maStart, maStartY); 
      maStartY = (float) (kChartTop + (highPrice - info.getMaValue10()) * heightScale); 
      path10.lineTo(maStart, maStartY); 
      maStartY = (float) (kChartTop + (highPrice - info.getMaValue20()) * heightScale); 
      path20.lineTo(maStart, maStartY); 
      maStart += per * perHalf; 
    } 
     
    Paint paint = new Paint(); 
    paint.setColor(Color.BLUE); 
    paint.setAntiAlias(true); 
    paint.setStrokeWidth(2); 
    paint.setStyle(Style.STROKE); 
    mCanvas.drawPath(path5, paint); 
    paint.setColor(Color.MAGENTA); 
    mCanvas.drawPath(path10, paint); 
    paint.setColor(Color.GREEN); 
    mCanvas.drawPath(path20, paint); 
  }
/** 
   * 下面的柱形图 
   */ 
  @Override 
  protected void drawPillarsChart(int flag) { 
    LineGrayPaint.setPathEffect(null); 
    Rect dirty = new Rect(left, pillarsChartTop, right, pillarsChartbottom); 
    // 画背景图的矩形 
    mCanvas.drawRect(dirty, LineGrayPaint); 
     
    int y = pillarsChartTop + (pillarsChartbottom - pillarsChartTop)/2; 
    mCanvas.drawLine(left,y,right, y, LineGrayPaint); 
     
    // 中间的值 
    String totalCount = getPriceText(maxCount/2/10000); 
    float maginLeft = left - textGrayPaint.measureText(totalCount)- 5; 
    mCanvas.drawText(totalCount, maginLeft, y,textGrayPaint); 
    // 上面的值 
    totalCount = getPriceText(maxCount/10000); 
    maginLeft = left - textGrayPaint.measureText(totalCount)- 5; 
    mCanvas.drawText(totalCount, maginLeft, pillarsChartTop,textGrayPaint); 
    // 下面的值 
    totalCount = "万手"; 
    maginLeft = left - textGrayPaint.measureText(totalCount) - 5; 
    mCanvas.drawText(totalCount, maginLeft, pillarsChartbottom,textGrayPaint); 
    int pStart = left; 
    float pStartY; 
    double heightScale = (pillarsChartbottom - pillarsChartTop)/maxCount; 
    Paint paint = new Paint(); 
    paint.setAntiAlias(true); 
    paint.setStyle(Paint.Style.FILL); 
    if (flag == StockService.FLAG){ 
      for(MinuteInfo info:minuteInfos){ 
        pStart += per * per16;// 每一天实际所占的数据是4/6,加上1/6 
        pStartY = (float) (pillarsChartTop + (maxCount - info.getVolume()) * heightScale); 
        dirty = new Rect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2); 
        paint.setColor(info.getColor()); 
        // 画背景图的矩形 
        mCanvas.drawRect(dirty, paint); 
        pStart += per * per56;// 右边的间距 5/6 
      } 
    }else{ 
      for(SingleStockInfo info:infos){ 
        pStart += per * per16;// 每一天实际所占的数据是4/6,加上1/6 
        pStartY = (float) (pillarsChartTop + (maxCount - info.getTotalCount()) * heightScale); 
        dirty = new Rect(pStart, (int) pStartY, (int) (pStart + per * per46), pillarsChartbottom-2); 
        paint.setColor(info.getColor()); 
        // 画背景图的矩形 
        mCanvas.drawRect(dirty, paint); 
        pStart += per * per56;// 右边的间距 5/6 
      } 
    } 
  } 
/** 
   * 分时图 
   */ 
  @Override 
  public void drawHoursChart(){ 
    double heightScale = (KChartbottom - kChartTop)/(highPrice - lowPrice); 
    int cLeft = left; 
    int cTop = 0; 
    Path path = new Path(); 
    path.moveTo(cLeft, KChartbottom-2); 
    int position = 0; 
    int perPointX = perXPoint[position];// 记录第一条垂直虚线的x坐标 
    for(MinuteInfo info:minuteInfos){ 
      cLeft += per * per16; 
      cTop = (int) (kChartTop + (highPrice - info.getNow()) * heightScale); 
      path.lineTo(cLeft + per * per26, cTop); 
      if (cLeft >= perPointX){ 
        // 恰好画到第一条垂直虚线的地方,需要画下面的时间 
        String text = KChartUtil.getMinute(info.getMinute()); 
        float textWidth = textGrayPaint.measureText(text); 
        int textHeight = (int) (textGrayPaint.descent()- textGrayPaint.ascent()); 
        mCanvas.drawText(text, perPointX - textWidth/2, KChartbottom + textHeight, textGrayPaint); 
        if (!(position == perXPoint.length-1)){ 
          Log.e(TAG, perPointX+"----------"+info.getMinute()+"---"+text); 
          perPointX = perXPoint[++position]; 
        } 
      } 
      cLeft += per * per56;// 右边的间距 5/6 
    } 
    path.lineTo(cLeft, KChartbottom-2); 
    Paint LinePaint = new Paint(); 
    LinePaint.setColor(Color.BLUE); 
    LinePaint.setAntiAlias(true); 
    LinePaint.setStrokeWidth(1); 
    LinePaint.setStyle(Style.STROKE); 
//   LinePaint.setStyle(Style.STROKE); 
    mCanvas.drawPath(path, LinePaint); 
    LinePaint.setAlpha(50); 
    LinePaint.setStyle(Style.FILL); 
    mCanvas.drawPath(path, LinePaint); 
  } 

新年伊始,中国股市走出世界罕见,前无古人后无来者的极端行情,股市有风险,投资需谨慎。
这句话是题外话了,重点还是希望对大家学习Android程序设计有所帮助。


推荐阅读
  • 六个接私活的平台,技术在手,财富自由!值得推荐给每一位专业人士!
    本文将介绍六个适合专业人士接私活的平台,帮助技术人才实现财富自由。这些平台不仅提供了丰富的项目机会,还为用户搭建了高效的合作桥梁,是每位技术人士不容错过的资源。 ... [详细]
  • 安卓逆向工程工具精选合集
    在安卓逆向工程领域,本文精选了一系列常用的工具,并将持续更新以适应技术的发展。特别推荐使用雷电3.98版本作为电脑模拟器,用户可从官方网站下载最新版本,确保最佳的兼容性和性能。此外,本文还介绍了其他关键工具,如反编译器、调试器和签名工具,为逆向工程师提供全面的支持。 ... [详细]
  • 为了优化直播应用底部聊天框的弹出机制,确保在不同设备上的布局稳定性和兼容性,特别是在配备虚拟按键的设备上,我们对用户交互流程进行了调整。首次打开应用时,需先点击首个输入框以准确获取键盘高度,避免直接点击第二个输入框导致的整体布局挤压问题。此优化通过调整 `activity_main.xml` 布局文件实现,确保了更好的用户体验和界面适配。 ... [详细]
  • 点云技术初探(三):PCL基础知识与学习路径指南本文首先介绍了点云库(PCL)的基本概念,PCL是一个在前人点云研究成果基础上发展而来的大型跨平台开源C++编程库,旨在为点云数据处理提供全面的支持。文章详细阐述了PCL的核心功能及其在三维数据处理、特征提取、分割与配准等方面的应用,并为初学者提供了系统的学习路径和资源推荐,帮助读者快速掌握PCL的使用方法。 ... [详细]
  • 在椭圆形状设计中,色彩搭配方案对视觉效果和用户体验至关重要。本文分析了不同色彩组合在椭圆形状设计中的应用效果,特别探讨了白色背景与绿色文字的搭配,指出长期观看这种配色可能会导致视觉疲劳。通过引入多种色彩搭配方案,本文旨在为设计师提供更加科学和舒适的色彩选择建议。 ... [详细]
  • 利用Redis HyperLogLog高效统计微博日活跃和月活跃用户数
    本文探讨了如何利用Redis的HyperLogLog数据结构高效地统计微博平台的日活跃用户(DAU)和月活跃用户(MAU)数量。通过HyperLogLog的高精度和低内存消耗特性,可以实现对大规模用户数据的实时统计与分析,为平台运营提供有力的数据支持。 ... [详细]
  • 表面缺陷检测数据集综述及GitHub开源项目推荐
    本文综述了表面缺陷检测领域的数据集,并推荐了多个GitHub上的开源项目。通过对现有文献和数据集的系统整理,为研究人员提供了全面的资源参考,有助于推动该领域的发展和技术进步。 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
  • 新年伊始,正是学习的最佳时机。本文全面解析了CK1957-Zookeeper的核心概念与实践技巧,旨在帮助初学者快速掌握这一深度学习工具。通过详细的理论讲解和实际操作示例,读者可以更好地理解Zookeeper的工作原理及其在分布式系统中的应用。无论是新手还是有一定基础的学习者,都能从中受益匪浅。 ... [详细]
  • 探究Oracle数据库字符集编码的详细方法与实践
    本文深入探讨了Oracle数据库字符集编码的详细方法与实践。首先,通过执行 `SELECT USERENV('language') FROM DUAL;` 查询服务端字符集编码。其次,通过在注册表中搜索 `NLS_LANG` 参数来查看客户端字符集编码。此外,文章还介绍了如何在不同场景下正确配置和转换字符集,以确保数据的一致性和完整性。 ... [详细]
  • 本文深入探讨了在Android应用开发中常见的相机连接故障问题,特别是在RK3288平台和Android 6.0系统上。通过分析具体案例,本文提供了详细的解决方案和应对策略,旨在帮助开发者有效解决相机连接问题,提升应用的稳定性和用户体验。 ... [详细]
  • 摩托罗拉Razr V3焕新归来:全球首款翻盖式折叠屏智能手机重磅发布
    曾经风靡一时的摩托罗拉Razr V3如今以全新面貌回归,成为全球首款翻盖式折叠屏智能手机。这款经典机型自2004年首次推出,迅速成为市场宠儿,全球销量突破1.3亿部,奠定了其在手机史上的传奇地位。此次焕新发布的Razr V3不仅继承了原版的精致设计,还融入了最新的折叠屏技术,为用户带来前所未有的使用体验。 ... [详细]
  • 因缺失VCRUNTIME140_1.dll文件导致代码无法运行,建议重新安装程序以解决问题
    因缺失VCRUNTIME140_1.dll文件导致代码无法运行,建议重新安装程序以解决问题 ... [详细]
  • SSMS 启动故障:错误报告与解决求助 ... [详细]
  • HTML5大文件传输技术深度解析与实践分享
    本文深入探讨了HTML5在Web前端开发中实现大文件上传的技术细节与实践方法。通过实例分析,详细讲解了如何利用HTML5的相关特性高效、稳定地处理大文件传输问题,并提供了可供参考的代码示例和解决方案。此外,文章还讨论了常见的技术挑战及优化策略,旨在帮助开发者更好地理解和应用HTML5大文件上传技术。 ... [详细]
author-avatar
mobiledu2502876293
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有