MPAndroidChart系列源码解读(四)

来源:互联网 发布:php date 取小时分钟 编辑:程序博客网 时间:2024/05/16 05:07

由于个人能力有限,不能再跟着仔细看源码了,感觉每个类关联甚多,决定直接从chart下手了

public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Entry>>> extends        ViewGroup        implements ChartInterface { public Chart(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();  } protected void init() {        setWillNotDraw(false);//如果自定义View重新onDraw方法不执行,调用该方法可以解决问题        // setLayerType(View.LAYER_TYPE_HARDWARE, null);        if (android.os.Build.VERSION.SDK_INT < 11)//图表的动画走版本分之            mAnimator = new ChartAnimator();        else            mAnimator = new ChartAnimator(new AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    // ViewCompat.postInvalidateOnAnimation(Chart.this);                    postInvalidate();                }            });        //下面这些相关类在前面两篇blog都或多或少的有提到        // initialize the utils        Utils.init(getContext());        mDefaultFormatter = new DefaultValueFormatter(1);        mViewPortHandler = new ViewPortHandler();        mLegend = new Legend();        mLegendRenderer = new LegendRenderer(mViewPortHandler, mLegend);        mXAxis = new XAxis();        // 初始化画笔配置        mDescPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mDescPaint.setColor(Color.BLACK);        mDescPaint.setTextAlign(Align.RIGHT);        mDescPaint.setTextSize(Utils.convertDpToPixel(9f));        mInfoPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mInfoPaint.setColor(Color.rgb(247, 189, 51)); // orange        mInfoPaint.setTextAlign(Align.CENTER);        mInfoPaint.setTextSize(Utils.convertDpToPixel(12f));        mDrawPaint = new Paint(Paint.DITHER_FLAG);        if (mLogEnabled)            Log.i("", "Chart.init()");    }}

自定义ViewGroup,不同的Chart传入不同的数据Data,实现ChartInterface接口,在前面的博客有提到具体方法含义。setData方法调用更新数据集,刷新视图

 public void setData(T data) {        if (data == null) {            Log.e(LOG_TAG,                    "Cannot set data for chart. Provided data object is null.");            return;        }        // LET THE CHART KNOW THERE IS DATA        mOffsetsCalculated = false;        mData = data;        // calculate how many digits are needed        calculateFormatter(data.getYMin(), data.getYMax());        for (IDataSet set : mData.getDataSets()) {            if (Utils.needsDefaultFormatter(set.getValueFormatter()))                set.setValueFormatter(mDefaultFormatter);        }        // let the chart know there is new data        notifyDataSetChanged();        if (mLogEnabled)            Log.i(LOG_TAG, "Data is set.");    }

setData的内部调用抽象方法notifyDataSetChanged方法,在具体的Chart类型具体实现,通过刷新引起onDraw方法的重绘,达到跟新视图的目的。clear方法清除数据,还定义了几个抽象方法,用于具体的Chart类型自己具体实现,比如calculateOffsets方法根据边界范围计算偏移量。

  /**     * calculates the offsets of the chart to the border depending on the     * position of an eventual legend or depending on the length of the y-axis     * and x-axis labels and their position     */    protected abstract void calculateOffsets();    /**     * calcualtes the y-min and y-max value and the y-delta and x-delta value     */    protected abstract void calcMinMax();    /**     * calculates the required number of digits for the values that might be     * drawn in the chart (if enabled), and creates the default-value-formatter     */    protected void calculateFormatter(float min, float max) {        float reference = 0f;        if (mData == null || mData.getXValCount() < 2) {            reference = Math.max(Math.abs(min), Math.abs(max));        } else {            reference = Math.abs(max - min);        }        int digits = Utils.getDecimals(reference);        mDefaultFormatter = new DefaultValueFormatter(digits);    }

如果mData数据集为空,会绘制相应的文字告知用户。

   @Override    protected void onDraw(Canvas canvas) {        // super.onDraw(canvas);        if (mData == null) {            boolean hasText = !TextUtils.isEmpty(mNoDataText);            boolean hasDescription = !TextUtils.isEmpty(mNoDataTextDescription);            float line1height = hasText ? Utils.calcTextHeight(mInfoPaint, mNoDataText) : 0.f;            float line2height = hasDescription ? Utils.calcTextHeight(mInfoPaint, mNoDataTextDescription) : 0.f;            float lineSpacing = (hasText && hasDescription) ?                    (mInfoPaint.getFontSpacing() - line1height) : 0.f;            // if no data, inform the user            float y = (getHeight() -                    (line1height + lineSpacing + line2height)) / 2.f                    + line1height;            if (hasText) {                canvas.drawText(mNoDataText, getWidth() / 2, y, mInfoPaint);                if (hasDescription) {                    y = y + line1height + lineSpacing;                }            }            if (hasDescription) {                canvas.drawText(mNoDataTextDescription, getWidth() / 2, y, mInfoPaint);            }            return;        }        //..................    }

drawMarkers方法是用于触摸弹出效果显示触摸区域的值,具体这块的View自定义控件在上篇有提到。saveToPath方法保存图表的截图到Sdcard(实例在Simple中有)同类型方法略,ViewGroup大小发生变化会引起onSizeChanged回调,这里面会调用notifyDataSetChanged方法刷新视图,setHardwareAccelerationEnabled设置硬件加速

  @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        if (mLogEnabled)            Log.i(LOG_TAG, "OnSizeChanged()");        if (w > 0 && h > 0 && w < 10000 && h < 10000) {            mViewPortHandler.setChartDimens(w, h);            if (mLogEnabled)                Log.i(LOG_TAG, "Setting chart dimens, width: " + w + ", height: " + h);            for (Runnable r : mJobs) {                post(r);            }            mJobs.clear();        }        notifyDataSetChanged();        super.onSizeChanged(w, h, oldw, oldh);    }    /**     * Setting this to true will set the layer-type HARDWARE for the view, false     * will set layer-type SOFTWARE.     *     * @param enabled     */    public void setHardwareAccelerationEnabled(boolean enabled) {        if (android.os.Build.VERSION.SDK_INT >= 11) {            if (enabled)                setLayerType(View.LAYER_TYPE_HARDWARE, null);            else                setLayerType(View.LAYER_TYPE_SOFTWARE, null);        } else {            Log.e(LOG_TAG,                    "Cannot enable/disable hardware acceleration for devices below API level 11.");        }    }

onDetachedFromWindow方法调用unbindDrawables方法,取消View以及子View的所有监听,以免内存泄漏

  private void unbindDrawables(View view) {        if (view.getBackground() != null) {            view.getBackground().setCallback(null);        }        if (view instanceof ViewGroup) {            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {                unbindDrawables(((ViewGroup) view).getChildAt(i));            }            ((ViewGroup) view).removeAllViews();        }    }

以上几篇blog对于个人来说就是打基础,以便于得心应手的玩转Chart,如果在没看过该库的大体结构,个人感觉是蒙的,不知从何下手,只知道官方simple照着抄,以上相关blog有任何问题欢迎指教留言,我也是个逗比中的菜逼,千万跟我较真!!

0 0