自定義View之顏色漸變折線圖
* 本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出
* 本文同步發表在簡書,轉載請註明出處。
首先看下要實現的效果圖。
折線圖的繪製主要有一下幾個步驟。
一、定義LineChartView類並繼承View。
二、新增自定義屬性。以在value目錄下建立attrs.xml檔案,檔案中我們可以定義一些用到的屬性,比如折線顏色、字型大小等屬性。檔案內容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LineChartView">
<attr name="axesColor" format="color"/> <!--座標軸顏色-->
<attr name="axesWidth" format="dimension"/><!--座標軸寬度-->
<attr name="textColor" format="color"/> <!--字型顏色-->
<attr name="textSize" format="dimension"/> <!--字型大小-->
<attr name="lineColor" format="color"/> <!--折線顏色-->
<attr name="bgColor" format="color"/> <!--背景色-->
</declare-styleable>
</resources>
接下來在LineChartView的構造方法中解析自定義屬性的值並做相應的處理。在構造方法裡還初始化了漸變顏色、折線資料的List集合以及初始化畫筆等操作程式碼如下:
public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LineChartView);
mAxesColor = typedArray.getColor(R.styleable.LineChartView_axesColor, Color.parseColor("#CCCCCC"));
mAxesWidth = typedArray.getDimension(R.styleable.LineChartView_axesWidth, 1);
mTextColor = typedArray.getColor(R.styleable.LineChartView_textColor, Color.parseColor("#ABABAB"));
mTextSize = typedArray.getDimension(R.styleable.LineChartView_textSize, 32);
mLineColor = typedArray.getColor(R.styleable.LineChartView_lineColor, Color.RED);
mBgColor = typedArray.getColor(R.styleable.LineChartView_bgColor, Color.WHITE);
typedArray.recycle();
// 初始化漸變色
shadeColors = new int[]{
Color.argb(100, 255, 86, 86), Color.argb(15, 255, 86, 86),
Color.argb(0, 255, 86, 86)};
// 初始化折線資料集合
mItems = new ArrayList<>();
mMargin10 = ScreenUtils.dp2px(context, 10);
init();
}
另外,折現資料需要實體類,實體類可直接新增到LineChartView內部。如下:
// 折線資料的實體類
public static class ItemBean {
private long Timestamp;
private int value;
public ItemBean(){}
public ItemBean(long timestamp, int value) {
super();
Timestamp = timestamp;
this.value = value;
}
public long getTimestamp() {
return Timestamp;
}
public void setTimestamp(long timestamp) {
Timestamp = timestamp;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
三、初始化畫筆和路徑。程式碼如下:
private void init() {
// 初始化座標軸畫筆
mPaintAxes = new Paint();
mPaintAxes.setColor(mAxesColor);
mPaintAxes.setStrokeWidth(mAxesWidth);
// 初始化文字畫筆
mPaintText = new Paint();
mPaintText.setStyle(Paint.Style.FILL);
mPaintText.setAntiAlias(true); //抗鋸齒
mPaintText.setTextSize(mTextSize);
mPaintText.setColor(mTextColor);
mPaintText.setTextAlign(Paint.Align.LEFT);
// 初始化折線畫筆
mPaintLine = new Paint();
mPaintLine.setStyle(Paint.Style.STROKE);
mPaintLine.setAntiAlias(true);
mPaintLine.setStrokeWidth(mAxesWidth / 2);
mPaintLine.setColor(mLineColor);
// 初始化折線路徑
mPath = new Path();
mPathShader = new Path();
// 陰影畫筆
mPaintShader = new Paint();
mPaintShader.setAntiAlias(true);
mPaintShader.setStrokeWidth(2f);
}
四、重寫onLayout方法。在onLayout方法中獲取控制元件的寬高、初始化原點座標以及設定控制元件的背景。程式碼如下:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
mWidth = getWidth();
mHeight = getHeight();
timeWidth = (int) mPaintText.measureText(startTime);
// 初始化原點座標
xOrigin = 0 + mMargin10;
yOrigin = (mHeight - mTextSize - mMargin10);
// 設定背景色
setBackgroundColor(mBgColor);
}
}
五、重寫onDraw方法。在onDraw方法中完成折線圖的繪製。程式碼如下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Y軸座標間距
yInterval = (max - min) / (yOrigin - mMargin10);
// X軸座標間距
xInterval = (mWidth - xOrigin) / (mItems.size() - 1);
// 畫座標軸
drawAxes(canvas);
// 畫文字
drawText(canvas);
// 畫折線
drawLine(canvas);
// 設定動畫
setAnim(canvas)
}
折線圖的繪製可以分三部分:1.繪製座標軸。2.繪製View上的文字。3.繪製折線。
1.座標軸繪製的是第一象限,即左下角的點為原點。繪製座標軸程式碼如下:
// 畫座標軸
private void drawAxes(Canvas canvas) {
// 繪製X軸
canvas.drawLine(xOrigin, yOrigin, mWidth - mMargin10, yOrigin, mPaintAxes);
// 繪製X中軸線
canvas.drawLine(xOrigin, yOrigin / 2, mWidth - mMargin10, yOrigin / 2, mPaintAxes);
// 繪製X上邊線
canvas.drawLine(xOrigin, mMargin10, mWidth - mMargin10, mMargin10, mPaintAxes);
// 繪製畫Y軸
canvas.drawLine(xOrigin, yOrigin, xOrigin, mMargin10, mPaintAxes);
// 繪製Y右邊線
canvas.drawLine(mWidth - mMargin10, mMargin10, mWidth - mMargin10, yOrigin, mPaintAxes);
}
2.繪製文字,程式碼如下:
private void drawText(Canvas canvas) {
// 繪製最大值
canvas.drawText(String.format("%.2f", max * 100 / 100.0) + "%", xOrigin + 6, 2 * mMargin10, mPaintText);
// 繪製最小值
canvas.drawText(String.format("%.2f", min * 100 / 100.0) + "%", xOrigin + 6, yOrigin - 6, mPaintText);
// 繪製中間值
canvas.drawText((String.format("%.2f", (min + max) * 100 / 200.0) + "%"), xOrigin + 6, (yOrigin + mMargin10) / 2, mPaintText);
// 繪製開始日期
canvas.drawText(startTime, xOrigin, mHeight - mMargin10, mPaintText);
// 繪製結束日期
canvas.drawText(endTime, mWidth - timeWidth - mMargin10, mHeight - mMargin10, mPaintText);
}
3.繪製折線及漸變填充
private void drawLine(Canvas canvas) {
// 畫座標點
for (int i = 0; i < mItems.size(); i++) {
float x = i * xInterval + xOrigin + mAxesWidth;
if (i == 0) {
mPathShader.moveTo(x, yOrigin - (mItems.get(i).getValue() - min) / yInterval);
mPath.moveTo(x, yOrigin - (mItems.get(i).getValue() - min) / yInterval);
} else {
mPath.lineTo(x - mMargin10 - mAxesWidth, yOrigin - (mItems.get(i).getValue() - min) / yInterval);
mPathShader.lineTo(x - mMargin10 - mAxesWidth, yOrigin - (mItems.get(i).getValue() - min) / yInterval);
if (i == mItems.size() - 1) {
mPathShader.lineTo(x - mMargin10 - mAxesWidth, yOrigin);
mPathShader.lineTo(xOrigin, yOrigin);
mPathShader.close();
}
}
}
// 漸變陰影
Shader mShader = new LinearGradient(0, 0, 0, getHeight(), shadeColors, null, Shader.TileMode.CLAMP);
mPaintShader.setShader(mShader);
// 繪製漸變陰影
canvas.drawPath(mPathShader, mPaintShader);
}
六、折線圖新增動畫。
1.首先需要計算動畫的進度,因此在LineChartView中定義成員變數mProgress,並新增以下方法:
/**
* Animate this property. It is the percentage of the path that is drawn.
* It must be [0,1].
*
* @param percentage float the percentage of the path.
*/
public void setPercentage(float percentage) {
if (percentage < 0.0f || percentage > 1.0f) {
throw new IllegalArgumentException(
"setPercentage not between 0.0f and 1.0f");
}
mProgress = percentage;
invalidate();
}
2.接下來設定動畫效果,程式碼如下:
private void setAnim(Canvas canvas) {
PathMeasure measure = new PathMeasure(mPath, false);
float pathLength = measure.getLength();
PathEffect effect = new DashPathEffect(new float[]{pathLength,
pathLength}, pathLength - pathLength * mProgress);
mPaintLine.setPathEffect(effect);
canvas.drawPath(mPath, mPaintLine);
}
3.新增開啟動畫的方法:
/**
* @param lineChartView
* @param duration 動畫持續時間
*/
public void startAnim(LineChartView lineChartView, long duration) {
ObjectAnimator anim = ObjectAnimator.ofFloat(lineChartView, "percentage", 0.0f, 1.0f);
anim.setDuration(duration);
anim.setInterpolator(new LinearInterpolator());
anim.start();
}
至此,折線圖的繪製已經全部完成。最後還可以新增get() set()方法,暴露出屬性介面,以供外部呼叫。程式碼就不再貼出來了。
七、使用LineChartView
1.在佈局檔案中新增LineChartView,可設定折線顏色、字型顏色、等屬性,如下:
<com.example.zhpan.linechartview.LineChartView
android:id="@+id/lcv"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginBottom="20dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
app:lineColor="#FF0000"
app:textColor="#ABABAB"
app:textSize="12dp"/>
2.在Activity中為LineChartView設定資料,也可以通過程式碼為其設定屬性。
private void initData() {
// 初始化折線資料
mItems = new ArrayList<>();
mItems.add(new LineChartView.ItemBean(1489507200, 23));
mItems.add(new LineChartView.ItemBean(1489593600, 88));
mItems.add(new LineChartView.ItemBean(1489680000, 60));
mItems.add(new LineChartView.ItemBean(1489766400, 50));
mItems.add(new LineChartView.ItemBean(1489852800, 70));
mItems.add(new LineChartView.ItemBean(1489939200, 10));
mItems.add(new LineChartView.ItemBean(1490025600, 33));
mItems.add(new LineChartView.ItemBean(1490112000, 44));
mItems.add(new LineChartView.ItemBean(1490198400, 99));
mItems.add(new LineChartView.ItemBean(1490284800, 17));
shadeColors= new int[]{
Color.argb(100, 255, 86, 86), Color.argb(15, 255, 86, 86),
Color.argb(0, 255, 86, 86)};
// 設定折線資料
mLineChartView.setItems(mItems);
// 設定漸變顏色
mLineChartView.setShadeColors(shadeColors);
// 開啟動畫
mLineChartView.startAnim(mLineChartView,2000);
}
相關文章
- 利用CAGradientLayer自定義顏色漸變viewView
- python seaborn畫熱力圖,自定義顏色漸變Python
- ECHARTS-折線圖不顯示資料 控制折線圖顏色Echarts
- iOS兩種顏色的線性漸變 --DDGBannerScrollViewiOSView
- 自定義控制元件之kotlin繪製折線圖和曲線圖控制元件Kotlin
- CSS 實現字型顏色漸變CSS
- css3背景顏色漸變CSSS3
- echarts自定義膠囊柱圖並設定每個柱子的漸變色Echarts
- js計算線性漸變的中間顏色值JS
- Android 顏色漸變 屬性動畫Android動畫
- echarts折線漸變 + 預測值Echarts
- 自定義View之SwitchViewView
- Python自定義詞雲圖形狀和文字顏色Python
- 【HarmonyOS NEXT】一波三折之解決Rect元件設定顏色漸變顯示異常元件
- Flutter自定義折線圖並新增點選事件Flutter事件
- Flutter 115: 圖解自定義 View 之 Canvas (四Flutter圖解ViewCanvas
- 【Android自定義View】繪圖之文字篇(三)AndroidView繪圖
- 【Android自定義View】繪圖之Path篇(二)AndroidView繪圖
- flutter 自定義view 繪製曲線統計圖FlutterView
- Android 自定義 View 之 LeavesLoadingAndroidView
- 在LCD螢幕上漸變顯示sRGB所有範圍顏色, 最大可漸變16,581,375種顏色
- Android自定義View之Paint繪製文字和線AndroidViewAI
- css文字顏色漸變的3種實現CSS
- CSS3文字顏色漸變效果CSSS3
- 直播小程式原始碼,Swift 獲取漸變色顏色值原始碼Swift
- Echarts 中國地圖各個省市自治區自定義顏色Echarts地圖
- 改變SVG圖的顏色SVG
- 圖示任意改變顏色
- 自定義View 之 RecyclerView.ItemDecorationView
- Android自定義View之捲尺AndroidView
- 簡易的iOS導航欄顏色漸變方案iOS
- 自定義VIEWView
- Android 自定義 View 實戰之 PuzzleViewAndroidView
- Android 自定義 View 之入門篇AndroidView
- Android自定義view之emoji鍵盤AndroidView
- Android自定義View之Canvas的使用AndroidViewCanvas
- app直播原始碼,xml實現由上而下的顏色漸變APP原始碼XML
- [譯] Android 實現顏色漸變的一個小 tipAndroid
- Android 沉浸式狀態列 漸變顏色的實現Android