股票应用开发——图表的绘制(三)

原创 2016年08月30日 14:14:45

        大家好,又一次和大家见面了!最近在写关于股票应用开发过程中的新的体会,希望对大家有所帮助,让大家不要向我一样,少走一些弯路。还用就是最近在更新这个系列的博客,怕到后面忙起来或者不想写了就落下了!

       今天主要说的是图表的绘制,当然你需要继承View,也就是现在一搜一大把的自定义View。我的整体思路是这样的:

       首先需要定义图表的基类,在基类内需要定义或者绘制一些共性的东西,如图表的大小,背景色,字体,坐标轴等等信息;

       然后就是继承图表的基类进行图形的绘制;

下面先说一下图表实体类的基类:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一、基类的定义:Chart.java

       基类解决的是共性问题,首先我们需要初始化一些图表的设置,确定图表的大小,颜色,字体等;其次就是在onDraw()方法内进行相关的绘制工作,如图表的边框,网格线等;最后就是定义图表点击的回调函数;

下面是代码示例:

package com.zxm.chart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.zxm.mykchart.R;
import com.zxm.util.LogUtil;

/**
 * Created by ZhangXinmin on 2016/8/22.
 * Base Class for Chart!
 */
public class Chart extends View{

    /**constractor*/
    public Chart(Context context) {
        super(context);
        init();
    }

    public Chart(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        LogUtil.i("tag","Chart..构造器2参数"+getTime());
    }

    public Chart(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
        LogUtil.i("tag","Chart..构造器3参数");
    }

    /**
     * 默认值
     */
    /** 默认背景色 */
    public static final int DEFAULT_BACKGROUD  = R.color.marker_bg;

    /** 默认XY轴字体大小 **/
    public static final int DEFAULT_AXIS_LABLE_SIZE = 22;

    /** 默认XY坐标轴颜色 */
    private static final int DEFAULT_AXIS_COLOR = Color.rgb(224,225,227);

    /** 默认经纬线颜色 */
    private static final int DEFAULT_LONGI_LAITUDE_COLOR = Color.rgb(224,225,227);

    /** 默认上表纬线数 */
    public static final int DEFAULT_UPER_LATITUDE_NUM = 3;

    /** 默认下表纬线数 */
    private static final int DEFAULT_LOWER_LATITUDE_NUM = 1;

    /** 默认经线数 */
    public static final int DEFAULT_LOGITUDE_NUM = 3;

    /** 默认边框的颜色 */
    public static final int DEFAULT_BORDER_COLOR = Color.rgb(224,225,227);

    /** 默认虚线效果 */
    private static final PathEffect DEFAULT_DASH_EFFECT = new DashPathEffect(new float[] { 3, 3, 3,
            3 }, 1);

    /** 下表的顶部 */
    public static float LOWER_CHART_TOP;

    /** 上表的底部 */
    public static float UPER_CHART_BOTTOM;

    /**
     * 属性
     */
    /** 背景色 */
    private int mBackGround;

    /** 坐标轴XY颜色 */
    private int mAxisColor;

    /** 经纬线颜色 */
    private int mLongiLatitudeColor;

    /** 虚线效果 */
    private PathEffect mDashEffect;

    /** 边线色 */
    private int mBorderColor;

    /** 上表高度 */
    private float mUperChartHeight;

    /** 是否显示下表Tabs */
    private boolean showLowerChartTabs;

    /** 是否显示顶部Titles */
    private boolean showTopTitles;

    /** 顶部Titles高度 */
    private float topTitleHeight;

    /** 下表TabTitles */
    private String[] mLowerChartTabTitles;

    /** 下表Tab宽度 */
    private float mTabWidth;

    /** 下表Tab高度 */
    private float mTabHight;

    /** 下表TabIndex */
    private int mTabIndex;

    /** 下表高度 */
    private float mLowerChartHeight;

    private float latitudeSpacing;

    private OnTabClickListener mOnTabClickListener;

    public void setOnTabClickListener(OnTabClickListener onTabClickListener) {
        mOnTabClickListener = onTabClickListener;
    }

    /**
     * 定义图表点击的监听接口
     */
    public interface OnTabClickListener {
        void onTabClick(int indext);
    }

    /**初始化设置表格属性*/
    private void init(){
        mBackGround = DEFAULT_BACKGROUD;
        mAxisColor = DEFAULT_AXIS_COLOR;
        mLongiLatitudeColor = DEFAULT_LONGI_LAITUDE_COLOR;
        mDashEffect = DEFAULT_DASH_EFFECT;
        mBorderColor = DEFAULT_BORDER_COLOR;
        showLowerChartTabs = true;
        showTopTitles = true;
        topTitleHeight = 0;
        mTabIndex = 0;
        mOnTabClickListener = null;

        mTabWidth = 0;
        mTabHight = 0;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        setBackgroundResource(mBackGround);//设置背景色
        int viewHeight = getHeight();
        int viewWidth = getWidth();
        mLowerChartHeight = viewHeight -2 - LOWER_CHART_TOP;//下表的高度

        //是否显示下表的tab
        if (showLowerChartTabs){//下表TAB的高度
            mTabHight = viewHeight / 24.0f;
        }

        //是否显示顶部title
        if (false){//顶部title的高度
            topTitleHeight = DEFAULT_AXIS_LABLE_SIZE + 2;
        }else {
            topTitleHeight = 0;
        }

        latitudeSpacing = (viewHeight - 4 -DEFAULT_AXIS_LABLE_SIZE - topTitleHeight - mTabHight) /
                (DEFAULT_UPER_LATITUDE_NUM + DEFAULT_LOWER_LATITUDE_NUM +2);
        //上表高度
        mUperChartHeight = latitudeSpacing * (DEFAULT_UPER_LATITUDE_NUM + 1);
        //下表顶部
        LOWER_CHART_TOP = viewHeight - 1 - latitudeSpacing * (DEFAULT_LOWER_LATITUDE_NUM+1);
        //上表的底部
        UPER_CHART_BOTTOM = 1 + topTitleHeight + latitudeSpacing * (DEFAULT_UPER_LATITUDE_NUM + 1);

        // 绘制边框
        drawBorders(canvas, viewHeight, viewWidth);

        // 绘制经线
//        drawLongitudes(canvas, viewHeight, longitudeSpacing);

        // 绘制纬线
        drawLatitudes(canvas, viewHeight, viewWidth, latitudeSpacing);

        // 绘制X线及LowerChartTitles
        drawRegions(canvas, viewHeight, viewWidth);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Rect rect = new Rect();
        getGlobalVisibleRect(rect);
        float x = event.getRawX();
        float y = event.getRawY();

        if (y <= LOWER_CHART_TOP + rect.top +2 &&
                y >= UPER_CHART_BOTTOM + DEFAULT_AXIS_LABLE_SIZE + rect.top){
            if (mTabWidth <= 0){
                return true;
            }
            int indext = (int) (x / mTabWidth);

            if (mTabIndex != indext){
                mTabIndex = indext;
                mOnTabClickListener.onTabClick(mTabIndex);
                return true;
            }
        }
        return false;
    }

    /**
     * 绘制边框
     * @param canvas
     * @param viewHeight
     * @param viewWidth
     */
    private void drawBorders(Canvas canvas, int viewHeight, int viewWidth){
        Paint paint = new Paint();
        paint.setColor(Color.rgb(224,225,227));//设置画笔颜色
        paint.setStrokeWidth(1);
        canvas.drawLine(1, 1, viewWidth - 1, 1, paint);
        canvas.drawLine(1,topTitleHeight,1,viewHeight - 1,paint);//左边框
        canvas.drawLine(viewWidth - 1,viewHeight - 1,viewWidth - 1,topTitleHeight,paint);//右边框
        canvas.drawLine(viewWidth - 1,viewHeight - 1,1, viewHeight - 1, paint);//下边框

    }

    /**
     * 绘制网格线;经线
     * @param canvas
     * @param viewHeight
     * @param longitudeSpacing
     */
    private void drawLongitudes(Canvas canvas, int viewHeight, float longitudeSpacing){
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setPathEffect(mDashEffect);//设置绘制虚线
        for (int i = 1; i <= DEFAULT_LOGITUDE_NUM;i++){
            canvas.drawLine(1 + longitudeSpacing * i,topTitleHeight + 2,
                    1 + longitudeSpacing * i,UPER_CHART_BOTTOM,paint);
            canvas.drawLine(1 + longitudeSpacing * i,LOWER_CHART_TOP,
                    1 + longitudeSpacing * i,viewHeight - 1,paint);
        }

    }

    /**
     * 绘制网格线;纬线
     * @param canvas
     * @param viewHeight
     * @param viewWidth
     * @param latitudeSpacing
     */
    private void drawLatitudes(Canvas canvas, int viewHeight, int viewWidth, float latitudeSpacing){
        Paint paint = new Paint();
        paint.setColor(mLongiLatitudeColor);
        paint.setPathEffect(mDashEffect);
        for (int i = 1;i <= DEFAULT_UPER_LATITUDE_NUM;i++){
            canvas.drawLine(1,topTitleHeight + 1 + latitudeSpacing * i,viewWidth - 1,
                    topTitleHeight + 1 + latitudeSpacing * i,paint);
            for (int j = 1;j <= DEFAULT_LOWER_LATITUDE_NUM;j++){
                canvas.drawLine(1,viewHeight - 1 - latitudeSpacing,viewWidth - 1,
                        viewHeight - 1 - latitudeSpacing,paint);
            }
        }
    }

    private void drawRegions(Canvas canvas, int viewHeight, int viewWidth){
        Paint paint = new Paint();
        paint.setColor(mAxisColor);
        paint.setAlpha(150);
        if (showTopTitles){//是否显示顶部title
            canvas.drawLine(1,1 + DEFAULT_AXIS_LABLE_SIZE + 2,viewWidth - 1,
                    1 + DEFAULT_AXIS_LABLE_SIZE + 2,paint);
        }
        canvas.drawLine(1,UPER_CHART_BOTTOM,viewWidth - 1,UPER_CHART_BOTTOM,paint);
        canvas.drawLine(1,LOWER_CHART_TOP,viewWidth - 1,LOWER_CHART_TOP,paint);

        if (showLowerChartTabs){//是否显示下表Tab
            canvas.drawLine(1, UPER_CHART_BOTTOM + DEFAULT_AXIS_LABLE_SIZE + 2, viewWidth - 1,
                    UPER_CHART_BOTTOM + DEFAULT_AXIS_LABLE_SIZE + 2, paint);
            if (mLowerChartTabTitles == null || mLowerChartTabTitles.length <= 0){
                return;
            }
            mTabWidth = (viewWidth - 2) / 10.0f * 10.0f / mLowerChartTabTitles.length;//下表Tab的宽度
            if (mTabWidth < DEFAULT_AXIS_LABLE_SIZE * 2.5f + 2){
                mTabWidth = DEFAULT_AXIS_LABLE_SIZE * 2.5f + 2;
            }

            Paint textPaint = new TextPaint();
            textPaint.setColor(Color.WHITE);
            textPaint.setTextSize(DEFAULT_AXIS_LABLE_SIZE);

            /*Paint bgPaint = new Paint();
            bgPaint.setColor(Color.MAGENTA);
            for (int i = 0; i < mLowerChartTabTitles.length && mTabWidth * (i + 1) <= viewWidth - 2;i++){
                if (i == mTabIndex){
                   canvas.drawRect(mTabWidth * i + 1,LOWER_CHART_TOP,mTabWidth * (i + 1) + 1,
                           UPER_CHART_BOTTOM + DEFAULT_AXIS_LABLE_SIZE + 2,bgPaint);

                }
                canvas.drawLine(mTabWidth * i + 1, LOWER_CHART_TOP, mTabWidth * i + 1,
                        UPER_CHART_BOTTOM + DEFAULT_AXIS_LABLE_SIZE + 2, paint);
                canvas.drawText(mLowerChartTabTitles[i], mTabWidth * i + mTabWidth / 2.0f
                                - mLowerChartTabTitles[i].length() / 3.0f * DEFAULT_AXIS_LABLE_SIZE,
                        LOWER_CHART_TOP - mTabHight / 2.0f + DEFAULT_AXIS_LABLE_SIZE / 2.0f,
                        textPaint);
            }*/
        }
    }

    public int getBackGround() {
        return mBackGround;
    }

    public void setBackGround(int BackGround) {
        this.mBackGround = BackGround;
    }

    public int getAxisColor() {
        return mAxisColor;
    }

    public void setAxisColor(int AxisColor) {
        this.mAxisColor = AxisColor;
    }

    public int getLongiLatitudeColor() {
        return mLongiLatitudeColor;
    }

    public void setLongiLatitudeColor(int LongiLatitudeColor) {
        this.mLongiLatitudeColor = LongiLatitudeColor;
    }

    public PathEffect getDashEffect() {
        return mDashEffect;
    }

    public void setDashEffect(PathEffect DashEffect) {
        this.mDashEffect = DashEffect;
    }

    public int getBorderColor() {
        return mBorderColor;
    }

    public void setBorderColor(int BorderColor) {
        this.mBorderColor = BorderColor;
    }

    public float getUperChartHeight() {
        return mUperChartHeight;
    }

    public void setUperChartHeight(float UperChartHeight) {
        this.mUperChartHeight = UperChartHeight;
    }

    public boolean isShowLowerChartTabs() {
        return showLowerChartTabs;
    }

    public void setShowLowerChartTabs(boolean showLowerChartTabs) {
        this.showLowerChartTabs = showLowerChartTabs;
    }

    public float getLowerChartHeight() {
        return mLowerChartHeight;
    }

    public void setLowerChartHeight(float LowerChartHeight) {
        this.mLowerChartHeight = LowerChartHeight;
    }

    public String[] getLowerChartTabTitles() {
        return mLowerChartTabTitles;
    }

    public void setLowerChartTabTitles(String[] LowerChartTabTitles) {
        this.mLowerChartTabTitles = LowerChartTabTitles;
    }

    public float getLatitudeSpacing() {
        return latitudeSpacing;
    }

    public void setLatitudeSpacing(float latitudeSpacing) {
        this.latitudeSpacing = latitudeSpacing;
    }

    public void setShowTopTitles(boolean showTopTitles) {
        this.showTopTitles = showTopTitles;
    }

    public float getTopTitleHeight() {
        return topTitleHeight;
    }

    public float getmTabHight() {
        return mTabHight;
    }

    protected String getTime() {
        return ":" + System.currentTimeMillis();
    }
}
二、绘制图表:CandleChart.java

       定义CandleChart.java继承Chart.java并实现Chart内部定义的接口:

       重写onDraw(Canvas canvas)方法,在方法内部,对K线图,成交量图,MACD图,KDJ图,绘制坐标轴以及刻度值,绘制十字线以及信息详情框;

       下面说一下技术难点:

A.    屏幕的手势设置:

思路参考:如下思维导图


关于手势实现思路:

首先是拖动十字线的实现,在实现的过程中是通过调用postInvalidate()去刷新View;

其次是拖动图表的实现,在实现过程中首先是隐藏十字线和信息显示框,然后判断移动距离是否满足最小移动距离,在这里是通过定义一个变量表示图表显示的起始位置来实现图表的移动的;

       最后是实现图表的缩放,实现的思路是首先计算手指触屏的初始位置,计算两手指之间的距离,当手指移动之后计算此时手指之间的距离,如果当前手指之间的距离大于初始时刻手指之间的距离,就对图表进行放大,反之缩小;还有需要注意的是在计算两手指之间的距离的时候,也就是在设置触摸模式之前需要判断当前屏幕有几个触摸点,否则会报异常(pointer index out of range);

B.图形的绘制:

a>无论是在绘制蜡烛图还是在绘制其他图形的时候首先需要将数据转化成屏幕上对应的像素,也就是转换的比率rate = getLowerChartHeight() / (max - 0),然后需要注意绘制每条数据的坐标位置,尤其是绘制上下两个关联的图表时,一定要注意坐标的一致性;

b>绘制MACD图表:

       为什么要单独说一下绘制MACD的图表呢?因为该图表存在y = 0 这条轴线,当然如果你不希望绘制的图形有固定的X轴,则可以不考虑这个问题;

       但是若没有固定的y = 0这条轴线,那么可能会出现当你的图表进行缩放的时候会在画布中移动,也就是X轴不固定;

       若存在这条固定的轴线,会出现该轴线上下两侧的缩放比例不一致的问题;

------------------------------------------------------------------------------------------------------------------

就说这么多吧,下面是代码示例:

绘制蜡烛图代码:

   /**
     * 绘制蜡烛图,也就是K线图
     */
    private void drawUpperRegion() {
//        LogUtil.i("tag", "CandleChart..drawUpperRegion" + getTime());
        //绘制蜡烛图
        Paint redPaint = new Paint();
        redPaint.setColor(Color.RED);
        Paint greenPaint = new Paint();
        greenPaint.setColor(Color.GREEN);

        int width = getWidth();//屏幕的宽度
        //设置Candle的宽度
        mCandleWidth = (width - 4) / 10.0f * 10.0f / mShowDataNum;
        /**计算蜡烛图每一个矩形的高度比例*/
        double rate = (getUperChartHeight() - 60) / (mMaxPrice - mMinPrice);

        for (int i = 0; i < mShowDataNum && mDataStartIndext + i < mList.size(); i++) {
            StockInfo info = mList.get(mDataStartIndext + i);

            /**计算每一天股票的价格所对应的像素*/
            float open = (float) ((mMaxPrice - info.getOpen()) * rate + DEFAULT_AXIS_LABLE_SIZE + 4);
            float close = (float) ((mMaxPrice - info.getClose()) * rate + DEFAULT_AXIS_LABLE_SIZE + 4);
            float high = (float) ((mMaxPrice - info.getHigh()) * rate + DEFAULT_AXIS_LABLE_SIZE + 4);
            float low = (float) ((mMaxPrice - info.getLow()) * rate + DEFAULT_AXIS_LABLE_SIZE + 4);

            float right = (float) (3 + mCandleWidth * (i + 1));
            float left = (float) (3 + mCandleWidth * i);
            //计算绘制每个蜡烛的开始X坐标
            float startX = (float) (3 + mCandleWidth * i + (mCandleWidth - 1) / 2);
            /**设置蜡烛图的颜色*/
            if (open < close) {
                canvas.drawRect(left, open, right, close, greenPaint);
//                LogUtil.i("tag","开盘价小于收盘价:left"+left+";close:"+close+";right:"+right+";open:"+open);
                canvas.drawLine(startX, high, startX, low, greenPaint);
            } else if (open == close) {
                canvas.drawLine(left, open, right, open, redPaint);
//                LogUtil.i("tag","开盘价=收盘价:left"+left+";open:"+open+";right:"+right+";open:"+open);
                canvas.drawLine(startX, high, startX, low, redPaint);
            } else {
                canvas.drawRect(left, close, right, open, redPaint);
//                LogUtil.i("tag","开盘价大于收盘价:left"+left+";open:"+open+";right:"+right+";close:"+close);
                canvas.drawLine(startX, high, startX, low, redPaint);
            }
        }

       
    }
绘制MACD图代码片段:

   /**
     * 绘制MACD指标图形
     */

    private void drawMACDChart() {

        float middle = LOWER_CHART_TOP + getLowerChartHeight() / 2;//获取下部绘图区域的中间位置
        mCandleWidth = (getWidth() - 4) / 10.0f * 10.0f / mShowDataNum;

        Paint linePaint = new Paint();//绘制曲线
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeWidth(2);

        Paint textPaint = new Paint();
        textPaint.setColor(DEFAULT_AXIS_X_LABLE_COLOR);
        textPaint.setTextSize(DEFAULT_AXIS_LABLE_SIZE);

        /**初始化集合数据*/
        MACD = mMacdData.getMACD();//集合不要忘记添加数据!
        DEA = mMacdData.getDEA();
        DIF = mMacdData.getDIF();

        if (!MACD.isEmpty() && !DEA.isEmpty() && !DIF.isEmpty()) {
            double low = DEA.get(mDataStartIndext);//刻度最小值
            double high = low;//刻度最大值
            double upRate = 0.0;//0刻度线之上绘图比例
            double downRate = 0.0;//0刻度线之下绘图比例
            double lineRate = 0.0;//
            for (int i = mDataStartIndext; i < mDataStartIndext + mShowDataNum && i < MACD.size(); i++) {
                low = low < MACD.get(i) ? low : MACD.get(i);
                low = low < DEA.get(i) ? low : DEA.get(i);
                low = low < DIF.get(i) ? low : DIF.get(i);

                high = high > MACD.get(i) ? high : MACD.get(i);
                high = high > DEA.get(i) ? high : DEA.get(i);
                high = high > DIF.get(i) ? high : DIF.get(i);
            }

            upRate = (getLowerChartHeight() / 2 - 4) / (high - 0);//计算上部比例
            downRate = (getLowerChartHeight() / 2 - 4) / Math.abs(low - 0);//计算下部比例
            lineRate = getLowerChartHeight() / (high - low);
            Paint redP = new Paint();
            redP.setColor(Color.RED);
            Paint greenP = new Paint();
            greenP.setColor(Color.GREEN);

            //两条曲线
            float dea = 0.0f;
            float dif = 0.0f;
            //绘制MACD图形
            for (int i = mDataStartIndext; i < mDataStartIndext + mShowDataNum
                    && i < MACD.size(); i++) {
                //绘制矩形
                //计算绘制每个蜡烛的开始X坐标
                float value = MACD.get(i);

                //计算绘制每个蜡烛的开始X坐标
                float startX = (float) (3 + mCandleWidth * (i - mDataStartIndext) + (mCandleWidth - 1) / 2);

                if (MACD.get(i) >= 0) {//MACD值大于0绘制在y = 0上方,红色;
                    canvas.drawLine(startX, (float) ((high - value) * upRate) + LOWER_CHART_TOP, startX, middle, redP);
                } else {
                    canvas.drawLine(startX, middle, startX, (float) (middle + Math.abs(value) * downRate), greenP);
                }

                if (i != mDataStartIndext) {

                    linePaint.setColor(Color.YELLOW);
                    canvas.drawLine(3 + (float) mCandleWidth * (i + 1 - mDataStartIndext) + (float) mCandleWidth / 2,
                            (float) ((high - DEA.get(i)) * lineRate) + LOWER_CHART_TOP,
                            3 + (float) mCandleWidth * (i - mDataStartIndext) + (float) mCandleWidth / 2,
                            dea,
                            linePaint);

                    linePaint.setColor(Color.RED);
                    canvas.drawLine(3 + (float) mCandleWidth * (i + 1 - mDataStartIndext) + (float) mCandleWidth / 2,
                            (float) ((high - DIF.get(i)) * lineRate) + LOWER_CHART_TOP,
                            3 + (float) mCandleWidth * (i - mDataStartIndext)
                                    + (float) mCandleWidth / 2, dif, linePaint);
                }
                dea = (float) ((high - DEA.get(i)) * lineRate) + LOWER_CHART_TOP;
                dif = (float) ((high - DIF.get(i)) * lineRate) + LOWER_CHART_TOP;

            }
            canvas.drawText(ValueFormater.format(high) + "", 2,
                    LOWER_CHART_TOP + DEFAULT_AXIS_LABLE_SIZE - 2, textPaint);
            canvas.drawText(ValueFormater.format((high + low) / 2) + "", 2,
                    LOWER_CHART_TOP + getLowerChartHeight() / 2 + DEFAULT_AXIS_LABLE_SIZE, textPaint);
            canvas.drawText(ValueFormater.format(low) + "", 2,
                    LOWER_CHART_TOP + getLowerChartHeight(),
                    textPaint);
        }

    }

其他的指标绘制方法类似,就不在贴代码了。





版权声明:本文为博主原创文章,未经博主允许不得转载。

股票应用开发——相关指标的含义(二)

上一篇博客主要是网络数据的获取以及解析,本篇博客将要讲述的是股票开发过程中相关指标的计算以及含义!在这里声明一点就是,不在贴出指标的计算代码,出于相关考虑敬请谅解!如有需要可以留言咱们一起探讨! 一...
  • zxm528
  • zxm528
  • 2016年08月29日 17:16
  • 326

股票应用开发——网络数据的获取(一)

一、背景         之前很少写技术博客一方面是怕自己的技术不到家,把大家带到坑里;另一方面就是自己太懒了。现在鼓起勇气把自己的心得体会以及项目的实现思路展现给大家。希望和大家一起学习一起进步!...
  • zxm528
  • zxm528
  • 2016年08月29日 16:07
  • 219

一步一步教你写股票走势图——分时图三(对齐图表、自定义高亮)

上一节我们学习了如何取自定义图表的xy轴,这一节我们介绍一下如何取对齐两个图表库以及如何去自定义柱状图的高亮样式。我们先看一下之前的效果图: 图表的两边明显不对齐,右边尤其明显,左边是因为都写了坐标...

基于Android的短信应用开发(三)——读取手机短信

在上一次,我们读取了手机联系人并将其显示在

IBM大型主机(Mainframe)技术简介之三——应用开发摘要(一)

1. 代码结构 COBOL的源程序的代码主体部分必须从第8列开始(A区域),通常包括分区Division,分段Section和第一级的数据等。 其第7列为指示字符保留,例如*表示注释行,-表...
  • quanben
  • quanben
  • 2011年05月25日 08:39
  • 1686

[Windows通用应用开发]Toast通知(三)——定时Toast

定时Toast 定时Toast采用ScheduledToastNotification类 该类有两个构造函数:
  • xiahn1a
  • xiahn1a
  • 2015年04月13日 02:10
  • 944

IBM大型主机(Mainframe)技术简介之七——应用开发摘要(三)

本文简要介绍Mainframe的CICS技术框架。 CICS基本概念 CICS是Mainframe事务(Transaction)处理的主要媒介,它位于操作系统z/OS之上,处在应用程序(例...
  • quanben
  • quanben
  • 2011年09月25日 11:41
  • 1504

一步一步教你写股票走势图——K线图二(图表联动)

目录 一步一步教你写股票走势图——分时图一(概述) 一步一步教你写股票走势图——分时图二(自定义xy轴) 一步一步教你写股票走势图——分时图三(对齐图表、自定义柱状图高亮) 一步一步教你写股票...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:股票应用开发——图表的绘制(三)
举报原因:
原因补充:

(最多只允许输入30个字)