android自定義View(儀表盤),多屬性可設置


需求:以儀表盤的形式展示數據,要求區間分明,且靈活。


功能(可設置屬性):  


                     當前指示值         

                     儀表盤種類是不超過半圓,還是超過半圓

                     大刻度份數和大刻度內小刻度的份數 

                     指針和原點的顏色(默認爲指針是紅色,圓點是灰色) 

                     外弧的色條,即數據區間

                     刻度和刻度值的顏色(默認爲跟隨外弧的顏色)         

                     原點上方的Text字體的大小和顏色(默認爲黑色,字體大小默認爲半徑的一定比例)           

                     原點下方的Text字體的大小和顏色(默認爲黑色,字體大小默認爲半徑的一定比例)

項目地址:https://github.com/AndroidCloud/PieDashboard   如有不足,歡迎各位issues和開支優化

GitHub地址:https://github.com/AndroidCloud


最終實現效果:


 


技術路線(簡要技術思路,具體實現詳見GitHub的Demo):


1,封裝DashboradBean對象和HighlightCR對象。用於傳遞屬性到View中進行繪製

public class DashboradBean {
    private int maxValue; //刻度盤最大值
    private int minValue; //刻度盤最小值
    private int bigSliceCount;  //刻度盤大刻度區間數
    private int smallSliceCount;  //刻度盤大刻度中小刻度區間數
    private int StartAngle;     //開始角度
    private int allAngle;       //需要畫的總角度
    private List<HighlightCR> highlightCRList; //外弧色帶的集合
    private boolean isHalf;     //是否是半圓以內
    private int scaleColor;     //刻度值的顏色,默認0時,顏色隨色帶變化
    private int scaleTextColor;     //刻度值的讀數的顏色,默認0時,顏色隨色帶變化
    private int centerPointColor;//中心原點的顏色
    private int pointerColor;    //指針的顏色
    //getset忽略

//外弧色帶
public class HighlightCR {

    private int mStartAngle;//開始角度
    private int mSweepAngle;//需要畫的度數
    private int mColor;//色帶顏色
    //getset忽略


2,根據傳遞的屬性對View進行繪製

      首先是控制View的大小適配(根據設定的寬來適配高),如果總弧度小於半圓,View的高度取View的寬度的1/2再           多一點,以爲畫外弧的畫筆要設置粗一點,所以爲了繪製原點,需要留出部分位置。如果總弧度大於半圓,                     View的高度取值和寬度一樣。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width=MeasureSpec.getSize(widthMeasureSpec);
    int height = 0;
    if (dashboradBean!=null){
        //總弧度是半圓以內
        if (dashboradBean.isHalf()){
            height =(int) (width/2f+(width/2f/7.5f));
        }else{
        //總弧度大於半圓    
            height=width;
        }
    setMeasuredDimension(width, height);
    }
}

3,進行繪製,分別繪製刻度盤的弧形,刻度盤的和刻度值,指針和中心原點,原點上方Text,原點下方Text

@Override
protected void onDraw(Canvas canvas) {
    mRadius=getWidth()/2f;
    mHighlightRadius=mRadius/7.5f;
    mCenterX=mRadius;
    mCenterY=mRadius;
    super.onDraw(canvas);
    if (dashboradBean != null) {
        drawMeasures(canvas);/*** 刻度線和刻度值*/
    drawStripe(canvas);/**刻度盤的弧形*/
    drawTopTexts(canvas);/**畫中心原點上方文本*/
        drawEndTexts(canvas);/**畫中心原點下方文本*/
        drawPointer(canvas);    /**畫指針和中心原點*/
    }
}
       繪製刻度線和刻度值(刻度線的長度和刻度值的字體大小都是根據View的寬度來按照一定比例換算得來,以達到            適配的目的),原理是旋轉畫布後畫好,在旋轉回來,依次把所有刻度線和刻度值畫好

/*** 刻度線和刻度值*/
private void drawMeasures(Canvas canvas) {
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStrokeWidth(2);
    Paint p=new Paint();
    p.setStyle(Paint.Style.FILL);
    p.setStrokeWidth(1);
    p.setTextSize(mHighlightRadius / 1.2f);
    p.setAntiAlias(true);
    p.setTextAlign(Paint.Align.CENTER);
    float averageBigangle=((float)dashboradBean.getAllAngle()) /((float)dashboradBean.getBigSliceCount());
    for (int i = 0; i <= dashboradBean.getBigSliceCount(); i++) {
        //繪製大刻度
        float angle = i *averageBigangle+dashboradBean.getStartAngle() ;
        float[] point1 = getCoordinatePoint(mRadius-mHighlightRadius/0.85f, angle);
        float[] point2 = getCoordinatePoint(mRadius-mHighlightRadius/0.85f-mHighlightRadius/5f*2.8f, angle);
        if ( dashboradBean.getHighlightCRList() != null) {
            for (int j = 0; j < dashboradBean.getHighlightCRList().size(); j++) {
                HighlightCR highlightCR = dashboradBean.getHighlightCRList().get(j);
                if (highlightCR.getColor() == 0 || highlightCR.getSweepAngle() == 0)
                    continue;
                if (angle>=highlightCR.getStartAngle()&&angle <= highlightCR.getStartAngle() + highlightCR.getSweepAngle()) {
                    paint.setColor(highlightCR.getColor());
                    p.setColor(highlightCR.getColor());
                    break;
                }
            }
        } else {
            paint.setColor(Color.BLACK);
            p.setColor(Color.BLACK);
        }
        if (dashboradBean.getScaleColor()!=0){
            paint.setColor(dashboradBean.getScaleColor());
        }
        paint.setStrokeWidth(mHighlightRadius / 6f);
        canvas.drawLine(point1[0], point1[1], point2[0], point2[1], paint);
        //繪製圓盤上的數字
        String number =trimFloat(((float) (dashboradBean.getMaxValue()-dashboradBean.getMinValue()))
                /((float)dashboradBean.getBigSliceCount())*i+(float)dashboradBean.getMinValue()) +"";
        if (dashboradBean.getScaleTextColor()!=0){
            p.setColor(dashboradBean.getScaleTextColor());
        }
        //旋轉繪製
        canvas.rotate(360f - (float) dashboradBean.getAllAngle() / 2f + (float) i * averageBigangle, mCenterX, mCenterY);
        canvas.drawText(number, mCenterX, mHighlightRadius * 2.75f, p);
        canvas.rotate(-360f+(float)dashboradBean.getAllAngle()/2f-(float)i*averageBigangle,mCenterX,mCenterY);
    }

    //繪製小的子刻度
    float averageSmallangle=((float)dashboradBean.getAllAngle() )/(float)(dashboradBean.getSmallSliceCount()*dashboradBean.getBigSliceCount());
    for (int i = 0; i < dashboradBean.getSmallSliceCount()*dashboradBean.getBigSliceCount(); i++) {
            float angle = i * averageSmallangle + dashboradBean.getStartAngle();
            float[] point1 = getCoordinatePoint(mRadius-mHighlightRadius/0.85f, angle);
            float[] point2 = getCoordinatePoint(mRadius-mHighlightRadius/0.85f-mHighlightRadius/5f*1.4f, angle);

            if ( dashboradBean.getHighlightCRList() != null) {
                for (int j = 0; j < dashboradBean.getHighlightCRList().size(); j++) {
                    HighlightCR highlightCR = dashboradBean.getHighlightCRList().get(j);
                    if (highlightCR.getColor() == 0 || highlightCR.getSweepAngle() == 0)
                        continue;
                    if (angle>=highlightCR.getStartAngle()&&angle <= highlightCR.getStartAngle() + highlightCR.getSweepAngle()) {
                        paint.setColor(highlightCR.getColor());
                        break;
                    }
                }
            } else {
                paint.setColor(Color.BLACK);
            }
        if (dashboradBean.getScaleColor()!=0){
            paint.setColor(dashboradBean.getScaleColor());
        }
        paint.setStrokeWidth(mHighlightRadius/6f/2f);
            canvas.drawLine(point1[0], point1[1], point2[0], point2[1], paint);
    }
}
         繪製刻度盤的外弧,包括粗的外弧和細的外弧(外弧的粗細程度都是根據View的寬度來按照一定比例換算得來,             以達到適配的目的)

/**刻度盤的弧形*/
private void drawStripe(Canvas canvas) {
        if (dashboradBean.getHighlightCRList()!=null){
        for (int i = 0; i < dashboradBean.getHighlightCRList().size(); i++) {
            HighlightCR highlightCR = dashboradBean.getHighlightCRList().get(i);
            if (highlightCR.getColor() == 0 || highlightCR.getSweepAngle() == 0)
                continue;
            paint.setColor(highlightCR.getColor());
            paint.setStrokeWidth(mHighlightRadius);
            paint.setStrokeCap(Paint.Cap.ROUND);
            paint.setStyle(Paint.Style.STROKE);
            RectF rectF1=new RectF(mHighlightRadius/2f,mHighlightRadius/2f,getWidth()-mHighlightRadius/2f,getWidth()-mHighlightRadius/2f);
            RectF rectF2=new RectF(mHighlightRadius/0.85f,mHighlightRadius/0.85f,getWidth()-mHighlightRadius/0.85f,getWidth()-mHighlightRadius/0.85f);
            canvas.drawArc(rectF1, highlightCR.getStartAngle(),
                    highlightCR.getSweepAngle(), false, paint);
            paint.setStrokeWidth(mHighlightRadius/6f);
            canvas.drawArc(rectF2, highlightCR.getStartAngle(),
                    highlightCR.getSweepAngle(), false, paint);
        }
    }
}

         繪製指針和原點,指針爲一個封閉的三角形,指針的頂點根據傳入的需要顯示的當前值來進行計算(計算前先判             斷該值是否在有效區間內,超過最大值顯示最大值,超過最小值顯示最小值)指針長度按照View的寬度的一                   定比例換算,達到適配,原點爲圓形。

/**畫指針和中心原點*/
private void drawPointer(Canvas canvas) {
    float degree=0;
    if (realTimeValue>=dashboradBean.getMinValue()&&realTimeValue<=dashboradBean.getMaxValue()){
        degree=(float)(dashboradBean.getStartAngle())+((realTimeValue-dashboradBean.getMinValue())/
            (dashboradBean.getMaxValue()-dashboradBean.getMinValue()))*(float)dashboradBean.getAllAngle();
    }else if(realTimeValue<dashboradBean.getMinValue()){
        degree=(float)dashboradBean.getStartAngle();
    }else{
        degree=(float)(dashboradBean.getStartAngle())+(float)dashboradBean.getAllAngle();
    }
    float point[]=getCoordinatePoint(mRadius-mHighlightRadius*2.4f,degree);
    paint.setStyle(Paint.Style.FILL);
        Path p=new Path();
        p.moveTo(point[0], point[1]);
        float point_left[]=getCoordinatePoint(mHighlightRadius / 2f,degree-90);
        float point_right[]=getCoordinatePoint(mHighlightRadius / 2f,degree+90);
        p.lineTo(point_left[0], point_left[1]);
        p.lineTo(point_right[0], point_right[1]);
        p.close();
        if(dashboradBean.getPointerColor()!=0){
            paint.setColor(dashboradBean.getPointerColor());
        }else{
            paint.setColor(Color.RED);
        }
        canvas.drawPath(p, paint);
        if (dashboradBean.getCenterPointColor()!=0){
             paint.setColor(dashboradBean.getCenterPointColor());
        } else {
            paint.setColor(Color.parseColor("#A9AFAE"));
        }
    canvas.drawCircle(mCenterX,mCenterY,mHighlightRadius/1.65f,paint);
}

最後繪製原點上方和下方的Text,字體繪製的位置和字體的大小都是根據View的寬度來按照一定比例換算得到的。

/**畫中心原點下方文本*/
private void drawEndTexts(Canvas canvas) {
    if (EndTextSize==0){
    paint.setTextSize(mHighlightRadius / 1.2f);
    }else {
        paint.setTextSize(EndTextSize);
    }
    if (EndTextColor==0){
        paint.setColor(Color.BLACK);
    }else{
        paint.setColor(EndTextColor);
    }
    paint.setStrokeWidth(1);
    paint.setStyle(Paint.Style.FILL);
    paint.setTextAlign(Paint.Align.CENTER);
    canvas.drawText(endText,mCenterX,mCenterY+3f*mHighlightRadius,paint);
}
/**畫指針和中心原點*/
private void drawTopTexts(Canvas canvas) {
    if (TopTextSize==0){
        paint.setTextSize(mHighlightRadius / 1.4f);
    }else {
        paint.setTextSize(TopTextSize);
    }
    if (TopTextColor==0){
        paint.setColor(Color.BLACK);
    }else{
        paint.setColor(TopTextColor);
    }
    paint.setStrokeWidth(1);
    paint.setStyle(Paint.Style.FILL);
    paint.setTextAlign(Paint.Align.CENTER);
    canvas.drawText(topText,mCenterX,mCenterY-mHighlightRadius,paint);
}
 

4,在Activity中使用,Demo的第一組示例佈局如下所示,寬度取屏幕的一半

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp"
    android:orientation="horizontal">
    <com.example.vmmet.mypiedashboard.view.NewDashboardView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:id="@+id/view1"
        />
    <com.example.vmmet.mypiedashboard.view.NewDashboardView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:id="@+id/view2"
        />
</LinearLayout>
 

如圖中所示的第一個示例。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();
    /**大刻度份數和小刻度份數(半圓)*/
    setView_1_2();

/**大刻度份數和小刻度份數(半圓)*/
private void setView_1_2() {
    List<HighlightCR> highlights = new ArrayList<>();
    highlights.add(new HighlightCR(180, 40, Color.parseColor("#4CAF50")));
    highlights.add(new HighlightCR(220, 50, Color.parseColor("#EEC900")));
    highlights.add(new HighlightCR(270, 90, Color.parseColor("#F44336")));
    DashboradBean dashboradBean=new DashboradBean();
    dashboradBean.setHighlightCRList(highlights);
    dashboradBean.setAllAngle(180);
    dashboradBean.setStartAngle(180);
    dashboradBean.setBigSliceCount(5);
    dashboradBean.setSmallSliceCount(3);
    dashboradBean.setMaxValue(100);
    dashboradBean.setMinValue(0);
    dashboradBean.setIsHalf(true);
    view1.setDashboradBean(dashboradBean);
    view1.setRealTimeValue(60);
    ///////////////////////////////
    DashboradBean dashboradBean2=new DashboradBean();
    dashboradBean2.setHighlightCRList(highlights);
    dashboradBean2.setAllAngle(180);
    dashboradBean2.setStartAngle(180);
    dashboradBean2.setBigSliceCount(10);
    dashboradBean2.setSmallSliceCount(5);
    dashboradBean2.setMaxValue(200);
    dashboradBean2.setMinValue(100);
    dashboradBean2.setIsHalf(true);
    view2.setDashboradBean(dashboradBean2);
    view2.setRealTimeValue(120);
}


                          做開發,需要腳踏實地,日積月累,願你我共勉

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章