1. 程式人生 > >Android 效果之帶刻度的半圓環進度條小述

Android 效果之帶刻度的半圓環進度條小述

一、背景

最近準備要做一個類似儀表盤樣式的半圓環帶刻度可拖動的進度條來展示和設定溫度,網上找了找demo,都和實際的需求有點區別,感覺這種功能實現起來不難,就索性自己弄了一個。

二、正文

在開始之前,我們來看下實際的執行效果,看看能不能滿足正在查詢資料的小夥伴的專案需求:

這裡寫圖片描述

效果就是這樣的啦,沒什麼特別的地方,我們來看下實現方法吧,如果對於自定義View的流程還有些不清楚,可以檢視一下自定義簡單View及獲取xml自定義屬性,裡面總結了自定義View的整體思路和流程,在本例中我們可以將要實現的View分解成一個個基本的小功能,再集中優勢力量各個擊破,思路如下:

1.繼承一個View或者一個我們需要的View的子類,並新增構造方法
2.重寫onMeasure方法
3.重寫onDraw方法 ,在這裡我們將上面的View分解為灰色的半圓環、藍色的半圓環、環上的按鈕圖示、灰色刻度線、藍色刻度線、中間顯示的進度幾個部分
4.重寫onTouchEvent方法,獲取使用者觸屏狀態,再進行相應處理
5.在xml中自定義View屬性

下面來讓我們跟著上面的思路來看看具體的實現程式碼吧,這是我們的自定義View類,我們添加了不同引數的構造方法,如果你只需要在xml中使用當前的自定義View,我們只需要新增兩個引數的構造方法即可

public class MyHalfCricularSlideWithScaleView extends View{

	//在程式碼中直接new的時候,會呼叫一個引數構造方法
    public MyHalfCricularSlideWithScaleView(Context context) {
        this(context, null);
    }

	//在xml中使用自定義控制元件的時候,不管有沒有使用我們自己的自定義屬性都會呼叫兩個引數構造方法
public MyHalfCricularSlideWithScaleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } //這個構造方法系統不會預設呼叫,需要我們自己主動呼叫 public MyHalfCricularSlideWithScaleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs,
defStyleAttr); init(context, attrs, defStyleAttr); } private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { } }

這是我們所宣告的變數,看著數量這麼多特別嚇人,但其實我告訴你這並不是一蹴而就的,而是你在編寫的過程中,陸陸續續發現少了引數而不斷新增後的結果,而且由於我是先寫了demo後才寫的部落格,這兩者並不是同步的,所以就造成onDraw方法裡實現繪製每個小功能的初始化程式碼都放在了一起,正常的寫的話都是按照上面步驟一點一點實現的。

    //圓環的寬度
    float ringWidth;
    //底部的圓弧顏色
    int ringBgCorlor;
    //滑動的圓弧顏色
    int slideRingCorlor;
    //同心圓的外圓半徑
    int radius;
    //中間字的顏色
    int wordCorlor;
    //中間字的大小
    int wordSize;

    //最大進度範圍
    int maxProgress;
    //最小進度範圍
    int minProgress;
    //當前進度(總是將起始位置等分為100份),通過進度的百分比求出實際顯示數值
    int progress;
    //實際顯示的數值
    double realShowProgress;
    //每次要增加減少的數值
    double addOrReduce = 1;
    //開始滑動的起始位置度數,頂部270 右側0 底部90 左側180,因為這是半圓直接寫死從左側180開始滑動
    int beginLocation;
    //當前可滑動區域的範圍
    int slideAbleLocation;

    //圓環上的圓圈
    Bitmap mDragBitmap;
    //圓環的寬
    int bitmapWidth;
    //圓環的高度
    int bitmapHight;

    //外側刻度線的數量
    int scaleLineCount;
    //外側正常刻度線的長度
    int scaleLineLength;
    //線條的寬度
    int scaleLineWidth;
    //需要特殊處理的刻度線長度,例如正方位上的刻度或者當前刻度
    int specialScaleLineLength;
    //刻度結束的角度
    float sweepAngle = 180;//因為是半圓,這裡就寫死了
    //未選擇的刻度線顏色
    int scaleLineNormalCorlor;
    //滑動後的刻度線顏色
    int specialScaleCorlor;
    //刻度線距離裡面的環的距離
    int scaleToRingSpace;

    //畫底部背景環的畫筆
    Paint ringBgPaint;
    //畫上面圓弧的畫筆
    Paint slideRingPaint;
    //圓環上的小圓圈
    Paint mBitmapPaint;
    //寫當前progress的畫筆
    Paint wordPaint;
    //畫普通背景刻度線的畫筆
    Paint scalePaint;
    //這是畫滑動後的刻度顏色畫筆
    Paint specialScalePaint;

    //顯示中間顯示文字(當前為progress)所佔的區域
    Rect rect;

    //這是保留小數的使用類
    DecimalFormat df;

正是由於我是寫了demo之後才寫的部落格,所以我就直接先展示我們所需要的view屬性了,你如果想自己從頭實現一個,完全可以給所需要的變數一個寫死的測試值,到功能實現之後,再將測試值替換成xml屬性。言歸正傳,我們在values目錄下新建attrs.xml,並建立declare-styleable,如下:

    <!--自定義的半圓環帶刻度可拖動SeekBar進度條效果-->
    <declare-styleable name="MyHalfCircularSildeView"
        >
        <!--圓環的寬度-->
        <attr name="ringWidth" format="float"/>
        <!--滑動圓弧的背景-->
        <attr name="slideRingCorlor" format="integer"/>
        <!--底部圓弧的背景-->
        <attr name="ringBgCorlor" format="integer"/>
        <!--當前文字的背景-->
        <attr name="wordCorlor" format="integer"/>
        <!--當前文字的大小-->
        <attr name="wordSize" format="integer"/>
        <!--同心圓外圓的半徑-->
        <attr name="radius" format="integer"/>
        <!--最大顯示進度-->
        <attr name="maxProgress" format="integer"/>
        <!--最小顯示進度-->
        <attr name="minProgress" format="integer"/>
        <!--當前顯示進度-->
        <attr name="progress" format="integer"/>

        <!--下面這是刻度線的一些屬性-->
        <!--刻度線的總數-->
        <attr name="scaleLineCount" format="integer"/>
        <!--普通刻度線的長度-->
        <attr name="scaleLineLength" format="integer"/>
        <!--特殊刻度線的長度-->
        <attr name="specialScaleLineLength" format="integer"/>
        <!--線條的寬度-->
        <attr name="scaleLineWidth" format="integer"/>
        <!--刻度線距離圓環的寬度-->
        <attr name="scaleToRingSpace" format="integer"/>
        <!--普通線的顏色-->
        <attr name="scaleLineNormalCorlor" format="integer"/>
        <!--特殊線的顏色-->
        <attr name="specialScaleCorlor" format="integer"/>
    </declare-styleable>

這是我們的變數初始化程式碼,沒有什麼可說的

private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        //dip2px這個方法就是將dp轉換成px
        slideAbleLocation = CommentUtil.dip2px(context, 30);

        bitmapWidth = CommentUtil.dip2px(context, 30);
        bitmapHight = CommentUtil.dip2px(context, 30);

        //設定圓環上的小圓圖示的大小
        mDragBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ring_dot);
        mDragBitmap = CommentUtil.conversionBitmap(mDragBitmap
                , bitmapWidth
                , bitmapHight);

        //獲取xml中定義屬性,並對需要的變數進行初始化
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs
                , R.styleable.MyHalfCircularSildeView
                , defStyleAttr, 0);
        ringWidth = array.getInt(R.styleable.MyHalfCircularSildeView_ringWidth, CommentUtil.dip2px(context, 10));
        slideRingCorlor = array.getInt(R.styleable.MyHalfCircularSildeView_slideRingCorlor, 0xFF6a6aff);
        ringBgCorlor = array.getInt(R.styleable.MyHalfCircularSildeView_ringBgCorlor, 0xFFbebebe);
        radius = array.getInt(R.styleable.MyHalfCircularSildeView_radius, CommentUtil.dip2px(context, 100));
        wordCorlor = array.getInt(R.styleable.MyHalfCircularSildeView_wordCorlor, Color.BLUE);
        wordSize = array.getInt(R.styleable.MyHalfCircularSildeView_wordSize, 18);
        maxProgress = array.getInt(R.styleable.MyHalfCircularSildeView_maxProgress, 100);
        minProgress = array.getInt(R.styleable.MyHalfCircularSildeView_minProgress, 0);
        progress = array.getInt(R.styleable.MyHalfCircularSildeView_progress, 15);
        //因為這是個半弧,所以我們直接寫死了,從左側開始
        beginLocation = 180;
        //下面是刻度線的屬性
        scaleLineCount = array.getInt(R.styleable.MyHalfCircularSildeView_scaleLineCount, 100);
        scaleLineLength = array.getInt(R.styleable.MyHalfCircularSildeView_scaleLineLength, CommentUtil.dip2px(context, 10));
        specialScaleLineLength = array.getInt(R.styleable.MyHalfCircularSildeView_specialScaleLineLength, CommentUtil.dip2px(context, 15));
        scaleToRingSpace = array.getInt(R.styleable.MyHalfCircularSildeView_scaleToRingSpace, CommentUtil.dip2px(context, 10));
        scaleLineNormalCorlor = array.getInt(R.styleable.MyHalfCircularSildeView_scaleLineNormalCorlor, 0xFFbebebe);
        specialScaleCorlor = array.getInt(R.styleable.MyHalfCircularSildeView_specialScaleCorlor, 0xFF6a6aff);
        scaleLineWidth = array.getInt(R.styleable.MyHalfCircularSildeView_scaleLineWidth, CommentUtil.dip2px(context, 2));
        //記得使用完銷燬
        array.recycle();

        //保留1位小數
        df = new DecimalFormat("#.0");
        realShowProgress = getShowProgress(progress);
    }

這是我們在初始化圓環上小圖示mDragBitmap點陣圖的時候,設定寬高的工具方法

    //轉換bitmap寬高
    public static Bitmap conversionBitmap(Bitmap bitmap, int newWidth, int newHeight) {
        Bitmap b = bitmap;
        int width = b.getWidth();
        int height = b.getHeight();
        // 計算縮放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要縮放的matrix引數
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的圖片
        return Bitmap.createBitmap(b, 0, 0, width, height, matrix, true);
    }

這是我們要根據刻度數量獲取展示數字的方法,因為目前要求刻度線的數量為100,但是進度範圍不一定是0-100,所以這就要求我們要根據當前的刻度數轉化成實際要顯示的數字,例如10-90範圍內,滑動了50個刻度,當前刻度為(90-10) * (50.0/100) + 10 = 50

    /** 根據progress,再求出如果首位不是0-100的時候的數字*/
    private double getShowProgress(int progress) {
        return Double.parseDouble(df.format((maxProgress - minProgress)/100.0 * progress + minProgress));
    }

這是我們初始畫筆的方法

private void initPaint(Context context) {
        //畫背景圓弧的畫筆初始化
        ringBgPaint = new Paint();
        ringBgPaint.setColor(ringBgCorlor);
        ringBgPaint.setAntiAlias(true);// 抗鋸齒效果
        ringBgPaint.setStyle(Paint.Style.STROKE);//設定空心
        ringBgPaint.setStrokeWidth(ringWidth);//線寬度,即環寬
        ringBgPaint.setStrokeCap(Paint.Cap.ROUND);//圓形筆頭

        //畫滑動圓弧的畫筆初始化
        slideRingPaint = new Paint();
        slideRingPaint.setAntiAlias(true);
        slideRingPaint.setStyle(Paint.Style.STROKE);
        slideRingPaint.setColor(slideRingCorlor);
        slideRingPaint.setStrokeWidth(ringWidth);
        slideRingPaint.setStrokeCap(Paint.Cap.ROUND);//圓形筆頭

        //寫中間文字的畫筆初始化
        wordPaint = new Paint();
        wordPaint.setColor(wordCorlor);
        wordPaint.setTextSize(CommentUtil.sp2px(context, wordSize));
        rect = new Rect();
        String str = progress+" C";
        wordPaint.getTextBounds(str, 0, str.length(),rect);

        //設定圓環上圓圈的畫筆初始化
        mBitmapPaint = new Paint();
        mBitmapPaint.setDither(true);//設定防抖動
        mBitmapPaint.setFilterBitmap(true);//對Bitmap進行濾波處理
        mBitmapPaint.setAntiAlias(true);//設定抗鋸齒

        //這是畫外面刻度線的畫筆
        scalePaint = new Paint();
        scalePaint.setColor(scaleLineNormalCorlor);
        scalePaint.setAntiAlias(true);
        scalePaint.setStyle(Paint.Style.STROKE);
        scalePaint.setStrokeWidth(scaleLineWidth);

        //這是畫滑動後的刻度線的畫筆
        specialScalePaint = new Paint();
        specialScalePaint.setColor(specialScaleCorlor);
        specialScalePaint.setAntiAlias(true);
        specialScalePaint.setStyle(Paint.Style.STROKE);
        specialScalePaint.setStrokeWidth(scaleLineWidth);
    }

重寫onMeasure方法,當layout_width和layout_height為wrap_content時,我們要給View設定大小,否則寬高會佔據全屏

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthModel = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightModel = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        switch (widthModel) {
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:
                //當時自適應控制元件的時候,寬度為圓直徑+左右邊距+2*(刻度線寬+刻度線距離圓環)
                widthSize = 2*radius + getPaddingLeft() + getPaddingRight() +2*(specialScaleLineLength + scaleToRingSpace);
                break;
            case MeasureSpec.EXACTLY:
                break;
        }
        switch (heightModel) {
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:
                //當控制元件自適應時候,尺寸=半徑+上下邊距+刻度線寬+刻度線距離圓環+圓環上圖示*0.5
                heightSize = radius + getPaddingTop() + getPaddingBottom() + bitmapHight/2 + specialScaleLineLength + scaleToRingSpace;
                break;
            //當寬度全屏或者固定尺寸時候
            case MeasureSpec.EXACTLY:
                break;
        }
        setMeasuredDimension(widthSize, heightSize);
    }

重寫onDraw方法,這是我們畫圓環背景的方法,drawArc方法的第一個引數為繪製圓弧所在的矩形區域範圍(取左上和右下座標)、第二個引數設定圓弧是從哪個角度來順時針繪畫的(0:右側,90下面,180左側,270上面)、第三個引數設定圓弧掃過的角度、第四個引數設定我們的圓弧在繪畫的時候是否經過圓形、第五個引數設定我們的畫筆物件的屬性。

        //畫背景圓環
        canvas.drawArc(new RectF(ringWidth/2 + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace
                        , ringWidth/2 + getPaddingTop() + specialScaleLineLength + scaleToRingSpace
                        , 2*radius- ringWidth/2 + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace
                        , 2*radius - ringWidth/2 + getPaddingTop() + specialScaleLineLength + scaleToRingSpace)
                , beginLocation, 180, false, ringBgPaint);

這是我們畫能拖動的圓環的方法

        //畫滑動圓弧
        canvas.drawArc(new RectF(ringWidth/2 + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace
                        , ringWidth/2 + getPaddingTop() + specialScaleLineLength + scaleToRingSpace
                        , 2*radius- ringWidth/2 + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace
                        , 2*radius - ringWidth/2 + getPaddingTop() + specialScaleLineLength + scaleToRingSpace)
                , beginLocation, progress * 180/100, false, slideRingPaint);

這是我們畫圓環上的小圖示的方法,難點主要是求小圓標在圓環不同位置上的圓點座標,反正我是把數學知識都交給體育老師了,直接在網上找的現成的方法

        //畫上滑動圖示
        PointF progressPoint = CommentUtil.calcArcEndPointXY(radius + getPaddingLeft() + specialScaleLineLength + scaleToRingSpace
                , radius + getPaddingTop() + specialScaleLineLength + scaleToRingSpace
                , radius - ringWidth/2
                , progress * 180/100, 180);
        int left = (int) progressPoint.x - mDragBitmap.getWidth() / 2;
        int top = (int
            
           

相關推薦

Android 效果刻度半圓進度

一、背景 最近準備要做一個類似儀表盤樣式的半圓環帶刻度可拖動的進度條來展示和設定溫度,網上找了找demo,都和實際的需求有點區別,感覺這種功能實現起來不難,就索性自己弄了一個。 二、正文 在開始之前,我們來看下實際的執行效果,看看能不能滿足正在查詢資料的小夥伴的

Android自定義動畫圓進度

1.首先是自定義類 package com.yx.yxcustomprogress; import android.content.Context; import android.content.res.TypedArray; import android.graphi

使用 Android Studio自定義View03——圓進度

整理總結自鴻洋的部落格:http://blog.csdn.net/lmj623565791/article/details/24500107 要實現的效果如圖: 分析一下,需要這麼幾個屬性:兩個顏色、一個速度、一個圓環寬度 com.cctvjiatao.customvie

Android繪圖:自定義View——矩形進度、圓進度、填充型進度、時鐘

主函式 這幾種進度條的主函式都是類似的,所以下面我只給出了一個填充型進度條的主函式,其他幾個主函式只是在這基礎上改動一下按鈕id(即與各自佈局裡面的id相同即可),還有改動一下相對應的類即可。 public class MainActivity

Android自定義控制元件百分比圓進度

首先我們先來看一下效果 分析 我們來看這個進度條應該分為3個小部分 1.中間的圓 2.外邊的圓環 3.中間的文字 分開畫 這3部分就是需要我們自己畫出來的,因此我們需要3根畫筆 //設定中心園的畫筆

Android 從無到有打造一個炫酷的進度效果

fault ref size art href 一個 font itl top 從無到有打造一個炫酷的進度條效果Android 從無到有打造一個炫酷的進度條效果

Android學習---使用非同步內部類實現進度載入效果

Android學習—使用非同步內部類 為什麼要用AsyncTask? 答:我們可以用上述兩種方法來完成我們的非同步操作,加入要我們寫的非同步操作比較多,或者較為繁瑣, 難道我們new Thread()然後用上述方法通知UI更新麼?程式設計師都是比較喜歡偷懶的,既然官方給我 們

自定義控制元件Android進度

Android自定義控制元件學習之圓環進度條,學習了一段時間,自定義控制元件,對一些自定義所需要的Api,基本上也掌握了,但是對於比較複雜的自定義控制元件,他們的座標計算 一直比較噁心(可能,我數學比較差~),記錄自定義控制元件學習過程。    對於圓環進度條的自定義

Android 自定義View,繪製一個比例的環形進度

最近專案有一個需求,要在首頁顯示三個環形餅狀圖,要求可以顯示比例大小,中間顯示文字部分,並且需要可以自定義顏色。設計圖如下: 思路: 繪製一個帶百分比的圓環,一共分了四個部分: 1.背景圓(就是底圖圓) 2.預設圓環 3.繪製的圓環(就是比例圓環) 4.中心文字 下面我們開始進行繪製,先準

android動畫的圓形進度

偶然發現一個很好的app,圓環進度條,帶加速動畫,看起來相當不錯。嘗試著克隆一下。 反編譯一看,哇塞,啥3.1415926都幹出來了,太高階玩不轉啊,算了,想想其它方式吧。 先看效果圖: 這個草稿存了小半年.....先發布了再說。實現了預想的效果,具體程式碼稍後奉上。

Android開發陰影的PopupWindow

先上效果圖, 中間是一個PopupWindow,旁邊為灰色背景. 首先建立一個PopupWindow的子類,初始化控制元件,並設定如下屬性: this.setContentView(mView); this.setWidth(ViewGroup.La

Android開發時間刻度

一、最近的一個專案中有遇到時間刻度盤的需求,在網上沒找到合適的,於是自己就花點時間實現了,現在分享出來,效果如下圖: 在介紹如何實現之前,先大概介紹一個這個時間刻度盤的功能: 1、顯示當前時間,並且可以左右拖動至上一天或者下一天, 2、根據傳入的時間塊來繪製藍色部分 二、

Android開發shape畫圓的方法

方法一:<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:innerRad

canvas繪製圓進度出現模糊效果解決方案

問題 近期用canvas繪製了圓環進度條,但是進度條出現周圍模糊的現象,針對這種現象,網上搜了搜,有人提問,但是貌似沒有很好的解決方案,針對這種情況,提出幾種解決方案,僅供參考! 模糊效果如下: 解決方案 針對這種情況,我提出幾種解決思路。 一、運用hidpi-canvas-polyfill 的js

android開發美化版的ProgressDialog進度

大夥也都知道,android版本太多了!哎,據統計截止今年1月初,安卓5.0佔有率不到0.1%。使用者大多仍使用Android Jelly Bean(果凍豆)系統,市場份額為46%,其中4.1佔19.2%,4.2佔20.3%,4.3佔6.5%。排在第二的是安卓4.4系統(3

Android自定義View:水平數字百分比的進度

public class NumberProgressView extends View { /** * 進度條畫筆的寬度(dp) */ private int paintProgressWidth = 3; /** * 文字百分比的字型大小(sp)

Android 四大元件Service的啟動、繫結

一、概述 學習過Android的小夥伴就不可能不知道Service是什麼,因為Service是Android四大元件之一,聲名赫赫有木有,所以在這裡我就不詳細介紹了,本節主要還是充當筆記的作用,因為我待記性如初戀,記性虐我千百遍。 二、Service的建立 Service是一

SpringMVC檔案上傳(進度顯示)

親測可用 1、mvc-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"   

Android 自定義View ProgressBarHorizontal:橫向進度、支援圓角、漸變、圖片

背景:因系統的ProgressBar設定圖片時,如果圖片不夠大,而在大解析度的手機上時會出現無法填充滿,所以自己寫一個,既修復該問題,又可方便拓展,所以拋磚引玉 功能介紹:橫向進度條,分為背景與封面兩層,封面與背景均支援圓角矩形、漸變、圖片。 效果圖: (上面仿微博

Android初級,MediaPlayer播放音樂,進度滑動及唱片轉動功能實現

最近在做仿網易雲音樂播放器的實訓專案,學習完後寫此部落格,一方面鞏固自己理解,一方面方便各位瀏覽。 讀完本文你將瞭解到: 如何利用MediaPlayer播放音樂 如何設定音樂進度條並實現自動滾動及手動定位 如何實現唱片轉動功能 1.效果圖