由于个人能力有限,不能再跟着仔细看源码了,感觉每个类关联甚多,决定直接从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有任何问题欢迎指教留言,我也是个逗比中的菜逼,千万跟我较真!!