#使用MPAndroidChart實現(xiàn)水平柱狀圖(圓角)
## 在使用MPAndroidChart組件前,我們必須閱讀官方API,看官方給出的Simple使用實例。如果你想實現(xiàn)的圖表與官方給出的實例有出入需要修改Chart設(shè)定,那需要仔細(xì)閱讀使用教程。由于圖表的構(gòu)成是多模塊的,每個模塊涉及屬性較多,建議花點時間閱讀教程。
## 在我項目中運(yùn)用MPAndroidChart的地方比較多,大多數(shù)官方使用實例是可以滿足使用要求的,那在本篇文章里我只對實現(xiàn)水平柱狀圖作介紹,其他的不作概述。
##### 首先了解一下需求,如下圖所示需要實現(xiàn)圓角柱狀圖。

##### 根據(jù)官方提供的HorizontalBarChart實現(xiàn)效果如下:

##### 這里我簡單貼一下Activity中實現(xiàn)代碼:
```
import android.app.Activity;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.MPPointF;
import java.util.ArrayList;
import java.util.Random;
public class OrderCountActivity extends Activity implements OnChartValueSelectedListener {
? ? // 自定義Chatrt圖標(biāo)
? ? private HorizontalBarChart chart;
? ? // 測試數(shù)據(jù)
? ? private String labelName[] = {"","南京", "常州", "揚(yáng)州", "無錫", "南通", "淮安", "蘇州", "連云港", "鹽城", "泰州", "宿遷", "鎮(zhèn)江", "徐州"};
? ? @Override
? ? protected void onCreate(@Nullable Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_order_count);
? ? ? ? initViews();
? ? }
? ? public void initViews() {
? ? ? ? chart = findViewById(R.id.custom_chart);
? ? ? ? chart.setOnChartValueSelectedListener(this);
? ? ? ? chart.setDrawBarShadow(true);
? ? ? ? chart.setDrawValueAboveBar(true);
? ? ? ? chart.setExtraOffsets(0, 10, 0, 10); // 設(shè)置餅圖的偏移量,類似于內(nèi)邊距 ,設(shè)置視圖窗口大小
? ? ? ? chart.setDoubleTapToZoomEnabled(false); // 雙擊不可放大
? ? ? ? chart.getDescription().setEnabled(false); // 不顯示描述
? ? ? ? chart.setMaxVisibleValueCount(60); // 最大值
? ? ? ? chart.setPinchZoom(false); // x,y軸方向縮放
? ? ? ? chart.setDrawGridBackground(false);? //網(wǎng)格背景
? ? ? ? chart.animateY(2500); // Y軸 初始化時動畫效果
? ? ? ? // 設(shè)置x軸
? ? ? ? final XAxis xl = chart.getXAxis();
? ? ? ? xl.setPosition(XAxis.XAxisPosition.BOTTOM); // 設(shè)置x軸顯示在下方,默認(rèn)在上方
? ? ? ? xl.setDrawAxisLine(true); //設(shè)置為true,則繪制該行旁邊的軸線(axis-line)
? ? ? ? xl.setDrawGridLines(true);// 將此設(shè)置為true,繪制該軸的網(wǎng)格線
? ? ? ? xl.setAxisMinimum(0.0f); // 設(shè)置最小值? 不要隨便改
? ? ? ? xl.setLabelCount(labelName.length);
? ? ? ? xl.setTextSize(14.0f); // 設(shè)置文字大小
? ? ? ? // 設(shè)置x軸顯示的值的格式
? ? ? ? xl.setValueFormatter(new IAxisValueFormatter() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public String getFormattedValue(float value, AxisBase axis) {
? ? ? ? ? ? ? ? if (value - xl.getAxisMinimum()< labelName.length) {
? ? ? ? ? ? ? ? ? ? return labelName[(int) (value - xl.getAxisMinimum())];
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? return "";
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? xl.setXOffset(0.0f); // 設(shè)置標(biāo)簽對x軸的偏移量,垂直方向
? ? ? ? // 設(shè)置y軸,y軸有兩條,分別為左和右
? ? ? ? YAxis yr = chart.getAxisRight();
? ? ? ? chart.getAxisLeft().setEnabled(false); // 隱藏右邊 的坐標(biāo)軸
? ? ? ? yr.setDrawAxisLine(false);
? ? ? ? yr.setDrawGridLines(false);
? ? ? ? yr.setTextSize(14.0f);
? ? ? ? // y軸添加限制線
? ? ? ? LimitLine limitLine = new LimitLine(2.0f, "平均值:2.0");
? ? ? ? limitLine.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_TOP);
? ? ? ? limitLine.setTextSize(12f);
? ? ? ? limitLine.setLineColor(getResources().getColor(R.color.colo_FFA224)); // 線的顏色
? ? ? ? limitLine.setTextColor(getResources().getColor(R.color.colo_FFA224)); // 文字的顏色
? ? ? ? yr.addLimitLine(limitLine);
? ? ? ? yr.setDrawZeroLine(true);
? ? ? ? yr.setYOffset(0.0f);
? ? ? ? Legend legend = chart.getLegend();
? ? ? ? legend.setEnabled(false);// 隱藏圖例
? ? ? ? setData(); // 填充數(shù)據(jù)
? ? }
? ? private void setData() {
? ? ? ? float barWidth = 0.5f;
? ? ? ? ArrayList<BarEntry> values_zs = new ArrayList<>();? // 總數(shù)
? ? ? ? ArrayList<BarEntry> values_ywc = new ArrayList<>(); // 已完成
? ? ? ? Random random = new Random();
? ? ? ? for (int i = 0; i < labelName.length; i++) {
? ? ? ? ? ? if(i==0){
? ? ? ? ? ? ? ? values_zs.add(new BarEntry(-1 , 0 ));
? ? ? ? ? ? ? ? values_ywc.add(new BarEntry(-1, 0));
? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? }
? ? ? ? ? ? int val = random.nextInt(20);
? ? ? ? ? ? float val2 = (float) Math.random()*10;
? ? ? ? ? ? values_zs.add(new BarEntry(i , 2*val2));
? ? ? ? ? ? values_ywc.add(new BarEntry(i, val2));
? ? ? ? }
? ? ? ? if (chart.getData() != null &&
? ? ? ? ? ? ? ? chart.getData().getDataSetCount() > 0) {
? ? ? ? ? ? BarDataSet dataSetZs = (BarDataSet) chart.getData().getDataSetByIndex(0); // 總數(shù)
? ? ? ? ? ? BarDataSet dataSetYwc = (BarDataSet) chart.getData().getDataSetByIndex(1); // 已完成數(shù)
? ? ? ? ? ? dataSetZs.setValues(values_zs);
? ? ? ? ? ? dataSetYwc.setValues(values_ywc);
? ? ? ? ? ? chart.getData().notifyDataChanged();
? ? ? ? ? ? chart.notifyDataSetChanged();
? ? ? ? } else {
? ? ? ? ? ? ArrayList<IBarDataSet> dataSets = new ArrayList<>();
? ? ? ? ? ? BarDataSet dataSetZs = new BarDataSet(values_zs, "總數(shù)");
? ? ? ? ? ? dataSetZs.setDrawIcons(false);
? ? ? ? ? ? dataSetZs.setDrawValues(false); // 不顯示值
? ? ? ? ? ? dataSetZs.setColor(getResources().getColor(R.color.colo_EFE8E1)); // 淺灰色
? ? ? ? ? ? dataSets.add(dataSetZs);
? ? ? ? ? ? BarDataSet dataSetYwc = new BarDataSet(values_ywc, "已完成");
? ? ? ? ? ? dataSetYwc.setDrawIcons(false);
? ? ? ? ? ? dataSetYwc.setColor(getResources().getColor(R.color.colo_B79C81)); // 淺褐色
? ? ? ? ? ? dataSets.add(dataSetYwc);
? ? ? ? ? ? BarData data = new BarData(dataSets);
? ? ? ? ? ? data.setValueTextSize(10f);
? ? ? ? ? ? data.setBarWidth(barWidth);
? ? ? ? ? ? chart.setData(data);
? ? ? ? }
? ? ? ? findViewById(R.id.tv_ywcs).setVisibility(View.VISIBLE);
? ? ? ? findViewById(R.id.tv_zs).setVisibility(View.VISIBLE);
? ? }
? ? private final RectF mOnValueSelectedRectF = new RectF();
? ? @Override
? ? public void onValueSelected(Entry e, Highlight h) {
? ? ? ? if (e == null)
? ? ? ? ? ? return;
? ? ? ? RectF bounds = mOnValueSelectedRectF;
? ? ? ? chart.getBarBounds((BarEntry) e, bounds);
? ? ? ? MPPointF position = chart.getPosition(e, chart.getData().getDataSetByIndex(h.getDataSetIndex())
? ? ? ? ? ? ? ? .getAxisDependency());
? ? ? ? Log.i("bounds", bounds.toString());
? ? ? ? Log.i("position", position.toString());
? ? ? ? MPPointF.recycleInstance(position);
? ? }
? ? @Override
? ? public void onNothingSelected() {
? ? }
}
```
#####布局文件 activity_order_count.xml:
```
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
? ? xmlns:tools="http://schemas.android.com/tools"
? ? android:layout_width="match_parent"
? ? android:layout_height="match_parent"
? ? android:background="@color/colo_F0F0F0"
? ? android:orientation="vertical">
? ? ? ? <!--? 已完成任務(wù)數(shù)對比-->
? ? ? ? <TextView
? ? ? ? ? ? android:id="@+id/title_bottom"
? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? android:layout_below="@+id/ll_middle"
? ? ? ? ? ? android:layout_margin="15dp"
? ? ? ? ? ? android:layout_weight="1"
? ? ? ? ? ? android:text="已完成任務(wù)數(shù)對比"
? ? ? ? ? ? android:textColor="@color/black"
? ? ? ? ? ? android:textSize="16sp"
? ? ? ? ? ? android:textStyle="bold" />
? ? ? ? <RelativeLayout
? ? ? ? ? ? android:layout_width="match_parent"
? ? ? ? ? ? android:layout_height="match_parent"
? ? ? ? ? ? android:layout_below="@+id/title_bottom">
? ? ? ? ? ? <TextView
? ? ? ? ? ? ? ? android:id="@+id/tv_ywcs"
? ? ? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? ? ? android:gravity="center_vertical"
? ? ? ? ? ? ? ? android:layout_alignParentTop="true"
? ? ? ? ? ? ? ? android:layout_alignParentRight="true"
? ? ? ? ? ? ? ? android:text="已完成"
? ? ? ? ? ? ? ? android:drawableLeft="@drawable/ic_brown_point"/>
? ? ? ? ? ? <TextView
? ? ? ? ? ? ? ? android:id="@+id/tv_zs"
? ? ? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? ? ? android:gravity="center_vertical"
? ? ? ? ? ? ? ? android:layout_alignParentTop="true"
? ? ? ? ? ? ? ? android:layout_toLeftOf="@+id/tv_ywcs"
? ? ? ? ? ? ? ? android:text="總數(shù)"
? ? ? ? ? ? ? ? android:layout_marginRight="10dp"
? ? ? ? ? ? ? ? android:drawableLeft="@drawable/ic_brown_low_point"/>
? ? ? ? ? ? <!-- 這是官方的HorizontalBarChart,后面使用自定義chart請?zhí)鎿Q成CustomHorizontalBarChart?-->
? ? ? ? ? ? <com.github.mikephil.charting.charts.HorizontalBarChart
? ? ? ? ? ? ? ? android:id="@+id/custom_chart"
? ? ? ? ? ? ? ? android:layout_width="match_parent"
? ? ? ? ? ? ? ? android:layout_height="match_parent"
? ? ? ? ? ? ? ? android:background="@android:color/white"
? ? ? ? ? ? ? ? android:layout_below="@+id/tv_ywcs"/>
? ? ? ? </RelativeLayout>
</LinearLayout>
```
#####距離實現(xiàn)圓角柱狀圖只差一步,自定義水平圓角柱狀圖,下面直接給出代碼吧
```
/**
*? 重寫HorizontalBarChart,更改其柱狀圖樣式
*/
public class CustomHorizontalBarChart extends HorizontalBarChart {
public CustomHorizontalBarChart(Context context) {
super(context);
? ? }
public CustomHorizontalBarChart(Context context, AttributeSet attrs) {
super(context, attrs);
? ? }
public CustomHorizontalBarChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
? ? }
@Override
? ? protected void init() {
super.init();
? ? ? ? this.mRenderer =new CustomHorizontalBarChartRenderer(this, this.mAnimator, this.mViewPortHandler);
? ? }
}
```
######最重要的步驟來了,重寫器渲染器,覆蓋HorizontalBarChartRenderer.java中繪制柱狀圖的方法。其中drawDataSet是繪制柱狀圖的方法,drawHighlighted是繪制點擊過后高亮柱狀圖。
```
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.highlight.Range;
import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.Log;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.buffer.BarBuffer;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.utils.Transformer;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.utils.ViewPortHandler;
/**
* 繼承HorizontalBarChartRenderer寫一個新的渲染器,調(diào)整為水平顏色
*/
public class CustomHorizontalBarChartRenderer extends HorizontalBarChartRenderer {
public CustomHorizontalBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
super(chart, animator, viewPortHandler);
? ? }
private RectFmBarShadowRectBuffer =new RectF();
? ? @Override
? ? protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {
Transformer trans =mChart.getTransformer(dataSet.getAxisDependency());
? ? ? ? mBarBorderPaint.setColor(dataSet.getBarBorderColor());
? ? ? ? mBarBorderPaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getBarBorderWidth()));
? ? ? ? final boolean drawBorder = dataSet.getBarBorderWidth() >0.f;
? ? ? ? float phaseX =mAnimator.getPhaseX();
? ? ? ? float phaseY =mAnimator.getPhaseY();
? ? ? ? // draw the bar shadow before the values
? ? ? ? if (mChart.isDrawBarShadowEnabled()) {
mShadowPaint.setColor(dataSet.getBarShadowColor());
? ? ? ? ? ? BarData barData =mChart.getBarData();
? ? ? ? ? ? final float barWidth = barData.getBarWidth();
? ? ? ? ? ? final float barWidthHalf = barWidth /2.0f;
? ? ? ? ? ? float x;
? ? ? ? ? ? for (int i =0, count = Math.min((int) (Math.ceil((float) (dataSet.getEntryCount()) * phaseX)), dataSet.getEntryCount());
? ? ? ? ? ? ? ? i < count;
? ? ? ? ? ? ? ? i++) {
BarEntry e = dataSet.getEntryForIndex(i);
? ? ? ? ? ? ? ? x = e.getX();
? ? ? ? ? ? ? ? mBarShadowRectBuffer.top = x - barWidthHalf;
? ? ? ? ? ? ? ? mBarShadowRectBuffer.bottom = x + barWidthHalf;
? ? ? ? ? ? ? ? trans.rectValueToPixel(mBarShadowRectBuffer);
? ? ? ? ? ? ? ? if (!mViewPortHandler.isInBoundsTop(mBarShadowRectBuffer.bottom))
continue;
? ? ? ? ? ? ? ? if (!mViewPortHandler.isInBoundsBottom(mBarShadowRectBuffer.top))
break;
? ? ? ? ? ? ? ? mBarShadowRectBuffer.left =mViewPortHandler.contentLeft();
? ? ? ? ? ? ? ? mBarShadowRectBuffer.right =mViewPortHandler.contentRight();
? ? ? ? ? ? ? ? float radius = (mBarShadowRectBuffer.bottom -mBarShadowRectBuffer.top) /2;
? ? ? ? ? ? ? ? // 畫半圓+矩形
? ? ? ? ? ? ? ? RectF rectFTo =new RectF(mBarShadowRectBuffer.right -2 * radius, mBarShadowRectBuffer.top,
? ? ? ? ? ? ? ? ? ? ? ? mBarShadowRectBuffer.right, mBarShadowRectBuffer.bottom);
? ? ? ? ? ? ? ? Path path =new Path();
? ? ? ? ? ? ? ? path.arcTo(rectFTo, -90, 180, true);
? ? ? ? ? ? ? ? if (mBarShadowRectBuffer.right -mBarShadowRectBuffer.left < radius) {
path.lineTo(rectFTo.centerX(), rectFTo.bottom);
? ? ? ? ? ? ? ? ? ? Path srcPath =new Path();
? ? ? ? ? ? ? ? ? ? srcPath.addRect(mBarShadowRectBuffer.left, mBarShadowRectBuffer.top, mBarShadowRectBuffer.right, mBarShadowRectBuffer.bottom, Path.Direction.CW);
? ? ? ? ? ? ? ? ? ? path.op(srcPath, Path.Op.INTERSECT); // 相交部分
? ? ? ? ? ? ? ? }else {
path.moveTo(rectFTo.centerX(), rectFTo.bottom);
? ? ? ? ? ? ? ? ? ? path.lineTo(mBarShadowRectBuffer.left, mBarShadowRectBuffer.bottom);
? ? ? ? ? ? ? ? ? ? path.lineTo(mBarShadowRectBuffer.left, mBarShadowRectBuffer.top);
? ? ? ? ? ? ? ? ? ? path.lineTo(rectFTo.centerX(), mBarShadowRectBuffer.top);
? ? ? ? ? ? ? ? }
c.drawPath(path, mShadowPaint);
? ? ? ? ? ? }
}
// initialize the buffer
? ? ? ? BarBuffer buffer =mBarBuffers[index];
? ? ? ? buffer.setPhases(phaseX, phaseY);
? ? ? ? buffer.setDataSet(index);
? ? ? ? buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
? ? ? ? buffer.setBarWidth(mChart.getBarData().getBarWidth());
? ? ? ? buffer.feed(dataSet);
? ? ? ? trans.pointValuesToPixel(buffer.buffer);
? ? ? ? final boolean isSingleColor = dataSet.getColors().size() ==1;
? ? ? ? if (isSingleColor) {
mRenderPaint.setColor(dataSet.getColor());
? ? ? ? }
for (int j =0; j < buffer.size(); j +=4) {
if (!mViewPortHandler.isInBoundsTop(buffer.buffer[j +3]))
break;
? ? ? ? ? ? if (!mViewPortHandler.isInBoundsBottom(buffer.buffer[j +1]))
continue;
? ? ? ? ? ? if (!isSingleColor) {
// Set the color for the currently drawn value. If the index
// is out of bounds, reuse colors.
? ? ? ? ? ? ? ? mRenderPaint.setColor(dataSet.getColor(j /4));
? ? ? ? ? ? }
// 畫半圓+矩形
? ? ? ? ? ? float barWidthHalf = (buffer.buffer[j +3] - buffer.buffer[j +1]) /2;
? ? ? ? ? ? RectF rectFTo =new RectF(buffer.buffer[j +2] -2 * barWidthHalf, buffer.buffer[j +1],
? ? ? ? ? ? ? ? ? ? buffer.buffer[j +2], buffer.buffer[j +3]);
? ? ? ? ? ? Path path =new Path();
? ? ? ? ? ? path.arcTo(rectFTo, -90, 180, true);
? ? ? ? ? ? if (buffer.buffer[j +2] - buffer.buffer[j] < barWidthHalf) {
path.lineTo(rectFTo.centerX(), rectFTo.bottom); // 封閉半圓
? ? ? ? ? ? ? ? Path srcPath =new Path();
? ? ? ? ? ? ? ? srcPath.addRect(buffer.buffer[j], buffer.buffer[j +1], buffer.buffer[j +2], buffer.buffer[j +3], Path.Direction.CW);
? ? ? ? ? ? ? ? path.op(srcPath, Path.Op.INTERSECT); // 相交部分
? ? ? ? ? ? }else {
path.moveTo(rectFTo.centerX(), rectFTo.bottom);
? ? ? ? ? ? ? ? path.lineTo(buffer.buffer[j], buffer.buffer[j +3]);
? ? ? ? ? ? ? ? path.lineTo(buffer.buffer[j], buffer.buffer[j +1]);
? ? ? ? ? ? ? ? path.lineTo(rectFTo.centerX(), buffer.buffer[j +1]);
? ? ? ? ? ? }
c.drawPath(path, mRenderPaint);
? ? ? ? ? ? if (drawBorder) {
c.drawPath(path, mBarBorderPaint);
? ? ? ? ? ? }
}
}
@Override
? ? public void drawHighlighted(Canvas c, Highlight[] indices) {
BarData barData =mChart.getBarData();
? ? ? ? final float barWidth = barData.getBarWidth();
? ? ? ? final float barWidthHalf = barWidth /2.0f;
? ? ? ? for (Highlight high : indices) {
IBarDataSet set = barData.getDataSetByIndex(high.getDataSetIndex());
? ? ? ? ? ? if (set ==null || !set.isHighlightEnabled())
continue;
? ? ? ? ? ? BarEntry e = set.getEntryForXValue(high.getX(), high.getY());
? ? ? ? ? ? if (!isInBoundsX(e, set))
continue;
? ? ? ? ? ? Transformer trans =mChart.getTransformer(set.getAxisDependency());
? ? ? ? ? ? mHighlightPaint.setColor(set.getHighLightColor());
? ? ? ? ? ? mHighlightPaint.setAlpha(set.getHighLightAlpha());
? ? ? ? ? ? boolean isStack = (high.getStackIndex() >=0 && e.isStacked()) ?true :false;
? ? ? ? ? ? final float y1;
? ? ? ? ? ? final float y2;
? ? ? ? ? ? if (isStack) {
if (mChart.isHighlightFullBarEnabled()) {
y1 = e.getPositiveSum();
? ? ? ? ? ? ? ? ? ? y2 = -e.getNegativeSum();
? ? ? ? ? ? ? ? }else {
Range range = e.getRanges()[high.getStackIndex()];
? ? ? ? ? ? ? ? ? ? y1 = range.from;
? ? ? ? ? ? ? ? ? ? y2 = range.to;
? ? ? ? ? ? ? ? }
}else {
y1 = e.getY();
? ? ? ? ? ? ? ? y2 =0.f;
? ? ? ? ? ? }
// 畫半圓
? ? ? ? ? ? float leftTo = y1 -2 * barWidth;
? ? ? ? ? ? float rightTo = y1;
? ? ? ? ? ? float topTo = e.getX() - barWidthHalf;
? ? ? ? ? ? float bottomTo = e.getX() + barWidthHalf;
? ? ? ? ? ? RectF rectFTo =new RectF(leftTo, topTo, rightTo, bottomTo);
? ? ? ? ? ? trans.rectToPixelPhase(rectFTo, mAnimator.getPhaseY());
? ? ? ? ? ? Path path =new Path();
? ? ? ? ? ? path.arcTo(rectFTo, -90, 180, true);
? ? ? ? ? ? RectF rectF =new RectF(y2, topTo, rightTo, bottomTo);
? ? ? ? ? ? trans.rectToPixelPhase(rectF, mAnimator.getPhaseY());
? ? ? ? ? ? if (y1 - barWidth <0) {
path.lineTo(rectFTo.centerX(), rectFTo.bottom);
? ? ? ? ? ? ? ? Path srcPath =new Path();
? ? ? ? ? ? ? ? srcPath.addRect(rectF.left,rectF.top, rectF.right, rectF.bottom, Path.Direction.CW);
? ? ? ? ? ? ? ? path.op(srcPath, Path.Op.INTERSECT); // 相交部分
? ? ? ? ? ? }else {
path.moveTo(rectFTo.centerX(), rectFTo.bottom);
? ? ? ? ? ? ? ? path.lineTo(rectF.left, rectFTo.bottom);
? ? ? ? ? ? ? ? path.lineTo(rectF.left, rectFTo.top);
? ? ? ? ? ? ? ? path.lineTo(rectFTo.centerX(), rectFTo.top);
? ? ? ? ? ? }
c.drawPath(path, mHighlightPaint);
? ? ? ? }
}
}
```
#####最后來看看最終實現(xiàn)效果:

~~~~~~ 結(jié)束,第一次寫簡書,對簡書的格式不熟悉,可能會在代碼開頭和結(jié)尾有“```” ,復(fù)制代碼時請刪除```”。