热门标签 | 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程序设计有所帮助。


推荐阅读
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 解决微信电脑版无法刷朋友圈问题:使用安卓远程投屏方案
    在工作期间想要浏览微信和朋友圈却不太方便?虽然微信电脑版目前不支持直接刷朋友圈,但通过远程投屏技术,可以轻松实现在电脑上操作安卓设备的功能。 ... [详细]
  • 在维护公司项目时,发现按下手机的某个物理按键后会激活相应的服务,并在屏幕上模拟点击特定坐标点。本文详细介绍了如何使用ADB Shell Input命令来模拟各种输入事件,包括滑动、按键和点击等。 ... [详细]
  • 本文探讨了如何在 PHP 的 Eloquent ORM 中实现数据表之间的关联查询,并通过具体示例详细解释了如何将关联数据嵌入到查询结果中。这不仅提高了数据查询的效率,还简化了代码逻辑。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 揭秘:为何我的网名是老紫竹
    本文详细解释了作者为何选择“老紫竹”作为网名,从个人喜好到网络经历,以及与紫竹植物的渊源。 ... [详细]
  • 本文将深入探讨PHP编程语言的基本概念,并解释PHP概念股的含义。通过详细解析,帮助读者理解PHP在Web开发和股票市场中的重要性。 ... [详细]
  • 本文介绍了一种有效的方法来检测硬盘上的视频文件是否损坏或存在缺帧问题。虽然一些常见的搜索引擎并未提供专门的工具,但通过使用FFmpeg等专业软件,可以全面验证各种视频格式的数据完整性,包括较为古老的AVI格式。 ... [详细]
  • 本次考试于2016年10月25日上午7:50至11:15举行,主要涉及数学专题,特别是斐波那契数列的性质及其在编程中的应用。本文将详细解析考试中的题目,并提供解题思路和代码实现。 ... [详细]
author-avatar
宝宝贝贝198812126
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有