1. 程式人生 > >Android:自定義View實現水波進度效果

Android:自定義View實現水波進度效果

首先上效果圖:


簡介:

1.自動適應螢幕大小;

2.水波自動橫向滾動;

3.各種繪製引數可通過修改常量進行控制。

程式碼不多,註釋也比較詳細,全部貼上:

(一)自定義元件:

/**
 * 水波進度效果.
 */
public class WaterWaveView extends View {
    //邊框寬度
    private int STROKE_WIDTH;
    //元件的寬,高
    private int width, height;
    /**
     * 進度條最大值和當前進度值
     */
    private float max, progress;

    /**
     * 繪製波浪的畫筆
     */
    private Paint progressPaint;

    //波紋振幅與半徑之比。(建議設定:<0.1)
    private static final float A = 0.05f;
    //繪製文字的畫筆
    private Paint textPaint;
    //繪製邊框的畫筆
    private Paint circlePaint;

    /**
     * 圓弧圓心位置
     */
    private int centerX, centerY;

    //內圓所在的矩形
    private RectF circleRectF;

    public WaterWaveView(Context context) {
        super(context);
        init();
    }

    public WaterWaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public WaterWaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    //初始化
    private void init() {
        progressPaint = new Paint();
        progressPaint.setColor(Color.parseColor("#77cccc88"));
        progressPaint.setAntiAlias(true);

        textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setAntiAlias(true);

        circlePaint = new Paint();
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setAntiAlias(true);
        circlePaint.setColor(Color.parseColor("#33333333"));

        autoRefresh();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (width == 0 || height == 0) {
            width = getWidth();
            height = getHeight();

            //計算圓弧半徑和圓心點
            int circleRadius = Math.min(width, height) >> 1;
            STROKE_WIDTH = circleRadius / 10;
            circlePaint.setStrokeWidth(STROKE_WIDTH);

            centerX = width / 2;
            centerY = height / 2;

            VALID_RADIUS = circleRadius - STROKE_WIDTH;
            RADIANS_PER_X = (float) (Math.PI / VALID_RADIUS);
            circleRectF = new RectF(centerX - VALID_RADIUS, centerY - VALID_RADIUS,
                    centerX + VALID_RADIUS, centerY + VALID_RADIUS);
        }
    }

    private Rect textBounds = new Rect();

    //x方向偏移量
    private int xOffset;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //繪製圓形邊框
        canvas.drawCircle(centerX, centerY, VALID_RADIUS + (STROKE_WIDTH >> 1), circlePaint);
        //繪製水波曲線
        canvas.drawPath(getWavePath(xOffset), progressPaint);

        //繪製文字
        textPaint.setTextSize(VALID_RADIUS >> 1);
        String text1 = String.valueOf(progress);
        //測量文字長度
        float w1 = textPaint.measureText(text1);
        //測量文字高度
        textPaint.getTextBounds("8", 0, 1, textBounds);
        float h1 = textBounds.height();
        float extraW = textPaint.measureText("8") / 3;
        canvas.drawText(text1, centerX - w1 / 2 - extraW, centerY + h1 / 2, textPaint);

        textPaint.setTextSize(VALID_RADIUS / 6);
        textPaint.getTextBounds("M", 0, 1, textBounds);
        float h2 = textBounds.height();
        canvas.drawText("M", centerX + w1 / 2 - extraW + 5, centerY - (h1 / 2 - h2), textPaint);

        String text3 = "共" + String.valueOf(max) + "M";
        float w3 = textPaint.measureText(text3, 0, text3.length());
        textPaint.getTextBounds("M", 0, 1, textBounds);
        float h3 = textBounds.height();
        canvas.drawText(text3, centerX - w3 / 2, centerY + (VALID_RADIUS >> 1) + h3 / 2, textPaint);

        String text4 = "流量剩餘";
        float w4 = textPaint.measureText(text4, 0, text4.length());
        textPaint.getTextBounds(text4, 0, text4.length(), textBounds);
        float h4 = textBounds.height();
        canvas.drawText(text4, centerX - w4 / 2, centerY - (VALID_RADIUS >> 1) + h4 / 2, textPaint);

    }

    //繪製水波的路徑
    private Path wavePath;
    //每一個畫素對應的弧度數
    private float RADIANS_PER_X;
    //去除邊框後的半徑(即內圓半徑)
    private int VALID_RADIUS;

    /**
     * 獲取水波曲線(包含圓弧部分)的Path.
     *
     * @param xOffset x方向畫素偏移量.
     */
    private Path getWavePath(int xOffset) {
        if (wavePath == null) {
            wavePath = new Path();
        } else {
            wavePath.reset();
        }

        float[] startPoint = new float[2];  //波浪線起點
        float[] endPoint = new float[2];  //波浪線終點

        for (int i = 0; i <= VALID_RADIUS * 2; i += 2) {
            float x = centerX - VALID_RADIUS + i;
            float y = (float) (centerY + VALID_RADIUS * (1.0f + A) * 2 * (0.5f - progress / max)
                    + VALID_RADIUS * A * Math.sin((xOffset + i) * RADIANS_PER_X));

            //只計算內圓內部的點,邊框上的忽略
            if (calDistance(x, y, centerX, centerY) > VALID_RADIUS) {
                if (x < centerX) {
                    continue;  //左邊框,繼續迴圈
                } else {
                    break; //右邊框,結束迴圈
                }
            }

            //第1個點
            if (wavePath.isEmpty()) {
                startPoint[0] = x;
                startPoint[1] = y;
                wavePath.moveTo(x, y);
            } else {
                wavePath.lineTo(x, y);
            }

            endPoint[0] = x;
            endPoint[1] = y;
        }

        if (wavePath.isEmpty()) {
            if (progress / max >= 0.5f) {
                //滿格
                wavePath.moveTo(centerX, centerY - VALID_RADIUS);
                wavePath.addCircle(centerX, centerY, VALID_RADIUS, Path.Direction.CW);
            } else {
                //空格
                return wavePath;
            }
        } else {
            //新增圓弧部分
            float startDegree = calDegreeByPosition(startPoint[0], startPoint[1]);  //0~180
            float endDegree = calDegreeByPosition(endPoint[0], endPoint[1]); //180~360
            wavePath.arcTo(circleRectF, endDegree - 360, startDegree - (endDegree - 360));
        }

        return wavePath;
    }

    private float calDistance(float x1, float y1, float x2, float y2) {
        return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    //根據當前位置,計算出進度條已經轉過的角度。
    private float calDegreeByPosition(float currentX, float currentY) {
        float a1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI * 180);
        if (currentY < centerY) {
            a1 += 180;
        } else if (currentY > centerY && currentX > centerX) {
            a1 += 360;
        }

        return a1 + 90;
    }

    public void setMax(int max) {
        this.max = max;
        invalidate();
    }

    //直接設定進度值(同步)
    public void setProgressSync(float progress) {
        this.progress = progress;
        invalidate();
    }

    /**
     * 自動重新整理頁面,創造水波效果。元件銷燬後該線城將自動停止。
     */
    private void autoRefresh() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!detached) {
                    xOffset += (VALID_RADIUS >> 4);
                    SystemClock.sleep(100);
                    postInvalidate();
                }
            }
        }).start();
    }

    //標記View是否已經銷燬
    private boolean detached = false;

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        detached = true;
    }
}

(二)使用方法:

在xml佈局中引入上述元件,然後在activity或fragment中設定屬性:

WaterWaveView bar = (WaterWaveView) getActivity().findViewById(R.id.water_wave_view);
        bar.setMax(500);
        bar.setProgressSync(361.8f);



相關推薦

Android定義View實現水波進度效果

首先上效果圖: 簡介: 1.自動適應螢幕大小; 2.水波自動橫向滾動; 3.各種繪製引數可通過修改常量進行控制。 程式碼不多,註釋也比較詳細,全部貼上: (一)自定義元件: /** * 水波進度效果. */ public class WaterWaveView e

Android定義View實現圓弧進度效果

前言:Android開發中,自定義View實現自己想要的效果已成為一項必備的技能,當然自定義View也是Android開發中比較難的部分,涉及到的知識有Canvas(畫布),Paint(畫筆)等,自定義控制元件分為三種:一是直接繼承自View,完全的自定義;二是在原有控制元件

Android繪圖定義View之——矩形進度條、圓環進度條、填充型進度條、時鐘

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

Android 定義View實現圓形進度條 深入理解onDraw和onMeasure及定義屬性

Android的View類是使用者介面的基礎構件,表示螢幕上的一塊矩形區域,負責這個區域的繪製和事件處理。自定義View的過程主要包括重寫onDraw及onMeasure方法 , 其中onMeasure方法的作用就是計算出自定義View的寬度和高度。這個計算的過

Android定義View——實現水波紋效果類似剩余流量球

string 三個點 pre ber block span 初始化 move 理解 最近突然手癢就想搞個貝塞爾曲線做個水波紋效果玩玩,終於功夫不負有心人最後實現了想要的效果,一起來看下吧: 效果圖鎮樓 一:先一步一步來分解一下實現的過程 需要繪制一個正弦曲線(sin

定義View實現圓形進度條跳轉頁面

效果: //首先在values資料夾下建立一個attrs.xml: ?xml version=“1.0” encoding=“utf-8”?> //佈局: <?xml version="1.0" encoding="utf-8"?>

Android 定義View實現拖拽效果

騰訊QQ有那種紅點拖動效果,今天就來實現一個簡單的自定義View拖動效果,再回到原處,並非完全仿QQ紅點拖動 先來看一下效果圖 簡單說一下實現步驟 1.建立一個類繼承View 2.繪製出一個

Android 定義View實現圓形環繞效果

之前專案中需要實現一個四周環繞中心圓形頭像的效果,感覺還是自定義比較方便,於是就自己封裝了一個控制元件去實現。先貼張圖顯示最終效果。 首先自定義一個View繼承自LinearLayout,通過動態新增childView的方式將子控制元件新增到View中。思路是先新增中間圓形頭像

Android 定義view實現水波紋效果

今天主要分享水波紋效果:1.標準正餘弦水波紋;2.非標準圓形液柱水波紋;雖說都是水波紋,但兩者在實現上差異是比較大的,一個通過正餘弦函式模擬水波紋效果,另外一個會運用到影象的混合模式(PorterDuffXfermode);先看效果:                     

Android定義View實現水波紋效果

本篇博文介紹一個Android自定義View的案例,後續博文會接下自定義View的相關流程和繪製原理。通過自定義控制元件實現。觸控式螢幕幕實現水波紋效果。實現步驟第1步.自定義MyWave繼承Viewpublic class MyWave extends View {}第2步

Android定義View——實現水波紋效果類似剩餘流量球

最近突然手癢就想搞個貝塞爾曲線做個水波紋效果玩玩,終於功夫不負有心人最後實現了想要的效果,一起來看下吧: 效果圖鎮樓 一:先一步一步來分解一下實現的過程 需要繪製一個正弦曲線(sin)或者餘弦曲線(cos) 通過水平平移曲線來的到像水

定義view實現水波紋效果

自定義view實現水波紋效果 參考csdn大神 啟艦的部落格http://blog.csdn.net/harvic880925/article/details/50995587,自己實現了一遍,碰到的坑有2個: 1、記得呼叫mPath.reset(),否則每次的path內容會疊

翻翻git之---定義View實現水位上漲效果 WaveProgressView

P1 (廢話部分,技術內容在P2) 上週陸續收到一些想嘗試性換工作的小夥伴們的簡歷,相關的負責的HR妹子已經電話轟炸過去了,如果有興趣的小夥伴可以看下http://blog.csdn.net/ddwhan0123/article/details/507

定義View實現圓形水波進度

每次聽到某大牛談論自定義View,頓時敬佩之心,如滔滔江水連綿不絕,心想我什麼時候能有如此境界,好了,心動不如行動,於是我開始了自定義View之路,雖然過程有坎坷,但是結果我還是挺滿意的。我知道大牛還遙不可及,但是我已使出洪荒之力。此篇部落格記錄本人初入自定義View之路。 既

Android定義View實現類似水波擴散效果

自定義View一共分為6步第一步public SpreadView(Context context) { this(context,null,0); } public SpreadView(Context context, @Nullable AttributeSe

定義View實現圓形水波進度條(上)

來源:伯樂線上專欄作者 - Code4Android 連結:http://android.jobbole.com/84776/ 每次聽到某大牛談論自定義View,頓時敬佩之心,如滔滔江水連綿不絕,心想我什麼時候能有如此境界,好了,心動不如行動,於是我開始了自定義View之路,雖然過程有坎坷,但是

定義View實現圓形水波進度條(下)

來源:伯樂線上專欄作者 - Code4Android 連結:http://android.jobbole.com/84776/ 接上文 通過效果圖,我們看到實現此效果就是不斷的更新進度值,然後重繪,,那麼我們只需開啟一個執行緒實現更新進度值,為了更好的控制我們再

我的Android進階之旅------>Android定義View實現帶數字的進度條(NumberProgressBar)

今天在Github上面看到一個來自於 daimajia所寫的關於Android自定義View實現帶數字的進度條(NumberProgressBar)的精彩案例,在這裡分享給大家一起來學習學習!同時感謝daimajia的開源奉獻! 第一步、效果展

Android零基礎入門第24節定義View簡單使用

子類 protect jin 討論 我們 @+ amp 進階 運行程序 當我們開發中遇到Android原生的組件無法滿足需求時,這時候就應該自定義View來滿足這些特殊的組件需求。 一、概述 很多初入Android開發的程序員,對於Android自定義View可能比較

Android -- 定義view實現keep歡迎頁倒計時效果

super onfinish -m use new getc awt ttr alt 1,最近打開keep的app的時候,發現它的歡迎頁面的倒計時效果還不錯,所以打算自己來寫寫,然後就有了這篇文章。 2,還是老規矩,先看一下我們今天實現的效果   相較於我們常見的倒計時