我们来看看下面的指示器 是如何绘制的 首先我们来看看跟之前的onDraw 有什么区别
mIndexMoveMeasure 计算了 指示器于柱状图 移动的差距比例 DrawIndex 绘制指示器
DrawIndex 我们来看看里面做了什么
-
首先这里绘制了 指示器上的三角形 moveX 计算指示器要移动的距离 通过刚才计算的 比例来计算
绘制指示器文本框 限制右边距
- 判断指示器 当前处于的位置 判断 topX 也就是三角形的 上边的x坐标 是不是 矩阵范围内, 不过这个时候有个问题空白区域的时候 就找不到因此 做一个处理 找不到时 绘制上一次绘制的文本
完整代码
<code>
package com.app.framework.widget.chart.rect;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.text.method.NumberKeyListener;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import java.util.ArrayList;
import java.util.List;
public class SlideRectChart extends AbsChart {
private static final String TAG = "SlideRectChart";
/**
* 柱子的画笔
*/
private Paint mSlideRectPaint;
/**绘制时间画笔*/
private Paint mTimePaint;
/**指示器画笔*/
private Paint mIndexPaint;
/**指示器文本画笔*/
private Paint mIndexTxtPaint;
/**
* 柱子的大小
*/
private float mRectSize;
/**move手指移动与 指针移动的比例*/
private float mIndexMoveMeasure;
/**
* 柱子之间的边距
*/
private float mRectLeft;
/**
* 右边超出的范围
*/
private float mRectDrawWidth;
public ArrayList<TimeData> mTimeData;
/**判断单位*/
private SlideRectEnum tag =SlideRectEnum.hour;
private List<Rect> mRectList;
private LinearGradient mLinearGradient;
public enum SlideRectEnum{
day,
month,
year,
hour,
}
public SlideRectChart(Context context) {
super(context);
init();
}
public SlideRectChart(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
if (mSlideRectPaint == null) {
mSlideRectPaint = new Paint();
}
mSlideRectPaint.setAntiAlias(true);
mSlideRectPaint.setStyle(Paint.Style.FILL);
mSlideRectPaint.setColor(Color.GREEN);
if(mTimePaint==null){
mTimePaint=new Paint();
}
mTimePaint.setAntiAlias(true);
mTimePaint.setStyle(Paint.Style.STROKE);
mTimePaint.setColor(Color.BLACK);
mTimePaint.setTextSize(dip2px(12));
mTimePaint.setTextAlign(Paint.Align.LEFT);
if(mIndexPaint==null){
mIndexPaint=new Paint();
}
mIndexPaint.setAntiAlias(true);
mIndexPaint.setStyle(Paint.Style.FILL);
mIndexPaint.setColor(Color.BLUE);
if(mIndexTxtPaint==null){
mIndexTxtPaint=new Paint();
}
mIndexTxtPaint.setAntiAlias(true);
mIndexTxtPaint.setStyle(Paint.Style.FILL);
mIndexTxtPaint.setColor(Color.WHITE);
mIndexTxtPaint.setTextSize(dip2px(12));
mIndexTxtPaint.setTextAlign(Paint.Align.CENTER);
getBrokenLinePaint().setTextSize(dip2px(12));
getBrokenLinePaint().setStrokeWidth(dip2px(0.5f));
getBrokenLinePaint().setStyle(Paint.Style.FILL);
}
@Override
public void setValue(float[] value) {
super.setValue(value);
this.mSlideX=0;
}
public void setTimeData(ArrayList<TimeData> timeData){
this.mTimeData =timeData;
}
public void setTag(SlideRectEnum slideRectEnum){
this.tag=slideRectEnum;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mRectSize = getViewWidth() / 24;
mRectLeft = dip2px(4);
mRectList=new ArrayList<>();
mLinearGradient = new LinearGradient(getBrokenLineLeft()-1 ,getBrokenLineTop(),getBrokenLineLeft(),getBrokenLineTop(),new int[]{0x00ffffff,Color.BLUE}, null, Shader.TileMode.CLAMP);
getBrokenLinePaint().setShader(mLinearGradient);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
onTouchEvent(event);
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**计算最多移动的距离*/
mRectDrawWidth = ((mRectLeft * mPoints.length) + (mRectSize * mPoints.length + getBrokenLineLeft() - getViewWidth()));
mIndexMoveMeasure=getNeedDrawWidth()/mRectDrawWidth;
DrawRect(canvas);
DrawIndex(canvas);
}
private String oldText="";
/**绘制指示器*/
private void DrawIndex(Canvas canvas) {
float moveX=mSlideX*mIndexMoveMeasure;
float leftX=getBrokenLineLeft()+moveX;
float rightX=getBrokenLineLeft()+mRectSize+moveX;
float topX =rightX-(rightX-leftX)/2;
float topY=getNeedDrawHeight()+getBrokenLineTop()+2;
float bottomY=getNeedDrawHeight()+getBrokenLineTop()+mRectSize/2;
if(leftX>=getViewWidth()-mRectSize-mRectLeft){
leftX=getViewWidth()-mRectSize-mRectLeft;
rightX=getViewWidth()-mRectLeft;
topX=rightX-(rightX-leftX)/2;
}
Path mPath=new Path();
mPath.moveTo(leftX,bottomY);
mPath.lineTo(topX,topY);
mPath.lineTo(rightX,bottomY);
mPath.lineTo(leftX,bottomY);
canvas.drawPath(mPath,mIndexPaint);
/**绘制指示器举证*/
Rect belowRect=new Rect();
int left= (int) (leftX-getBrokenLineLeft());
int right = (int) (leftX+getBrokenLineLeft());
int top= (int) (topY+getBrokenLineTop()/1.5);
int bottom=getViewHeight();
if(right>=getViewWidth()-mRectLeft){
left= (int) (getViewWidth()-mRectLeft-getBrokenLineLeft()*2);
right= (int) (getViewWidth()-mRectLeft);
}
belowRect.left=left;
belowRect.right=right;
belowRect.top=top;
belowRect.bottom=bottom;
canvas.drawRect(belowRect,mIndexPaint);
int bx=belowRect.left+(belowRect.right-belowRect.left)/2;
for (int i = 0; i < mRectList.size(); i++) {
Rect rect=mRectList.get(i);
if(rect.left<=topX && rect.right>=topX ){
if(tag==SlideRectEnum.hour) {
oldText=mTimeData.get(i).getHour() + ":00" + " γ: " + floatKeepTwoDecimalPlaces(getValue()[i]);
canvas.drawText(oldText, bx, getHeight() - dip2px(2), mIndexTxtPaint);
}
if(tag==SlideRectEnum.day) {
oldText=mTimeData.get(i).getDay() + "日" + " γ: " + floatKeepTwoDecimalPlaces(getValue()[i]);
canvas.drawText(oldText, bx, getHeight() - dip2px(2), mIndexTxtPaint);
}
break;
}
if(mRectList.size()==i+1){
canvas.drawText(oldText, bx, getHeight() - dip2px(2), mIndexTxtPaint);
}
}
}
/**绘制矩阵*/
private void DrawRect(Canvas canvas) {
mRectList.clear();
for (int i = 0; i < mPoints.length; i++) {
Point point = mPoints[i];
Rect rect = new Rect();
int left = (int) ((mRectLeft * i) + (mRectSize * i + getBrokenLineLeft()) - mSlideX);
int right = ((int) ((mRectLeft * i) + (mRectSize * i + mRectSize + getBrokenLineLeft() - mSlideX)));
if(tag==SlideRectEnum.hour){
if(mTimeData!=null){
TimeData timeData=mTimeData.get(i);
if(i==0 || timeData.getHour()==1){
canvas.drawLine(left,getNeedDrawHeight()+getBrokenLineTop(),left,0,getBrokenLinePaint());
canvas.drawText(timeData.getDay()+"日",left+2,getBrokenLineTop(),getBrokenLinePaint());
}
}
}
if(tag==SlideRectEnum.day){
if(mTimeData!=null){
TimeData timeData=mTimeData.get(i);
if(i==0 || timeData.getDay()==1){
canvas.drawLine(left,getNeedDrawHeight()+getBrokenLineTop(),left,0,getBrokenLinePaint());
canvas.drawText(timeData.getMonth()+"月",left+2,getBrokenLineTop(),getBrokenLinePaint());
}
}
}
/**限制柱状绘制范围*/
if (left < getBrokenLineLeft()) {
left = (int) getBrokenLineLeft();
}
if (right < getBrokenLineLeft()) {
right = (int) getBrokenLineLeft();
}
rect.left = left;
rect.right = right;
rect.bottom = (int) (getNeedDrawHeight() + getBrokenLineTop());
rect.top = point.y;
mRectList.add(rect);
canvas.drawRect(rect, mSlideRectPaint);
}
}
private float mSlideX = 0;
private float mLastDownX;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastDownX = event.getX();
return true;
case MotionEvent.ACTION_UP:
mSlideX += (mLastDownX - event.getX());
mLastDownX = event.getX();
if (mSlideX <= 0) {
mSlideX = 0;
}
if (mSlideX >= mRectDrawWidth) {
mSlideX = mRectDrawWidth;
}
postInvalidate();
return true;
case MotionEvent.ACTION_MOVE:
mSlideX += (mLastDownX - event.getX());
mLastDownX = event.getX();
if (mSlideX <= 0) {
mSlideX = 0;
}
if (mSlideX >= mRectDrawWidth) {
mSlideX = mRectDrawWidth;
}
postInvalidate();
return true;
}
return true;
}
}
</code >