iOS 股票K线图

作者: 飞不越疯人院 | 来源:发表于2019-09-17 14:30 被阅读0次

    好久没有在简书写东西记录, 前段时间想要将现在工程中用的股票图表绘制重写一遍, 主观臆断一两个星期可以完成, 最后确是磕磕碰碰写了几个月, 而且写出的东西也没有任何美可言, 从这件事中切身体会到一句话那就是"纸上得来终觉浅, 绝知此事要躬行"; 出发点是学习Swift,所以整个绘制采用了Swift+MVVM的形式, 采用Frame布局, 横屏时不会自动适应需要重新加载。

    由于指标线的绘制还没添加, 目前只有部分功能应用在了公司的项目上; 学习交流为目的, 不建议直接使用在自己公司的项目上;


    主要的类介绍

    Use文件夹

    XStockContainView.swift
    

    显示图表的低层View, 将分时, 五日, K线等放在上面;

    XStockContainHandler.swift
    

    低层View配合使用的的数据请求请求处理工具;

    Model文件夹

    XStockTimeModel.swift
    

    分时/五日的数据模型(根据实际应用时更改)

    XStockKLineModel.swift
    

    K线的数据模型(根据实际应用时更改);

    XStockTimeModelRequest.swift
    

    分时/五日数据的封装处理工具, 处理完后回调给XStockContainHandler.swift然后到XStockContainView.swift进而到各个图标的显示中;

    XStockKLineModelRequest.swift
    

    K线数据的封装处理工具, 处理完后回调给XStockContainHandler.swift然后到XStockContainView.swift进而到各个图标的显示中;

    Views文件夹

    XStockChartTimeView.swift
    

    分时/五日图表类;

    XStockTimeInfoBar.swift
    

    长按分时/五日图表时弹出的InfoBar;

    XStockChartKLineView.swift
    

    K线图表类;

    XStockKLineInfoBar.swift
    

    长按K线图表时弹出的InfoBar;

    XStockContainTitleView.swift
    

    分时/五日/日K/周K/月K的按钮View;

    Macro文件夹

    XStockConstant.swift
    

    一些常量数据和扩展;

    XStockEnum.swift
    

    全局枚举值;

    Manger文件夹

    XStockHelper.swift
    

    工具类;

    XStockColor.swift
    

    后期换肤功能用的颜色工具类;

    XStockGlobal.swift
    

    关于图表的显示的整体设置值, 每次使用时如果需要可以先设置初始值;


    整体的效果

    总体效果

    分时的效果


    分时

    五日的效果


    五日

    日K的效果


    日K

    周K的效果


    周K

    月K的效果


    月K

    使用示例

    #ViewController.swift竖图显示的类
    
    import UIKit
    class ViewController: UIViewController, XStockContainViewDelegate {
        var chartView : XStockContainView?;
        override func viewDidLoad() {
            super.viewDidLoad()
            chartView = XStockContainView.init(frame: CGRect(x: 0, y: 100, width: XScreenWidth, height: 440), stkCode: "665.HK", delegate: self, preClose: "2.45", showType: .Time);
            self.view.addSubview(chartView!)
        }
    
        //MARK:XStockContainViewDelegate
        func xStockChartTaped(showType: XStockChartType) {
            AppDelegate.delegate.isLandScape = true;
            UIDevice.switchOrientation(orientation: UIInterfaceOrientation.landscapeRight);
            let landscapeC = LandscapeViewController.init(stk: "665.HK", preClose: "2.45", showType: showType);
            let navC  = UINavigationController.init(rootViewController: landscapeC);
            self.navigationController!.present(navC, animated: true, completion: nil);
            print("去大图");
        }
    }
    
    #LandscapeViewController.swift横图显示的类
    
    import UIKit
    class LandscapeViewController: UIViewController, XStockContainViewDelegate {
        var chartView : XStockContainView?;
        init(stk:String!, preClose:String!, showType:XStockChartType) {
            super.init(nibName: nil, bundle: nil);
            chartView = XStockContainView.init(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 30), stkCode: stk, delegate: self, preClose: "2.45", showType: showType);
        }
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            self.navigationController?.navigationBar.isHidden = true;
            self.view.backgroundColor = UIColor.white;
            self.view.addSubview(chartView!)
            // Do any additional setup after loading the view.
        }
        //MARK:XStockContainViewDelegate
        func xStockChartTaped(showType: XStockChartType) {
            AppDelegate.delegate.isLandScape = false;
            UIDevice.switchOrientation(orientation: UIInterfaceOrientation.portrait);
            self.dismiss(animated: true, completion: nil);
        }
    }
    

    编写思路

    分时/五日

    分时/五日图, 拿到数据封装处理过程中遍历拿到最高/最低价和最大成交量数值, 进而可以确定图表和成交量的坐标值, 昨收价必须有, 因为根据这个算涨跌的数据;
    封装数据完成后遍历数据贝赛尔曲线将数据点链接起来进行显示, 渐变色区域:确定好分时/五日线后确定左下角和右下角的坐标. 得到一个封闭区域,然后CAGradientLayermask设置为封闭区域进而得到渐变色区域;

    K线图

    K线图, 拿到数据封装处理过程中遍历拿到最高/最低价(以及MA数据的最大最小值, 防止数据绘制在外边)和最大成交量数值, 进而可以确定图表和成交量的坐标值;
    封装数据完成后确定每屏显示K线的蜡烛图的个数, 进而确定每个蜡烛图所占宽度, 然后遍历数据贝赛尔曲线将数据点链接起来进行显示;

    拖动/缩放

    一个关键记录值(最后一个数据所在数组的下标); 确定后每屏显示蜡烛个数后, 就可以确定需要的数据个数, 记录下当前屏幕显示的数据最后一个数据所在数组中的下标(最开始默认就是Array.count-1), 每次拖动或者缩放/放大时实际是计算最后一个数据的下标值得移动, 这里需要注意左侧边界不能超过0右侧边界不能超过Array.count-1 每次换算好最后的数据数组下标后去除对应数据进行重绘(这里有一些疑惑, 每次都要重新绘制是否太浪费资源, 有什么好的解决方案?),

    长按移动定位

    以K线图为例长按时定位按压点的坐标然后除以每个蜡烛图所占宽度求整得到一个数值即为此时十字线竖线应该显示在从左开始的第n个蜡烛图上, 然后再求半得到此蜡烛图的中心, 然后显示十字线;移动时也是这个原理;


    工作中暂时用不到图表了, 所以指标线的绘制还没有完成, 入门的写法交流画法使用;
    虽然分时, 蜡烛线的主体功能都完成了, 但是总觉得设计编写的很乱, 不容易梳理,能力有限想不出更好的思路; 如果有好的方案或者构架理念欢迎各位不吝指导, 谢谢;
    Demo地址

    相关文章

      网友评论

        本文标题:iOS 股票K线图

        本文链接:https://www.haomeiwen.com/subject/poxcuctx.html