????????????? Android开发之实现比特币走势图(仿股票走势图)

资讯 2024-07-16 阅读:187 评论:0
最近有关区块链的项目层出不穷,在项目中碰到了绘制比特币涨幅走势图的需求,在网上搜了一些案例,大致就是利用绘制贝塞尔曲线来完成。Recent projects relating to block chains have evolved, e...

最近有关区块链的项目层出不穷,在项目中碰到了绘制比特币涨幅走势图的需求,在网上搜了一些案例,大致就是利用绘制贝塞尔曲线来完成。

Recent projects relating to block chains have evolved, encountered the need for a Bitcoin upscaling map in the project, and examined some cases online, largely using the Bézier curve.

思路来源于绘制股票走势图,主要内容在于自定义K_View,效果图:

The idea stems from the mapping of stock trends, mainly in custom K_View, impact maps:



大致步骤:

General steps:

1、绘制X、Y坐标轴并绘制坐标;

1. Draw the X-Y-coordinate axis and draw the coordinates;

2、根据数据绘制走势图,其实就是根据返回数据的多个点连成的平滑曲线;

(ii) The mapping of trends based on data, which is a smooth curve linked to multiple points of returned data;

3、根据手势找点,然后绘制当前所在点并显示具体数据。

3. Find points based on gestures and then draw current points and display specific data.

相关数据对象类

Relevant data object class

public class FundMode? implements Serializable {

//x轴原始时间数据,ms

//x axis raw time data, ms

? ? public Stringtime;

public Stringlast;

public float dataY;

//在自定义view:FundView中的位置坐标

// in custom view: FundView

? ? public float floatX;

public float floatY;

}

public class XYEntityimplements Serializable{

public Listxlist;

public Listylist;

}

这里的内容只是让一些小白们看的更容易理解,早对象可以根据需求随意改动,各取所需。

The content here is simply easier for some white people to see, and the early audience can vary according to demand.

Xml布局中代码

The code in the Xml layout /i>

<XXXXX....K_VIew

? ? android:id="@+id/k_view"

? ? android:layout_width="match_parent"

? ? android:layout_height="@dimen/base130dp"

? ? app:xyTextSize="@dimen/base8sp"

? ? app:loadingTextSize="@dimen/base12sp"

? ? app:longPressTextSize="@dimen/base10sp"

? ? app:loadingText="正在加载数据...."

♪ App:loading Text= "loading data..."

? ? app:xBottomTopPadding="@dimen/base8dp"

? ? app:reactWidth="@dimen/base100dp"

? ? app:reactHeight="@dimen/base38dp"

? ? app:reactTextMargin_top="@dimen/base8dp"

? ? app:reactTextMargin_bottom="@dimen/base23dp"

? ? app:paddingTop_FV="@dimen/base10dp"

? ? app:paddingBottom_FV="@dimen/base20dp"

? ? app:paddingRight_FV="@dimen/base10dp"

? ? app:yTextPadding="@dimen/base10dp"

? ? app:yTextRightPadding="@dimen/base5dp"

? ? android:background="#fff"/>


attrs.xml 中内容大致就是一些自定义属性,内容如下

The contents of anatrs.xml are broadly defined properties, as follows:



activity 中需要执行的操作很少,从服务器获取到数据后 直接调用 k_view.setData(apiResult)即可;

Very few operations to perform in activity, call k_view.setData(apiResult) as soon as the data are obtained from the server;


下面是自定义view具体代码,所有逻辑都包括在里面了

Here's the custom code for the view. All the logic is in it.

public class K_View? extends View {

//控件默认宽高

// Control default width

private static final float DEF_WIDTH=650;

private static final float DEF_HIGHT=400;

//数据源

/ / data sources

? ApiResult2<List< FundMode>,XYEntity>>apiResult;

//ApiResult2 服务器返回的数据,FundMode平滑曲线上的点,XYEntity X、Y对应坐标,下面贴出数据结构

/ApiResult2 server returns data, FundMode smooth curve points, XYEntity X, Y corresponding coordinates, post the data structure below


//控件宽高

// Control width

? ? int mWidth;

int mHeight;

//上下左右padding

/ /padding up and down

? ? int mPaddingTop=30;

int mPaddingBottom=50;

int yTextPadding=20;

float mPaddingLeft=70;

int mPaddingRight=30;

int yTextRightPadding=5;

float textTopPadding=5;

int reactHeight=80;

int reactWidth=210;

int reactTextMargin_top=20;

int reactTextMargin_bottom=50

FundMode mMinFundMode;

FundMode mMaxFundMode;

float maxY;

float minY;

//X、Y轴每一个data对应的大小

//X, the size of each data at the Y axis

? ? float mPerX;

float mPerY;

//正在加载中

/ / loading in progress

? ? Paint mLoadingPaint;

int mLoadingTextSize=20;

String mLoadingText="";

boolean mDrawLoadingPaint=true;

Paint xyPaint;

//外围X、Y轴线文字

/ Perimeter X, Y axis text

? ? Paint mXYPaint;

Paint longPressPaint;

//x、y轴指示文字字体的大小

//x, y-axis indicates the font size of the text

? ? Paint rectTextPaint;

private int mXYTextSize=20;

//左侧文字距离左边线线的距离

// left text distance from left line

? ? final float mLeftTxtPadding=5;

//底部文字距离底部线的距离

// Bottom text distance from bottom line

? ? int xBottomTopPadding=20;

float halfTextWidth_X=22;

private ListpointData=new ArrayList<>();

private int pointCount;

//内部X轴虚线

// Internal X-axis

? ? Paint mInnerXPaint;

float mInnerXStrokeWidth=1;

//折线

Line / / / Line / Line / Line / Line / Line / Line / Line / Line / Line / Line / Line / Line / Line / Line / Line /

? ? Paint mBrokenPaint;

Paint rectBGPaint;

Paint alphaPaint;

//单位:dp

/ Unit: dp

//长按的十字线

// Long-pressed crosslines

? ? Paint mLongPressPaint;

Paint blueLinePaint;

boolean mDrawLongPressPaint=false;

//长按处理

// Long press process

? ? long mPressTime;

//默认多长时间算长按

// Default length of time

? ? final long DEF_LONGPRESS_LENGTH=200;

float mPressX;

float mPressY;

//最上面默认显示累计收益金额

Accumulated amount of proceeds shown by default above/above

? ? final float mDefAllIncomeTextSize=20;

//长按情况下x轴和y轴要显示的文字

Text to display in x-axis and y-axis in case of length

? ? Paint mLongPressTxtPaint;

int mLongPressTextSize=25;

public K_View(Context context) {

this(context,null);

}

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

this(context, attrs,0);

}

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

super(context, attrs, defStyleAttr);

TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.K_View);

mXYTextSize=a.getDimensionPixelSize(R.styleable.K_View_xyTextSize, mXYTextSize);

mLoadingTextSize=a.getDimensionPixelSize(R.styleable.K_View_loadingTextSize, mLoadingTextSize);

mLongPressTextSize=a.getDimensionPixelSize(R.styleable.K_View_longPressTextSize, mLongPressTextSize);

mLoadingText=a.getString(R.styleable.K_View_loadingText);

xBottomTopPadding=a.getDimensionPixelSize(R.styleable.K_View_xBottomTopPadding, xBottomTopPadding);

reactWidth=a.getDimensionPixelSize(R.styleable.K_View_reactWidth, reactWidth);

reactHeight=a.getDimensionPixelSize(R.styleable.K_View_reactHeight, reactHeight);

reactTextMargin_top=a.getDimensionPixelSize(R.styleable.K_View_reactTextMargin_top, reactTextMargin_top);

reactTextMargin_bottom=a.getDimensionPixelSize(R.styleable.K_View_reactTextMargin_bottom, reactTextMargin_bottom);

mPaddingTop=a.getDimensionPixelSize(R.styleable.K_View_paddingTop_FV, mPaddingTop);

mPaddingBottom=a.getDimensionPixelSize(R.styleable.K_View_paddingBottom_FV, mPaddingBottom);

mPaddingRight=a.getDimensionPixelSize(R.styleable.K_View_paddingRight_FV, mPaddingRight);

yTextPadding=a.getDimensionPixelSize(R.styleable.K_View_yTextPadding, yTextPadding);

yTextRightPadding=a.getDimensionPixelSize(R.styleable.K_View_yTextRightPadding, yTextRightPadding);

initAttrs();

}

@Override

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthSpecMode=MeasureSpec.getMode(widthMeasureSpec);

int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);

int heightSpecMode=MeasureSpec.getMode(heightMeasureSpec);

int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);

if (widthSpecMode==AT_MOST && heightSpecMode==AT_MOST) {

setMeasuredDimension((int) DEF_WIDTH, (int) DEF_HIGHT);

}else if (widthSpecMode==AT_MOST) {

setMeasuredDimension((int) DEF_WIDTH, heightSpecSize);

}else if (heightSpecMode==AT_MOST) {

setMeasuredDimension(widthSpecSize, (int) DEF_HIGHT);

}else {

setMeasuredDimension(widthSpecSize, heightSpecSize);

}

mWidth=getMeasuredWidth();

mHeight=getMeasuredHeight();

}

@Override

protected void onLayout(boolean changed,int left,int top,int right,int bottom) {

super.onLayout(changed, left, top, right, bottom);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//默认加载loading界面

/ / Default loading interface

? ? ? ? showLoadingPaint(canvas);

if (apiResult==null || apiResult.data.size()==0)return;

drawInnerXPaint(canvas);

drawBrokenPaint(canvas);

drawXYPaint(canvas);

drawLongPress(canvas);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

//? ? ? ? ? ? ? ? mPressTime=event.getDownTime();

? ? ? ? ? ? ? ? mPressX=event.getX();

mPressY=event.getY();

//处理长按后的逻辑

/ / Process long after logic

? ? ? ? ? ? ? ? showLongPressView();

break;

case MotionEvent.ACTION_MOVE:

mPressX=event.getX();

mPressY=event.getY();

//处理长按后的逻辑

/ / Process long after logic

? ? ? ? ? ? ? ? ? ? showLongPressView();

//? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? break;

case MotionEvent.ACTION_UP:

//处理松手后的逻辑

// Deal with the logic of letting go

? ? ? ? ? ? ? ? hiddenLongPressView();

break;

default:

break;

}

return true;

}

private void initAttrs() {

intXYLintPaint();

initRectBGPaint();

initLoadingPaint();

initRectTextPaint();

initInnerXPaint();

initXYPaint();

initBrokenPaint();

initAlphaPaint();

initLongPressPaint();

initYLinePaint();

//? ? ? ? initTopTxt();

? ? }

private void intXYLintPaint() {

xyPaint=new Paint();

xyPaint.setColor(getColor(R.color.gray));

xyPaint.setStrokeWidth(mInnerXStrokeWidth);

}

private void initRectBGPaint() {

rectBGPaint=getRectBGPaint();

}

private void initLoadingPaint() {

mLoadingPaint=new Paint();

mLoadingPaint.setColor(getColor(R.color.gray));

mLoadingPaint.setTextSize(mLoadingTextSize);

mLoadingPaint.setAntiAlias(true);

}

//初始化绘制虚线的画笔

// Initialize the brushing of the dotted line

? ? private void initInnerXPaint() {

mInnerXPaint=new Paint();

mInnerXPaint.setColor(getColor(R.color.bg_lsj));

mInnerXPaint.setStrokeWidth(mInnerXStrokeWidth);

mInnerXPaint.setAlpha(40);

mInnerXPaint.setStyle(Paint.Style.STROKE);

}

private void initXYPaint() {

mXYPaint=new Paint();

mXYPaint.setColor(getColor(R.color.text_dz));

mXYPaint.setTextSize(mXYTextSize);

mXYPaint.setAntiAlias(true);

}

private void initLongPressTextPaint() {

longPressPaint=new Paint();

longPressPaint.setColor(getColor(R.color.text_dz));

longPressPaint.setTextSize(mXYTextSize);

longPressPaint.setAntiAlias(true);

}

private void initRectTextPaint() {

rectTextPaint=new Paint();

rectTextPaint.setColor(getColor(R.color.white));

rectTextPaint.setTextSize(mXYTextSize);

rectTextPaint.setAntiAlias(true);

}

private void initBrokenPaint() {

mBrokenPaint=new Paint();

mBrokenPaint.setColor(getColor(R.color.all_k_color));

mBrokenPaint.setStyle(Paint.Style.STROKE);

mBrokenPaint.setAntiAlias(true);

mBrokenPaint.setStrokeWidth(convertDp2Px(mInnerXStrokeWidth));

}

private void initAlphaPaint() {

alphaPaint=new Paint();

alphaPaint.setColor(getResources().getColor(R.color.all_k_color));

alphaPaint.setAntiAlias(true);

alphaPaint.setAlpha(40);

alphaPaint.setStyle(Paint.Style.FILL);

}

private void initLongPressPaint() {

mLongPressPaint=new Paint();

mLongPressPaint.setColor(getColor(R.color.white));

mLongPressPaint.setStyle(Paint.Style.FILL);

mLongPressPaint.setAntiAlias(true);

mLongPressPaint.setTextSize(mLongPressTextSize);

}

private void initYLinePaint() {

blueLinePaint=new Paint();

blueLinePaint.setColor(getColor(R.color.bg_lsj));

blueLinePaint.setStrokeWidth(1);

blueLinePaint.setAntiAlias(true);

}

private void showLoadingPaint(Canvas canvas) {

if (!mDrawLoadingPaint)return;

//这里特别注意,x轴的起始点要减去文字宽度的一半

// Particular attention is given here that the starting point of the x-axis is less than half the width of the text

? ? ? ? canvas.drawText(mLoadingText, mWidth /2 - mLoadingPaint.measureText(mLoadingText) /2, mHeight /2, mLoadingPaint);

}

private void drawInnerXPaint(Canvas canvas) {

//画5条横轴的虚线

// Draws a thin line of 5 horizontal axes

//首先确定最大值和最小值的位置

/// First determine the location of maximum and minimum values

? ? ? ? float perHight=(mHeight - mPaddingBottom - mPaddingTop) /3;

canvas.drawLine(mPaddingLeft,mPaddingTop,mPaddingLeft,mHeight - mPaddingBottom,xyPaint);

canvas.drawLine(mPaddingLeft,mHeight - mPaddingBottom,mPaddingLeft+mPerX*(apiResult.data.size()-1),mHeight - mPaddingBottom,xyPaint);

canvas.drawLine(0 + mPaddingLeft, mPaddingTop,

mPaddingLeft+mPerX*(apiResult.data.size()-1), mPaddingTop, mInnerXPaint);//最上面的那一条

mPadddingLft+mPerX* (apiResult.data.size(()-1), mPadddingTop, mInnerXPaint);//

? ? ? ? canvas.drawLine(0 + mPaddingLeft, mPaddingTop + perHight *1,

mPaddingLeft+mPerX*(apiResult.data.size()-1), mPaddingTop + perHight *1, mInnerXPaint);//2

? ? ? ? canvas.drawLine(0 + mPaddingLeft, mPaddingTop + perHight *2,

mPaddingLeft+mPerX*(apiResult.data.size()-1), mPaddingTop + perHight *2, mInnerXPaint);//4

? ? }

private void drawBrokenPaint(Canvas canvas) {

if(pointData.size()>0){//清空所有点

if (pointData.size()>0) {/ emptied all points

? ? ? ? ? ? pointData.clear();

}

//先画第一个点

/// Draw the first dot first

? ? ? ? FundMode fundMode=apiResult.data.get(0);

Path path=new Path();

//这里需要说明一下,x轴的起始点,其实需要加上mPerX,但是加上之后不是从起始位置开始,不好看。

The starting point of the x-axis actually needs to be added to mPerX, but then it doesn't start from the beginning. It's not good.

// 同理,for循环内x轴其实需要(i+1)。现在这样处理,最后会留一点空隙,其实挺好看的。

/ Similarly, the x-axis in the for cycle actually need (i+1) to be dealt with now and eventually leave a little space, which is really pretty.

? ? ? ? float floatY=mHeight - mPaddingBottom - mPerY * ((Float.parseFloat(fundMode.last) - minY));

fundMode.floatX=mPaddingLeft;

fundMode.floatY=floatY;

Path timeAlphaPath=new Path();

timeAlphaPath.moveTo(mPaddingLeft, mHeight - mPaddingBottom);

timeAlphaPath.lineTo(mPaddingLeft, floatY);

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

FundMode fm=apiResult.data.get(i);

float floatX1=mPaddingLeft + mPerX * i;

float floatY1=mHeight - mPaddingBottom - mPerY * ((Float.parseFloat(fm.last) - minY));

fm.floatX=floatX1;

fm.floatY=floatY1;

if(i%pointCount==0||i==apiResult.data.size()-1){

pointData.add(fm);

}

if(i

float floatX2=mPaddingLeft + mPerX * (i+1);

float floatY2=mHeight - mPaddingBottom - mPerY * ( (Float.parseFloat(apiResult.data.get(i+1).last) - minY));

float wt=(floatX1 + floatX2) /2;

float floatX1_last=wt;

float floatY1_last=floatY1;

float floatX2_next=wt;

float floatY2_next=floatY2;

if(i==0){

path.moveTo(floatX1, floatY1);

}

path.cubicTo(floatX1_last, floatY1_last, floatX2_next, floatY2_next, floatX2, floatY2);

timeAlphaPath.cubicTo(floatX1_last, floatY1_last, floatX2_next, floatY2_next, floatX2, floatY2);

}else {

timeAlphaPath.lineTo(floatX1 , mHeight - mPaddingBottom);

Paint paint=new Paint();

paint.setColor(getColor(R.color.bg_lsj));

paint.setAntiAlias(true);

paint.setStrokeWidth(1);

paint.setStyle(Paint.Style.STROKE);

canvas.drawPath(path, paint);

paint.setAlpha(40);

paint.setStyle(Paint.Style.FILL);

canvas.drawPath(timeAlphaPath, paint);

}

}

}

private void drawXYPaint(Canvas canvas) {

//先处理y轴方向文字

// Deal with y-axis text first

? ? ? ? drawYPaint(canvas);

//处理x轴方向文字

// Process x-axis text

? ? ? ? drawXPaint(canvas);

}

*

* @param canvas

*/

private void drawLongPress(Canvas canvas) {

if (!mDrawLongPressPaint)return;

//获取距离最近按下的位置的model

// Get the model from the nearest position

? ? ? ? float pressX=mPressX;

//循环遍历,找到距离最短的x轴的mode

//Coop through, find the shortest x-axis mode

? ? ? ? FundMode finalFundMode=pointData.get(0);

float minXLen=Integer.MAX_VALUE;

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

FundMode currFunMode=pointData.get(i);

float abs=Math.abs(pressX - currFunMode.floatX);

if (abs < minXLen) {

finalFundMode=currFunMode;

minXLen=abs;

}

}

//x

? ? ? ? float topY=mHeight - mPaddingBottom - mPerY *? (maxY - minY);

int left=(int)finalFundMode.floatX-reactWidth>=mPaddingLeft?(int)finalFundMode.floatX-reactWidth:(int)finalFundMode.floatX;

int right=(int)finalFundMode.floatX-reactWidth>=mPaddingLeft?(int)finalFundMode.floatX:reactWidth+(int)finalFundMode.floatX;

int top=(int)finalFundMode.floatY-reactHeight>=(int)topY?(int)finalFundMode.floatY-reactHeight:(int)topY;

int bottom=(int)finalFundMode.floatY-reactHeight>=(int)topY?(int)finalFundMode.floatY:(int)topY+reactHeight;

Rect topDirty=new Rect(left, top, right, bottom);

canvas.drawRect(topDirty, rectBGPaint);

canvas.drawText(finalFundMode.time +"",

left+(reactWidth-mLongPressPaint.measureText(finalFundMode.time+""))/2,top+reactTextMargin_top+getFontHeight(mLongPressTextSize, mLongPressPaint) /2 , mLongPressPaint);

canvas.drawText("¥"+AppConfig.formatNum(finalFundMode.last) ,

left+(reactWidth-mLongPressPaint.measureText(finalFundMode.time+""))/2,top+reactTextMargin_bottom+getFontHeight(mLongPressTextSize, mLongPressPaint) /2 , mLongPressPaint);

}

public Paint getRectBGPaint() {

Paint paint=new Paint();

paint.setColor(Color.BLACK);

paint.setAntiAlias(true);

paint.setStrokeWidth(mInnerXStrokeWidth);

paint.setAlpha(85);

paint.setStyle(Paint.Style.FILL);

return paint;

}

//找到最大时间、最小时间和中间时间显示即可

/ / Find maximum time, minimum time and mid-time displays sufficient

? ? private void drawXPaint(Canvas canvas) {

if(apiResult.ext.xlist.size()>=6){

String firstX=apiResult.ext.xlist.get(0);

String secondX=apiResult.ext.xlist.get(1);

String thirdX=apiResult.ext.xlist.get(2);

String forthX=apiResult.ext.xlist.get(3);

String fifthX=apiResult.ext.xlist.get(4);

String sixX=apiResult.ext.xlist.get(5);

//x轴文字的高度

Height of //x-axis text

? ? ? ? ? ? halfTextWidth_X=mXYPaint.measureText(firstX)/2;

float hight=mHeight - mPaddingBottom + xBottomTopPadding;

canvas.drawText(firstX,

mPaddingLeft-halfTextWidth_X,

hight+textTopPadding, mXYPaint);

canvas.drawText(secondX,

mPaddingLeft + (mWidth - mPaddingLeft - mPaddingRight) /6-halfTextWidth_X,

hight+textTopPadding, mXYPaint);

canvas.drawText(thirdX,

mPaddingLeft + (mWidth - mPaddingLeft - mPaddingRight) /3f-halfTextWidth_X,

hight+textTopPadding, mXYPaint);

canvas.drawText(forthX,

mPaddingLeft + (mWidth - mPaddingLeft - mPaddingRight) /2-halfTextWidth_X,

hight+textTopPadding, mXYPaint);

canvas.drawText(fifthX,

mPaddingLeft + (mWidth - mPaddingLeft - mPaddingRight)*2 /3-halfTextWidth_X,

hight+textTopPadding, mXYPaint);

canvas.drawText(sixX,

mPaddingLeft + (mWidth - mPaddingLeft - mPaddingRight)*5/6-halfTextWidth_X,

hight+textTopPadding, mXYPaint);

}

}

private void drawYPaint(Canvas canvas) {

//现将最小值、最大值画好

//The minimum, maximum value is now done

//draw min

? ? ? ? if(apiResult.ext.ylist.size()>=4){

String firstY=apiResult.ext.ylist.get(0);

String secondY=apiResult.ext.ylist.get(1);

String thirdY=apiResult.ext.ylist.get(2);

String forthY=apiResult.ext.ylist.get(3);

float txtWigth=mXYPaint.measureText(firstY) ;

float perYWidth=(mHeight - mPaddingBottom - mPaddingTop) /3;

canvas.drawText(AppConfig.formatNum(firstY),

mPaddingLeft - txtWigth- yTextRightPadding,

mHeight - mPaddingBottom, mXYPaint);

//draw max

? ? ? ? ? ? canvas.drawText(AppConfig.formatNum(secondY),

mPaddingLeft - txtWigth- yTextRightPadding,

mPaddingTop+perYWidth*2+getFontHeight(mXYTextSize, mXYPaint) /4, mXYPaint);

canvas.drawText(AppConfig.formatNum(thirdY),

mPaddingLeft - txtWigth- yTextRightPadding,

mPaddingTop+perYWidth+getFontHeight(mXYTextSize, mXYPaint) /4, mXYPaint);

canvas.drawText(AppConfig.formatNum(forthY),

mPaddingLeft - txtWigth- yTextRightPadding,

mPaddingTop+getFontHeight(mXYTextSize, mXYPaint) /4, mXYPaint);

}

}

private void showLongPressView() {

mDrawLongPressPaint=true;

invalidate();

}

private void hiddenLongPressView() {

//实现蚂蚁金服延迟消失十字线

/// Delayed disappearance of ants

? ? ? ? postDelayed(new Runnable() {

@Override

public void run() {

mDrawLongPressPaint=false;

invalidate();

}

},200);

}

// 只需要把画笔颜色置为透明即可

/ / All you need to do is make the brush color transparent.

? ? private void hiddenLoadingPaint() {

mLoadingPaint.setColor(0x00000000);

mDrawLoadingPaint=false;

}

private void showLoadingPaint() {

mLoadingPaint.setColor(getColor(R.color.gray));

mDrawLoadingPaint=true;

}

private int getColor(@ColorResint colorId) {

return getResources().getColor(colorId);

}

private float convertDp2Px(float dpValue) {

final float scale=getContext().getResources().getDisplayMetrics().density;

return (dpValue * scale +0.5f);

}

public float getFontHeight(float fontSize, Paint paint) {

paint.setTextSize(fontSize);

Paint.FontMetrics fm=paint.getFontMetrics();

return (float) (Math.ceil(fm.descent - fm.top) +2);

}

? ? public void setData(ApiResult2, XYEntity> apiResult) {

this.apiResult=apiResult;

if (apiResult==null || apiResult.data.size()==0) {

showLoadingPaint();

invalidate();

}else {

if(apiResult.ext.ylist.size()>=4){

mPaddingLeft=mXYPaint.measureText(apiResult.ext.ylist.get(3))+yTextPadding;

maxY=Float.parseFloat(apiResult.ext.ylist.get(3));

minY=Float.parseFloat(apiResult.ext.ylist.get(0));

}

mPerX=(mWidth - mPaddingLeft - mPaddingRight) / (apiResult.data.size()-1);

mPerY=((mHeight - mPaddingTop - mPaddingBottom) /? (maxY - minY));

pointCount=(apiResult.data.size()-1)/24;

//数据过来,隐藏加载更多

/// Data come over, hide more loads

? ? ? ? ? ? hiddenLoadingPaint();

//刷新界面

// Refresh Interface

? ? ? ? ? ? invalidate();

}

}

}

自定义K_View中代码没做封装提取,理解起来相对容易。具体内容都是一些尺寸计算,看起来有点烧脑,但是静下心来慢慢咀嚼,会发现其实整个实现过程非常简单。在这基础上朋友们可以根据需求随意改动,实现更丰富多彩的效果。

Customizing the code in K_View without an encapsulation is relatively easy to understand. It's a few size calculations, it looks a little cerebral, but slowly chewing, and it turns out that the whole process of realization is very simple. On that basis, friends can change them as they want.



文字格式和图片示例

注册有任何问题请添加 微信:MVIP619 拉你进入群

弹窗与图片大小一致 文章转载注明

分享:

扫一扫在手机阅读、分享本文

发表评论
热门文章
  • 以太坊区块链浏览器的搭建

    以太坊区块链浏览器的搭建
    环境;Ubuntu 首先需要下载git 参考链接:?http://www.360bchain.com/article/156.html??Environment; Ubuntu first needs to download git reference link: ˂a rel="noformlow" href="http://www.360bchai.com/article/156.html"? http://www.360bchai.com/article/156.htm...
  • 百度元宇宙希壤app官方下载

    百度元宇宙希壤app官方下载
    希壤元宇宙是一款非常好玩的休闲手游,这款游戏采用了元宇宙的游戏概念,超级自由的游戏玩法,在这里没有什么标准限定,你可以自由的在这里进行着一切你想做的事情,游戏比较的休闲和放松,没有什么操作难度,感兴趣的小伙伴们可以来007游戏网下载这款非常有趣的希壤元宇宙吧!˂a href=http://m.yx007.com/key/xxsy" target="_blank" , a game that uses the concept of meta-cosm, super-free p...
  • 【CoinCentral 合作內容】加密貨幣 Decred 正式推出 2018 發展路段線圖

    【CoinCentral 合作內容】加密貨幣 Decred 正式推出 2018 發展路段線圖
    早些時候,加密貨幣Decred發表了一篇博客文章,概述了他們2018年的正式發展路線圖。Earlier, encrypt currency Decred published a blog article outlining their official road map for development in 2018.在這個路線圖中,團隊在為他們制定營銷宣傳之前,明確地表明他們於建立和發布可交付物品的成果,同時將他們的營銷集中在項目的核心組成部分。Decred團隊正在研究一些...
  • 跨接在两个网络间的语音记录仪设计

    跨接在两个网络间的语音记录仪设计
      摘  要: 设计了语音记录仪。该语音记录仪桥接在通信设备之间,同时提供3种桥接接口:以太网接口,支持在IP通信方式下的各通话组的直通及录音功能;二线接口,支持模拟二线方式下的直通及录音功能;音频接口,支持模拟音频方式下的直通及录音功能。同时话音记录仪提供FTP服务器,可以通过局域网对语音记录仪保存的语音文件进行下载和管理。此外,该设备支持语音回放功能。 extracts & nbsp; to : The voice record...
  • 元宇宙概念股有哪些 元宇宙概念股一览表

    元宇宙概念股有哪些 元宇宙概念股一览表
    元宇宙概念股排行精选 元宇宙概念股一览表(2022/11/08),下文就随小蔡来简单的了解一下吧。The contours of the meta-cosmology unit are in the list of the meta-cosmological concept units (2022/11/08), so let's get to the bottom of this with Little Choi. 元宇宙概念股龙头有:The contou...
标签列表