1. 程式人生 > >開發懸浮球SDK之自定義view(流量球)上篇 — 水波紋(波浪線)

開發懸浮球SDK之自定義view(流量球)上篇 — 水波紋(波浪線)

本人開發懸浮球SDK大致流程及過程中遇到的問題和解決方法我會寫到我的部落格中。

(關於Paint 類,Path類,Canvas類相關具體詳解,請您拉到本部落格下方,點選連結方便您學習哦!)

自定義view的核心方法 onMeasure(int widthMeasureSpec,int heightMeasureSpec),onLayout(boolean changed,int left,int top,int right,int bottom),onDraw(Canvas  canvas)。

invalidate()   是進行重繪 ,每次執行時會呼叫onDraw()方法。

初始時流量球介面的實現效果上面要求我流量球有水波紋效果,之後改成圓形圖片背景(地址:裁剪圖片過程),文字嵌入其中。這些之中所面對的問題就是:水波紋效果實現,圓形圖片剪下。


水波紋效果:其中核心就是 sin、cos 函式,通過此函式可以通過Paht類 畫出水波紋的流動效果,如果你對三角函式不太瞭解,可以學習一下。(在網上沒找到較好的三角函式介紹的網址,您只能自己查一下書籍了)

     簡單版程式碼如下:   這是簡單的波紋線的繪製。用來跟朋友們解釋水波紋的核心原理。

     y = Asin(Wx + b)+h ;以左上角為中心x表示其水平位置,y表示在x處當前點的豎直方向位置。W決定震動週期,W 越大波浪週期越短(反比)。

A是震動幅度決定Y值大小(正比), b是初相,決定初始時x軸上平移位置,h決定y的位置y軸 ,本例使用正弦函式;


public class View2 extends View {
    Context context ;
    Paint linePaint1;
    Paint linePaint2;
    Canvas canvas1;
    Path path1;
    Path path2;

    int width = 100;
    int height = 100;
    public View2(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public View2(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public View2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }


    private void init() {
        linePaint1 = new Paint();//Paint 類的詳解,請您拉到本部落格下方
        linePaint1.setColor(Color.RED);
        linePaint1.setAntiAlias(true);//設定抗鋸齒,線條更平滑
        linePaint1.setStyle(Paint.Style.STROKE);//paint.Style.stroke 設定畫筆樣式為空心。例如:畫的圓是空心的
        linePaint1.setStrokeWidth(3);// 線寬
        linePaint2 = new Paint();
        linePaint2.setColor(Color.BLUE);
        linePaint2.setAntiAlias(true);
        linePaint2.setStyle(Paint.Style.STROKE);
        linePaint2.setStrokeWidth(3);
        path1= new Path();//Path 類的詳解,請您拉到本部落格下方
        path2= new Path();
        canvas1 = new Canvas();// canvas 類的詳解,請您拉到本部落格下方
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec,heightMeasureSpec);
    }
    int w ;
    int h  = height / 2;
    double W = 15;
    int A = 8;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫出波浪條紋  sin、cos
        // Math.sin();
        canvas1 = canvas;
        canvas1.drawCircle(width/2,height/2,width/2,linePaint1);
        postDelayed(new LineRunnable(),50);

    }


    private class  LineRunnable implements Runnable {

        @Override
        public void run() {
            path1.reset();
            path2.reset();
            path1.moveTo(0,h);
            path2.moveTo(0,h);
            w+=5;
            if(w> (width-5)*2){
                w = 0;
            }
            for(int i = 5;i<width;i++){
//            y = Asin(Wx + b)+h
                path1.lineTo(i, h + (float) (A*Math.sin(Math.PI*(i+w) / width)));// 這裡我們要想弧線儘量平滑那麼就將週期儘量變長,所以W的值儘可能小,
                path2.lineTo(i,h - (float) (A*Math.sin(Math.PI*(i+w) / width)));
            }
            //path1.close();
            canvas1.drawPath(path1, linePaint1);
            canvas1.drawPath(path2, linePaint2);
            invalidate();
        }
    }
}

下面是完整版的波浪水紋():


此水波紋效果顏色我設定為RED和BLUE,高度設定為height的一半,linePaint1和linePaint2 的樣式屬性設定為預設,只將邊框circlePaint設定為Paint.Style.STROKE,線寬為3所以 對比簡單水波紋,我們需要將i 的初始值設定為線寬3(i是path的第一個引數就是橫座標),您如果想要波浪能跟隨高度而變化,那麼不僅僅要調節波浪本身高度 h 的引數,還要同步調節波浪線的初始和結束的位置。由於公司改變了SDK的樣式要求,波浪線的繪製就到這裡,不過今後隨著我學習深入會補充隨高度變化的水波紋效果以及更絢麗的效果。

public class View1 extends View {
    Context context ;
    Paint linePaint1;
    Paint linePaint2;
    Paint circlePaint;
    Canvas canvas1;
    Path path1;
    Path path2;
    RectF rectF;

    int width = 100;
    int height = 100;
    public View1(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public View1(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public View1(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }


    private void init() {
        linePaint1 = new Paint();//Paint 類的詳解,請您拉到本部落格下方
        linePaint1.setColor(Color.RED);
        linePaint1.setAntiAlias(true);//設定抗鋸齒,線條更平滑
//        linePaint1.setStyle(Paint.Style.STROKE);//paint.Style.stroke 設定畫筆樣式為空心。例如:畫的圓是空心的
//        linePaint1.setStrokeWidth(3);// 線寬
        linePaint2 = new Paint();
        linePaint2.setColor(Color.BLUE);
        linePaint2.setAntiAlias(true);
//        linePaint2.setStyle(Paint.Style.STROKE);
//        linePaint2.setStrokeWidth(3);

        circlePaint = new Paint();
        circlePaint.setColor(Color.BLACK);// 設定黑色邊框,是為了您觀察更清楚
        circlePaint.setAntiAlias(true);//設定抗鋸齒,線條更平滑
        circlePaint.setStyle(Paint.Style.STROKE);//paint.Style.stroke 設定畫筆樣式為空心。例如:畫的圓是空心的
        circlePaint.setStrokeWidth(3);// 線寬

        rectF = new RectF(3,3,width+3,height+3);//這裡設定矩形,是用來畫圓的,讓介面出現一個實心的半圓效果,結合弧線會展示出實心波浪的效果

        path1= new Path();//Path 類的詳解,請您拉到本部落格下方
        path2= new Path();
        canvas1 = new Canvas();// canvas 類的詳解,請您拉到本部落格下方
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec,heightMeasureSpec);
    }
    int w ;
    int h  = height / 2;
    double W = 15;
    int A = 8;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫出波浪條紋  sin、cos
        // Math.sin();
        canvas1 = canvas;
        canvas1.drawCircle(width/2+3,height/2+3,width/2,circlePaint);
        postDelayed(new LineRunnable(),50);

    }


    private class  LineRunnable implements Runnable {

        @Override
        public void run() {
            path1.reset();
            path2.reset();

            path1.addArc(rectF,0,180);// 引數1 是矩形變數,2 是初始弧度,3 是結束弧度 (我只是簡單介紹,具體的有關弧度及path類詳解請您拉到本部落格下方)
            path2.addArc(rectF,0,180);

            w+=3;//w 值設定為外圓線寬 3
            if(w> (width-3)*2){
                w = 0;
            }
            for(int i = 3;i<width+3;i++){// 水波紋最後一個位置是(width + 線寬)
//            y = Asin(Wx + b)+h
                path1.lineTo(i, h + (float) (A*Math.sin(Math.PI*(i+w) / width)));
                path2.lineTo(i,h - (float) (A*Math.sin(Math.PI*(i+w) / width)));
            }
            path1.close();//閉合路徑,使得顏色完全填充。
            path2.close();

            canvas1.drawPath(path1, linePaint1);
            canvas1.drawPath(path2, linePaint2);
            invalidate();
        }
    }
}

這只是水波紋繪製的其中一種方法,還有一個更好理解的是通過賽貝爾曲線:核心方法是path.quadTo(); 四個引數前倆是途經的點座標,後倆是終點的座標。通過設定多個點,可以展現出波浪線的效果。


以下是從網上找的介紹Paint 類、Path類、Canvas類的好的網站(方便您學習哦!):

Paint : http://blog.csdn.net/abcdef314159/article/details/51720686

Path : http://blog.csdn.net/u012702547/article/details/52454406 , http://www.jianshu.com/p/f1e4fc2feb25 , path.ArcTo()弧度解釋

Canvas : http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html