2019-03-05 自定義View繪制線性表

? ? ? 自定義View繪圖,學(xué)的就是用的,怎么方便怎么來(lái),就像隨手涂鴉一樣,以后都不會(huì)再

拾起,所以沒(méi)怎么封裝,也不標(biāo)準(zhǔn)。
第一次寫(xiě)個(gè)稍微完整點(diǎn)的例子,寫(xiě)的不好還請(qǐng)多多指教..

1、先來(lái)效果圖:

圖1
圖2



素材1
素材2
素材3

2、圖1的源碼:

package com.lipy.linechart;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.support.annotation.Nullable;

import android.util.AttributeSet;

import android.util.TypedValue;

import android.view.View;

import android.widget.Switch;

import java.util.ArrayList;

import java.util.List;

public class TrendLineChartView extends View {

? ? private List<Integer> trendData;? ? //走勢(shì)數(shù)據(jù)

? ? private Paint redPaint,blackPaint,greenPaint; //圓點(diǎn)畫(huà)筆

? ? private Paint realLinePaint,dashLinePaint;? //實(shí)線和灰線畫(huà)筆

? ? private int defaultPadding = this.dp2px(getContext(),5); //默認(rèn)內(nèi)邊距

? ? private int dotRadius = this.dp2px(getContext(),4);? ? //圓點(diǎn)的半徑

? ? /**

? ? * 設(shè)置走勢(shì)數(shù)據(jù)

? ? * 列表首項(xiàng)是最遠(yuǎn)天數(shù),畫(huà)在圖表的最左邊

? ? * 數(shù)據(jù)值對(duì)應(yīng)? 1:紅點(diǎn),0:綠點(diǎn),-1:黑點(diǎn)

? ? */

? ? public void setTrendData(List<Integer> trendData){

? ? ? ? this.trendData = trendData;

? ? ? ? invalidate();

? ? }

? ? public TrendLineChartView(Context context) {

? ? ? ? this(context,null);

? ? }

? ? public TrendLineChartView(Context context, @Nullable AttributeSet attrs) {

? ? ? ? super(context, attrs);

? ? ? ? init();

? ? }

? ? private void init() {

? ? ? ? dashLinePaint = new Paint();

? ? ? ? dashLinePaint.setColor(Color.GRAY);

? ? ? ? dashLinePaint.setAlpha(100);

? ? ? ? dashLinePaint.setStrokeWidth(1.5f);

? ? ? ? realLinePaint = new Paint(dashLinePaint);

? ? ? ? realLinePaint.setColor(Color.parseColor("#555555"));

? ? ? ? realLinePaint.setAntiAlias(true);

? ? ? ? realLinePaint.setStrokeWidth(1.8f);

? ? ? ? redPaint = new Paint(realLinePaint);

? ? ? ? redPaint.setColor(Color.RED);

? ? ? ? redPaint.setStyle(Paint.Style.FILL);

? ? ? ? greenPaint = new Paint(redPaint);

? ? ? ? greenPaint.setColor(Color.GREEN);

? ? ? ? blackPaint = new Paint(greenPaint);

? ? ? ? blackPaint.setColor(Color.BLACK);

? ? }

? ? @Override

? ? protected void onDraw(Canvas canvas) {

? ? ? ? super.onDraw(canvas);

? ? ? ? drawBackground(canvas);

? ? ? ? drawData(canvas);

? ? }

? ? //繪制數(shù)據(jù)

? ? private void drawData(Canvas canvas) {

? ? ? ? int width = canvas.getWidth();

? ? ? ? int height = canvas.getHeight();

? ? ? ? if (trendData == null){

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? if (trendData.size() <= 1){

? ? ? ? ? ? //數(shù)據(jù)只有一條時(shí),默認(rèn)畫(huà)在中間

? ? ? ? ? ? canvas.drawCircle(width/2,getDrawHeight(height,trendData.get(0)),dotRadius,getPaint(trendData.get(0)));

? ? ? ? }

? ? ? ? else{

? ? ? ? ? ? float space = (width-defaultPadding*2)/(trendData.size()-1);

? ? ? ? ? ? //畫(huà)折線

? ? ? ? ? ? for (int i = 0; i < trendData.size()-1; i++) {

? ? ? ? ? ? ? ? canvas.drawLine(defaultPadding+i*space,getDrawHeight(height,trendData.get(i)),defaultPadding+(i+1)*space,getDrawHeight(height,trendData.get(i+1)),realLinePaint);

? ? ? ? ? ? }

? ? ? ? ? ? //畫(huà)圓點(diǎn)

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

? ? ? ? ? ? ? ? canvas.drawCircle(defaultPadding+i*space,getDrawHeight(height,trendData.get(i)),dotRadius,getPaint(trendData.get(i)));

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? //畫(huà)三條虛線組成的背景

? ? private void drawBackground(Canvas canvas) {

? ? ? ? int width = canvas.getWidth();

? ? ? ? int height = canvas.getHeight();

? ? ? ? canvas.drawLine(defaultPadding,defaultPadding,width-defaultPadding,defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine(defaultPadding,height/2,width-defaultPadding,height/2,dashLinePaint);

? ? ? ? canvas.drawLine(defaultPadding,height-defaultPadding,width-defaultPadding,height-defaultPadding,dashLinePaint);

? ? }

? ? /**

? ? * 更具trendData數(shù)據(jù)獲得對(duì)應(yīng)顏色的畫(huà)筆

? ? */

? ? private Paint getPaint(int result){

? ? ? ? if (result == -1){

? ? ? ? ? ? return blackPaint;

? ? ? ? }

? ? ? ? else if (result == 0){

? ? ? ? ? ? return? greenPaint;

? ? ? ? }

? ? ? ? else if (result == 1){

? ? ? ? ? ? return redPaint;

? ? ? ? }

? ? ? ? return greenPaint;

? ? }

? ? /**

? ? * @param height? ? 控件的總高度

? ? * @param result? ? 數(shù)據(jù)的走勢(shì)

? ? * @return? 計(jì)算出該圓點(diǎn)的Y坐標(biāo)

? ? */

? ? private int getDrawHeight(int height,int result){

? ? ? ? if (result == -1){

? ? ? ? ? ? return height - defaultPadding;

? ? ? ? }

? ? ? ? else if (result == 0){

? ? ? ? ? ? return? height/2;

? ? ? ? }

? ? ? ? else if (result == 1){

? ? ? ? ? ? return defaultPadding;

? ? ? ? }

? ? ? ? return height/2;

? ? }

? ? private int dp2px(Context context, int dip) {

? ? ? ? final float scale = context.getResources().getDisplayMetrics().density;

? ? ? ? return (int) (dip * scale + 0.5f);

? ? }

? ? private int sp2px(Context context, float spValue) {

? ? ? ? return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics());

? ? }

}

3、圖2的源碼:

package com.lipy.linechart;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.BitmapShader;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.LinearGradient;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.Rect;

import android.graphics.Shader;

import android.graphics.drawable.ShapeDrawable;

import android.graphics.drawable.shapes.PathShape;

import android.support.annotation.Nullable;

import android.util.AttributeSet;

import android.util.Log;

import android.util.TypedValue;

import android.view.View;

import java.util.Arrays;

import java.util.List;

public class HitRateLineGridView extends View {

? ? private List<Integer> hitRateData;? ? //命中率數(shù)據(jù),? 固定的4條數(shù)據(jù)。

? ? private String[] xLabels;? //x軸的標(biāo)簽

? ? private int maxIndex = 0;? //命中率最高的一項(xiàng)的索引,設(shè)置數(shù)據(jù)時(shí)就會(huì)計(jì)算

? ? private Bitmap bmLeftTip, bmCenterTip,bmRightTip;? ? ? //位于三個(gè)不同方位的提示圖片

? ? private Paint hollowCirclePaint,solidCirclePaint; //空心元和實(shí)心圓畫(huà)筆

? ? private Paint labelFontPaint,tipFontPaint;? //標(biāo)簽文字畫(huà)筆和提示文字畫(huà)筆

? ? private Paint realLinePaint,dashLinePaint;? //折線畫(huà)筆和背景灰線畫(huà)筆

? ? private Paint shaderBgPaint;? ? //陰影背景畫(huà)筆

? ? private int dataColor = Color.parseColor("#d92e48"); //數(shù)據(jù)顏色,紅色

? ? private int defaultPadding = this.dp2px(getContext(),20); //默認(rèn)邊距

? ? private int fontSize = this.sp2px(getContext(),8); //默認(rèn)字體顏色

? ? private Path shaderPath;? ? //漸變陰影的路徑,在繪制折線的時(shí)候記錄路徑

? ? /**

? ? * 設(shè)置命中率數(shù)據(jù),取最近的7天

? ? * 不需要這個(gè)方法,已標(biāo)記為過(guò)時(shí)

? ? */

? ? @Deprecated

? ? public void setHitRateData(List<Integer> hitRateData){

? ? ? ? this.hitRateData = hitRateData;

? ? ? ? if (hitRateData.size()<=7){

? ? ? ? ? ? //this.hitRateData = hitRateData;

? ? ? ? ? ? //++計(jì)算統(tǒng)計(jì)后再賦值給 hitRateData變量

? ? ? ? }

? ? ? ? else{

? ? ? ? ? ? //this.hitRateData = hitRateData.subList(hitRateData.size() - 7,hitRateData.size());

? ? ? ? ? ? //++計(jì)算統(tǒng)計(jì)后再賦值給 hitRateData變量

? ? ? ? }

? ? ? ? invalidate();

? ? }

? ? /**

? ? * 設(shè)置命中率數(shù)據(jù),已經(jīng)統(tǒng)計(jì)過(guò)的數(shù)據(jù),注意!只接收固定的4條數(shù)據(jù)

? ? *分別是近7天的命中率,近5天的命中率,近3天的命中率,和近2天的命中率

? ? */

? ? public void setHitRateDataCounted(List<Integer> hitRateData){

? ? ? ? this.hitRateData = hitRateData;

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

? ? ? ? ? ? if (hitRateData.get(maxIndex) < hitRateData.get(i)){

? ? ? ? ? ? ? ? maxIndex = i;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? invalidate();

? ? }

? ? /**

? ? * @param xLabels x軸底部的標(biāo)簽,最多取前4個(gè)

? ? */

? ? private void setXLabels(String[] xLabels){

? ? ? ? if (xLabels.length<=4){

? ? ? ? ? ? this.xLabels = xLabels;

? ? ? ? }

? ? ? ? else{

? ? ? ? ? ? this.xLabels = Arrays.copyOfRange(xLabels,0,4);

? ? ? ? }

? ? ? ? invalidate();

? ? }

? ? public HitRateLineGridView(Context context) {

? ? ? ? this(context,null);

? ? }

? ? public HitRateLineGridView(Context context, @Nullable AttributeSet attrs) {

? ? ? ? super(context, attrs);

? ? ? ? init();

? ? }

? ? private void init() {

? ? ? ? dashLinePaint = new Paint();

? ? ? ? dashLinePaint.setColor(Color.GRAY);

? ? ? ? dashLinePaint.setAlpha(100);

? ? ? ? dashLinePaint.setStrokeWidth(1.5f);

? ? ? ? labelFontPaint = new Paint();

? ? ? ? labelFontPaint.setColor(Color.GRAY);

? ? ? ? labelFontPaint.setTextSize(fontSize);

? ? ? ? setXLabels(new String[]{"近7","近5","近3","近2"} );

? ? ? ? realLinePaint = new Paint();

? ? ? ? realLinePaint.setColor(dataColor);

? ? ? ? realLinePaint.setStrokeWidth(4f);

? ? ? ? realLinePaint.setAntiAlias(true);

? ? ? ? solidCirclePaint = new Paint(realLinePaint);

? ? ? ? solidCirclePaint.setStrokeWidth(1.5f);

? ? ? ? //solidCirclePaint.setStyle(Paint.Style.FILL);? ? //設(shè)置實(shí)心

? ? ? ? hollowCirclePaint = new Paint(realLinePaint);

? ? ? ? hollowCirclePaint.setColor(Color.WHITE);? ? //采取在一個(gè)大實(shí)心圓里畫(huà)一個(gè)小白圓來(lái)實(shí)現(xiàn)空心圓效果的策略

? ? ? ? hollowCirclePaint.setStrokeWidth(1.8f);

? ? ? ? //hollowCirclePaint.setStyle(Paint.Style.STROKE); //設(shè)置空心

? ? ? ? tipFontPaint = new Paint();

? ? ? ? tipFontPaint.setTextSize(sp2px(getContext(),10));

? ? ? ? tipFontPaint.setColor(Color.WHITE);

? ? ? ? bmLeftTip = getTipBitmap(R.drawable.bubble_red_left,defaultPadding * 3,defaultPadding);

? ? ? ? bmCenterTip = getTipBitmap(R.drawable.bubble_red_mid,defaultPadding * 3,defaultPadding);

? ? ? ? bmRightTip = getTipBitmap(R.drawable.bubble_red_right,defaultPadding * 3,defaultPadding);

? ? ? ? shaderPath = new Path();

? ? ? ? shaderBgPaint = new Paint();

? ? ? ? shaderBgPaint.setAntiAlias(true);

? ? ? ? shaderBgPaint.setStyle(Paint.Style.FILL);

? ? }

? ? @Override

? ? protected void onDraw(Canvas canvas) {

? ? ? ? super.onDraw(canvas);

? ? ? ? drawBackground(canvas);

? ? ? ? drawXLabels(canvas);

? ? ? ? drawData(canvas);

? ? }

? ? //繪制漸變陰影

? ? private void drawShader(Canvas canvas) {

? ? ? ? int width = canvas.getWidth();

? ? ? ? int height = canvas.getHeight();

? ? ? ? LinearGradient lg = new LinearGradient(width/2,height,width/2,0,

? ? ? ? ? ? Color.parseColor("#00d92e48"),

? ? ? ? ? ? Color.parseColor("#99d92e48"),

? ? ? ? ? ? Shader.TileMode.CLAMP);// CLAMP重復(fù)最后一個(gè)顏色至最后

? ? ? ? shaderBgPaint.setShader(lg);

? ? ? ? canvas.drawPath(shaderPath,shaderBgPaint);

? ? }

? ? //繪制數(shù)據(jù)

? ? private void drawData(Canvas canvas) {

? ? ? ? int width = canvas.getWidth();

? ? ? ? int height = canvas.getHeight();

? ? ? ? int gridHeight = height - defaultPadding*2;

? ? ? ? if (hitRateData == null){

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? float w_space = (width-defaultPadding*2)/3;

? ? ? ? //畫(huà)折線

? ? ? ? for (int i = 0; i < 3; i++) {

? ? ? ? ? ? float startX = defaultPadding+i*w_space;

? ? ? ? ? ? float startY = (100-hitRateData.get(i)) *gridHeight/100 + defaultPadding;

? ? ? ? ? ? float stopX = defaultPadding+(i+1)*w_space;

? ? ? ? ? ? float stopY = (100-hitRateData.get(i+1))*gridHeight/100 + defaultPadding;

? ? ? ? ? ? canvas.drawLine(startX,startY,stopX,stopY,realLinePaint);

? ? ? ? ? ? //陰影

? ? ? ? ? ? if (i == 0){

? ? ? ? ? ? ? ? shaderPath.moveTo(startX,startY);

? ? ? ? ? ? }

? ? ? ? ? ? else if(i == 1){

? ? ? ? ? ? ? ? shaderPath.lineTo(startX,startY);

? ? ? ? ? ? }

? ? ? ? ? ? else if (i == 2){

? ? ? ? ? ? ? ? shaderPath.lineTo(startX,startY);

? ? ? ? ? ? ? ? shaderPath.lineTo(stopX,stopY);

? ? ? ? ? ? ? ? shaderPath.lineTo(stopX,height-defaultPadding);

? ? ? ? ? ? ? ? shaderPath.lineTo(defaultPadding,height-defaultPadding);

? ? ? ? ? ? ? ? shaderPath.close();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? //畫(huà)陰影

? ? ? ? drawShader(canvas);

? ? ? ? //畫(huà)圓點(diǎn)

? ? ? ? for (int i = 0; i < 4; i++) {

? ? ? ? ? ? if (i == maxIndex){? ? //最大項(xiàng)單獨(dú)處理

? ? ? ? ? ? ? ? //畫(huà)空心圓

? ? ? ? ? ? ? ? canvas.drawCircle(defaultPadding+i*w_space,(100-hitRateData.get(i))*gridHeight/100 + defaultPadding,dp2px(getContext(),5),solidCirclePaint);

? ? ? ? ? ? ? ? canvas.drawCircle(defaultPadding+i*w_space,(100-hitRateData.get(i))*gridHeight/100 + defaultPadding,dp2px(getContext(),3),hollowCirclePaint);

? ? ? ? ? ? ? ? //畫(huà)提示圖

? ? ? ? ? ? ? ? int tipTopValue = (100-hitRateData.get(i))*gridHeight/100 - dp2px(getContext(),6);? //提示圖y軸方向的位置

? ? ? ? ? ? ? ? if (maxIndex == 0){

? ? ? ? ? ? ? ? ? ? float tipLeftValue = i*w_space + dp2px(getContext(),1);

? ? ? ? ? ? ? ? ? ? canvas.drawBitmap(bmLeftTip,tipLeftValue , tipTopValue, tipFontPaint);

? ? ? ? ? ? ? ? ? ? canvas.drawText("命中率"+hitRateData.get(i)+"%", tipLeftValue + dp2px(getContext(),3), tipTopValue + dp2px(getContext(),12), tipFontPaint);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if (maxIndex == 1){

? ? ? ? ? ? ? ? ? ? float tipLeftValue = i*w_space - defaultPadding/2;

? ? ? ? ? ? ? ? ? ? canvas.drawBitmap(bmCenterTip, tipLeftValue, tipTopValue, tipFontPaint);

? ? ? ? ? ? ? ? ? ? canvas.drawText("命中率"+hitRateData.get(i)+"%", tipLeftValue + dp2px(getContext(),3), tipTopValue? + dp2px(getContext(),12), tipFontPaint);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if(maxIndex == 2){

? ? ? ? ? ? ? ? ? ? float tipLeftValue = i*w_space - defaultPadding/2;

? ? ? ? ? ? ? ? ? ? canvas.drawBitmap(bmCenterTip, tipLeftValue, tipTopValue, tipFontPaint);

? ? ? ? ? ? ? ? ? ? canvas.drawText("命中率"+hitRateData.get(i)+"%", tipLeftValue + dp2px(getContext(),3), tipTopValue? + dp2px(getContext(),12), tipFontPaint);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if (maxIndex == 3){

? ? ? ? ? ? ? ? ? ? float tipLeftValue = i*w_space - defaultPadding - dp2px(getContext(),1);

? ? ? ? ? ? ? ? ? ? canvas.drawBitmap(bmRightTip, tipLeftValue, tipTopValue, tipFontPaint);

? ? ? ? ? ? ? ? ? ? canvas.drawText("命中率"+hitRateData.get(i)+"%", tipLeftValue + dp2px(getContext(),3), tipTopValue? + dp2px(getContext(),12), tipFontPaint);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? } else{

? ? ? ? ? ? ? ? canvas.drawCircle(defaultPadding+i*w_space,(100-hitRateData.get(i))*gridHeight/100 + defaultPadding,dp2px(getContext(),3),solidCirclePaint);

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? //繪制x軸下方的標(biāo)簽

? ? private void drawXLabels(Canvas canvas) {

? ? ? ? int width = canvas.getWidth();

? ? ? ? int height = canvas.getHeight();

? ? ? ? if (xLabels == null){

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? int space = (width-defaultPadding - defaultPadding) / 3;

? ? ? ? Path path = new Path();

? ? ? ? for (int i = 0; i < xLabels.length; i++) {

? ? ? ? ? ? // path.reset();? ? //用路徑也沒(méi)法實(shí)現(xiàn)垂直繪制文字,得拆分了畫(huà)

? ? ? ? ? ? // path.moveTo(i*space + defaultPadding,height - defaultPadding + 3);

? ? ? ? ? ? //path.lineTo(i*space + defaultPadding,height - 3);

? ? ? ? ? ? // canvas.drawTextOnPath(xLabels[i],path,0f,0f,labelFontPaint);

? ? ? ? ? ? canvas.drawText(xLabels[i],i*space + defaultPadding/2 + 3,height- defaultPadding/2 + 3,labelFontPaint);

? ? ? ? }

? ? }

? ? //繪制背景4*3表格,

? ? private void drawBackground(Canvas canvas) {

? ? ? ? int width = canvas.getWidth();

? ? ? ? int height = canvas.getHeight();

? ? ? ? //畫(huà)5橫

? ? ? ? canvas.drawLine(defaultPadding,defaultPadding,width-defaultPadding,defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine(defaultPadding,(height - defaultPadding - defaultPadding)/4 + defaultPadding ,width-defaultPadding,(height - defaultPadding - defaultPadding)/4 + defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine(defaultPadding,height/2 ,width-defaultPadding, height/2,dashLinePaint);

? ? ? ? canvas.drawLine(defaultPadding,(height - defaultPadding - defaultPadding)*3/4 + defaultPadding ,width-defaultPadding,(height - defaultPadding - defaultPadding)*3/4 + defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine(defaultPadding,height-defaultPadding,width-defaultPadding,height-defaultPadding,dashLinePaint);

? ? ? ? //畫(huà)4豎

? ? ? ? canvas.drawLine(defaultPadding,defaultPadding,defaultPadding,height - defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine((width - defaultPadding - defaultPadding) / 3 + defaultPadding,defaultPadding,(width - defaultPadding - defaultPadding) / 3 + defaultPadding,height - defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine((width - defaultPadding - defaultPadding) *2/ 3 + defaultPadding,defaultPadding,(width - defaultPadding - defaultPadding)*2 / 3 + defaultPadding,height - defaultPadding,dashLinePaint);

? ? ? ? canvas.drawLine(width-defaultPadding,defaultPadding,width-defaultPadding,height - defaultPadding,dashLinePaint);

? ? }

? ? /**

? ? * @param sourceId? 圖片的資源id

? ? * @param width? 指定寬度

? ? * @param height? 指定高度

? ? * @return? 適應(yīng)控件大小的圖片

? ? */

? ? private Bitmap getTipBitmap(int sourceId,int width,int height){

? ? ? ? Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),sourceId);

? ? ? ? if (bitmap.getWidth() == width && bitmap.getHeight() == height){? ? //寫(xiě)這個(gè)判斷,避createScaledBitmap()的坑

? ? ? ? ? ? return bitmap;

? ? ? ? }

? ? ? ? return Bitmap.createScaledBitmap(bitmap,width,height,true);

? ? }

? ? private int dp2px(Context context, int dip) {

? ? ? ? final float scale = context.getResources().getDisplayMetrics().density;

? ? ? ? return (int) (dip * scale + 0.5f);

? ? }

? ? private int sp2px(Context context, float spValue) {

? ? ? ? return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics());

? ? }

}

4、后話:

? ? ? ? 這也沒(méi)啥技術(shù)含量,就是官方的api用用,基本的計(jì)算公式擺擺,也不多廢話了。

反正用代碼畫(huà)圖挺好玩的,文章里可能會(huì)有些你一時(shí)沒(méi)想到的小技巧吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容