1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > android自定义曲线控件 Android自定义折线图(可拖动显示)

android自定义曲线控件 Android自定义折线图(可拖动显示)

时间:2023-02-07 19:32:37

相关推荐

android自定义曲线控件 Android自定义折线图(可拖动显示)

废话不多说先上图咯

图一

至于怎么做呢 咱们可以先获取下折线图数据分析一波

{

"code": 200,

"message": "",

"data": {

"list": [

{

"day": "-10-22",

"readCount": 0,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-21",

"readCount": 0,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-20",

"readCount": 1,

"okGroupCount": 0,

"streamCount": 17,

"buyCount": 0

},

{

"day": "-10-19",

"readCount": 0,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-18",

"readCount": 0,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-17",

"readCount": 1,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-16",

"readCount": 4,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-15",

"readCount": 3,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-14",

"readCount": 1,

"okGroupCount": 0,

"streamCount": 2,

"buyCount": 0

},

{

"day": "-10-13",

"readCount": 4,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-12",

"readCount": 2,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-11",

"readCount": 0,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

},

{

"day": "-10-10",

"readCount": 3,

"okGroupCount": 0,

"streamCount": 0,

"buyCount": 0

}

]

}

}

获取到数据后 我对数据先进行了稍微处理 循环遍历获取他们里面最大值,当做表格的上限,当然 我最后表格的上限是用的最大值又乘了1.1

图二

javaBean AdvLineChart

//广告折线图bean

public class AdvLineChart {

private String day;

private long readCount; //阅读人数

private long okGroupCount; //拼成数量

private long streamCount; //引流量

private long buyCount; //下单量

private String dayDetail; //自己转换的日期 不带年

private float x;

private int position;

public String getDay() {

return day;

}

public void setDay(String day) {

this.day = day;

}

public long getReadCount() {

return readCount;

}

public void setReadCount(long readCount) {

this.readCount = readCount;

}

public long getOkGroupCount() {

return okGroupCount;

}

public void setOkGroupCount(long okGroupCount) {

this.okGroupCount = okGroupCount;

}

public long getStreamCount() {

return streamCount;

}

public void setStreamCount(long streamCount) {

this.streamCount = streamCount;

}

public long getBuyCount() {

return buyCount;

}

public void setBuyCount(long buyCount) {

this.buyCount = buyCount;

}

public String getDayDetail() {

return dayDetail;

}

public void setDayDetail(String dayDetail) {

this.dayDetail = dayDetail;

}

public float getX() {

return x;

}

public void setX(float x) {

this.x = x;

}

public int getPosition() {

return position;

}

public void setPosition(int position) {

this.position = position;

}

}

处理过数据后 我们就开始绘制了,我们可以把list里的每一个数据 当做一条竖线 for循环挨个绘制他们

下面我直接贴出自定义view的代码了 里面注释还是蛮清晰的:

里面有一些缺少的类 就是一些dp、数量转换 可以自己定义

//广告折线图

public class AdvLineChartView extends View {

private final static int PADDING_START_ADN_END = 10; //距离左右边距

private float mWidth;

private float mHeight;

private Rect mTopTextRect;

private Rect mBottomTextRect;

private Rect mTipTextRect;

private Paint mLinePaint;

private Paint mTopTextPaint;

private Paint mBottomTextPaint;

private Paint mTipTextPaint;

private Paint mTipTextBgPaint;

private long advMax; //最大价格值

private float max; //最大1.1

private float downX, downY; //按下的位置

private float moveY; //移动的y点

private float lineHeight; //线高

private List advList = new ArrayList<>(); //各个点信息

private AdvLineChart tipViewData;

private CallBack mCallBack;

public AdvLineChartView(Context context) {

this(context, null);

}

public AdvLineChartView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public AdvLineChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mTopTextRect = new Rect();

mBottomTextRect = new Rect();

mTipTextRect = new Rect();

mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mLinePaint.setStrokeWidth(2);

mTopTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mTopTextPaint.setColor(getContext().getResources().getColor(R.color.c_1D1D1D));

mTopTextPaint.setTextSize(DensityUtil.dip2px(getContext(), 8));

mBottomTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mBottomTextPaint.setColor(getContext().getResources().getColor(R.color.c_1D1D1D));

mBottomTextPaint.setTextSize(DensityUtil.dip2px(getContext(), 7));

mTipTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mTipTextBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mTipTextBgPaint.setStrokeWidth(2);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

mWidth = getMeasuredWidth();

mHeight = getMeasuredHeight();

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

//点击记录位置

downX = event.getX();

downY = event.getY();

moveY = event.getY();

return true;

case MotionEvent.ACTION_MOVE:

moveY = event.getY();

AdvLineChart clickOnPoint1 = getClickOnPoint(event.getX());

if (null != clickOnPoint1) {

//绘制提示view

tipViewData = clickOnPoint1;

invalidate();

}

//父布局不拦截子布局事件

getParent().requestDisallowInterceptTouchEvent(true);

return true;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

//松开时判断 松开位置在点击位置的有效范围内

if (Math.abs(downX - event.getX()) <= 2 && Math.abs(downY - event.getY()) <= 2) {

AdvLineChart clickOnPoint2 = getClickOnPoint(event.getX());

if (null != clickOnPoint2) {

//绘制提示view

tipViewData = clickOnPoint2;

invalidate();

return true;

} else {

return super.onTouchEvent(event);

}

} else {

return super.onTouchEvent(event);

}

}

return super.onTouchEvent(event);

}

@SuppressLint("DrawAllocation")

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

float paddingStartAndEnd = DensityUtil.dip2px(getContext(), PADDING_START_ADN_END);

for (int i = 0; i < advList.size(); i++) {

AdvLineChart data = advList.get(i);

String topText = data.getDay();

String bottomText = data.getDayDetail();

mTopTextPaint.setColor(getContext().getResources().getColor(R.color.c_1D1D1D));

mTopTextPaint.getTextBounds(topText, 0, topText.length(), mTopTextRect);

mBottomTextPaint.getTextBounds(bottomText, 0, bottomText.length(), mBottomTextRect);

//计算各条线x点

float x = calculationPositionX(i);

//竖线高度

lineHeight = mHeight - mTopTextRect.height() - mBottomTextRect.height() - DensityUtil.dip2px(getContext(), 16);

/** 绘制竖线 **/

drawLine(canvas, x, 0, x, lineHeight);

/** 绘制文字 **/

canvas.drawText(topText, x - mTopTextRect.width() / 2f,

mHeight - DensityUtil.dip2px(getContext(), 9) - mBottomTextRect.height(), mTopTextPaint);

canvas.drawText(bottomText, x - mBottomTextRect.width() / 2f,

mHeight - DensityUtil.dip2px(getContext(), 7), mBottomTextPaint);

/** 绘制横线 只绘制一次 **/

if (i == 0) {

drawLine(canvas, paddingStartAndEnd, 1, mWidth - paddingStartAndEnd, 1);

drawLine(canvas, paddingStartAndEnd, lineHeight / 2, mWidth - paddingStartAndEnd, lineHeight / 2);

drawLine(canvas, paddingStartAndEnd, lineHeight, mWidth - paddingStartAndEnd, lineHeight);

}

/** 绘制分数线 **/

if (i < advList.size() - 1 && max >= 0) {

AdvLineChart nextData = advList.get(i + 1);

//下一个x点

float nextX = calculationPositionX(i + 1);

/** 阅读人数 **/

drawLine(canvas, x, calculationPositionY(lineHeight, data.getReadCount()),

nextX, calculationPositionY(lineHeight, nextData.getReadCount()),

getResources().getColor(R.color.c_BF383E));

/** 拼成数量 **/

drawLine(canvas, x, calculationPositionY(lineHeight, data.getOkGroupCount()),

nextX, calculationPositionY(lineHeight, nextData.getOkGroupCount()),

getResources().getColor(R.color.c_FFC90D));

/** 引流数量 **/

drawLine(canvas, x, calculationPositionY(lineHeight, data.getStreamCount()),

nextX, calculationPositionY(lineHeight, nextData.getStreamCount()),

getResources().getColor(R.color.lightpink));

/** 下单数量 **/

drawLine(canvas, x, calculationPositionY(lineHeight, data.getBuyCount()),

nextX, calculationPositionY(lineHeight, nextData.getBuyCount()),

getResources().getColor(R.color.darkviolet));

//设置当前位置数据的坐标

data.setX(x);

data.setPosition(i);

//最后一个了 把nextX加进去

if (i == advList.size() - 2) {

nextData.setX(nextX);

nextData.setPosition(i + 1);

//默认显示成第一个

if (null == tipViewData) {

tipViewData = advList.get(advList.size() - 1);

moveY = 1;//calculationPositionY(lineHeight, advList.get(advList.size() - 1).getReadCount());

}

}

}

}

//绘制提示view

if (null != tipViewData) {

moveY = moveY < 1 ? 1 : moveY > lineHeight ? lineHeight : moveY;

String title = tipViewData.getDay() + "-" + tipViewData.getDayDetail().replace("/", "-");

String readStr = "阅读";

String read = StringUtil.getLastNum(tipViewData.getReadCount()) + "人";

String okGroupStr = "拼成";

String okGroup = StringUtil.getLastNum(tipViewData.getOkGroupCount()) + "个";

String streamStr = "引流";

String stream = StringUtil.getLastNum(tipViewData.getStreamCount()) + "次";

String buyStr = "下单";

String buy = StringUtil.getLastNum(tipViewData.getBuyCount()) + "笔";

mTipTextPaint.setTextSize(DensityUtil.dip2px(getContext(), 12));

mTipTextPaint.getTextBounds(title, 0, title.length(), mTipTextRect);

//标题高度

int titleHeight = mTipTextRect.height();

mTipTextPaint.setTextSize(DensityUtil.dip2px(getContext(), 10));

mTipTextPaint.getTextBounds(read, 0, read.length(), mTipTextRect);

//其他内容的高度

int otherHeight = mTipTextRect.height();

//阅读宽度

int readWidth = mTipTextRect.width();

mTipTextPaint.getTextBounds(okGroup, 0, okGroup.length(), mTipTextRect);

//拼成宽度

int okGroupWidth = mTipTextRect.width();

mTipTextPaint.getTextBounds(stream, 0, stream.length(), mTipTextRect);

//引流宽度

int streamWidth = mTipTextRect.width();

mTipTextPaint.getTextBounds(buy, 0, buy.length(), mTipTextRect);

//下单宽度

int buyWidth = mTipTextRect.width();

//x点位置

float tipViewX;

if (tipViewData.getX() + DensityUtil.dip2px(getContext(), 80) > mWidth - paddingStartAndEnd) {

tipViewX = mWidth - paddingStartAndEnd - DensityUtil.dip2px(getContext(), 80);

} else {

tipViewX = tipViewData.getX();

}

//框高度 padding上下7 标题padding下3 其他3个文字padding上下3 最后其他文字的上3 加起来就是38

int rectHeight = DensityUtil.dip2px(getContext(), 38) + titleHeight + otherHeight * 4;

//y点位置

if (moveY + rectHeight > lineHeight) {

moveY = lineHeight - rectHeight;

}

/** 绘制白色覆盖背景 **/

RectF rectF = new RectF(tipViewX, moveY,

tipViewX + DensityUtil.dip2px(getContext(), 80), moveY + rectHeight);

mTipTextBgPaint.setStyle(Paint.Style.FILL);

mTipTextBgPaint.setColor(Color.WHITE);

canvas.drawRoundRect(rectF, 0, 0, mTipTextBgPaint);

/** 绘制背景边框 **/

mTipTextBgPaint.setStyle(Paint.Style.STROKE);

mTipTextBgPaint.setColor(getResources().getColor(R.color.c_1D1D1D));

canvas.drawRoundRect(rectF, 0, 0, mTipTextBgPaint);

//strText前面距离

int strText = DensityUtil.dip2px(getContext(), 4);

/** 标题 **/

//标题y位置

float titleY = moveY + DensityUtil.dip2px(getContext(), 7) + titleHeight;

mTipTextPaint.setColor(getContext().getResources().getColor(R.color.c_BF383E));

canvas.drawText(title, tipViewX + strText, titleY, mTipTextPaint);

/** 阅读 **/

//阅读y位置

float readY = titleY + DensityUtil.dip2px(getContext(), 6) + otherHeight;

mTipTextPaint.setColor(getContext().getResources().getColor(R.color.c_BF383E));

canvas.drawText(readStr, tipViewX + strText, readY, mTipTextPaint);

canvas.drawText(read, rectF.right - readWidth - strText, readY, mTipTextPaint);

/** 拼成 **/

//拼成y位置

float okGroupY = readY + DensityUtil.dip2px(getContext(), 6) + otherHeight;

mTipTextPaint.setColor(getContext().getResources().getColor(R.color.c_FFC90D));

canvas.drawText(okGroupStr, tipViewX + strText, okGroupY, mTipTextPaint);

canvas.drawText(okGroup, rectF.right - okGroupWidth - strText, okGroupY, mTipTextPaint);

/** 引流 **/

//引流y位置

float streamY = okGroupY + DensityUtil.dip2px(getContext(), 6) + otherHeight;

mTipTextPaint.setColor(getContext().getResources().getColor(R.color.lightpink));

canvas.drawText(streamStr, tipViewX + strText, streamY, mTipTextPaint);

canvas.drawText(stream, rectF.right - streamWidth - strText, streamY, mTipTextPaint);

/** 下单 **/

//下单y位置

float buyY = streamY + DensityUtil.dip2px(getContext(), 6) + otherHeight;

mTipTextPaint.setColor(getContext().getResources().getColor(R.color.darkviolet));

canvas.drawText(buyStr, tipViewX + strText, buyY, mTipTextPaint);

canvas.drawText(buy, rectF.right - buyWidth - strText, buyY, mTipTextPaint);

/** 绘制选中的竖线 **/

drawLine(canvas, tipViewData.getX() < paddingStartAndEnd ? paddingStartAndEnd :

tipViewData.getX() > mWidth - paddingStartAndEnd ? mWidth - paddingStartAndEnd : tipViewData.getX(),

0, tipViewData.getX() < paddingStartAndEnd ? paddingStartAndEnd :

tipViewData.getX() > mWidth - paddingStartAndEnd ? mWidth - paddingStartAndEnd : tipViewData.getX(),

tipViewData.getX() > rectF.left && tipViewData.getX() < rectF.right ? rectF.top - 2 : lineHeight,

getResources().getColor(R.color.c_ED1C24), 3);

/** 绘制下半截的竖线 **/

if (tipViewData.getX() > rectF.left && tipViewData.getX() < rectF.right) {

drawLine(canvas, tipViewData.getX() < paddingStartAndEnd ? paddingStartAndEnd :

tipViewData.getX() > mWidth - paddingStartAndEnd ? mWidth - paddingStartAndEnd : tipViewData.getX(),

rectF.bottom + 2, tipViewData.getX() < paddingStartAndEnd ? paddingStartAndEnd :

tipViewData.getX() > mWidth - paddingStartAndEnd ? mWidth - paddingStartAndEnd : tipViewData.getX(), lineHeight,

getResources().getColor(R.color.c_ED1C24), 3);

}

if (null != mCallBack) {

mCallBack.pointClick(tipViewData, moveY);

}

}

}

/**

* 设置数据

*/

public void setData(List shopList, long shopMax) {

this.advMax = shopMax;

if (null != shopList && shopList.size() > 0) {

this.advList.clear();

this.advList.addAll(shopList);

max = (float) (this.advMax * 1.1);

invalidate();

}

}

/**

* 移动tipsView pre是否往前 num数量

*/

public void moveTipsView(boolean pre, int num) {

if (null != tipViewData) {

//前移 因为数据是从最新的开始排的 所以往后选

if (pre) {

if (tipViewData.getPosition() + num < advList.size()) {

tipViewData = advList.get(tipViewData.getPosition() + num);

} else {

tipViewData = advList.get(advList.size() - 1);

}

invalidate();

} else { //后移

if (tipViewData.getPosition() - num >= 0) {

tipViewData = advList.get(tipViewData.getPosition() - num);

} else {

tipViewData = advList.get(0);

}

invalidate();

}

}

}

private void drawLine(Canvas canvas, float startX, float startY, float endX, float endY) {

drawLine(canvas, startX, startY, endX, endY, getResources().getColor(R.color.c_1D1D1D), 2);

}

private void drawLine(Canvas canvas, float startX, float startY, float endX, float endY, int color) {

drawLine(canvas, startX, startY, endX, endY, color, 2);

}

private void drawLine(Canvas canvas, float startX, float startY, float endX, float endY, int color, int strokeWidth) {

mLinePaint.setColor(color);

mLinePaint.setStrokeWidth(strokeWidth);

canvas.drawLine(startX, startY, endX, endY, mLinePaint);

}

//计算x位置

private float calculationPositionX(int i) {

//当前数组是从大到小的 计算x点时从最后面开始算

return (mWidth - DensityUtil.dip2px(getContext(), PADDING_START_ADN_END * 2)) /

(advList.size() - 1) * (advList.size() - 1 - i) +

DensityUtil.dip2px(getContext(), PADDING_START_ADN_END);

}

//计算y位置

private float calculationPositionY(float lineHeight, long currentNum) {

float currentPositionY = lineHeight * advMax / max;

float scale = (1 - currentNum / (float) advMax);

return scale == 1 ? lineHeight : lineHeight - currentPositionY + currentPositionY * scale;

}

//计算当前点击是否在点上 是的话返回点对象 否则null

private AdvLineChart getClickOnPoint(float x) {

AdvLineChart advLineChartReturn = null;

for (AdvLineChart advLineChart : advList) {

if (Math.abs(x - advLineChart.getX()) < mWidth / advList.size() / 2) {

advLineChartReturn = advLineChart;

break;

}

}

return advLineChartReturn;

}

public void setOnMoveListener(CallBack callBack) {

this.mCallBack = callBack;

}

public interface CallBack {

void pointClick(AdvLineChart advLineChart, float rawY);

}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。