Android的學習與實踐11(波浪線與進度的結合,利用圖片來進行“加載”的實現)

1 收獲

說實話今天沒有多少的新知識點,但是今天做的東西是在昨天做的東西之上又實現了一些功能,昨天最后的波浪時靜態的,而今天我們將昨天做的最后一個靜態的波浪線是實現了動態,就在這里我們又重復用到了昨天學到的知識和以前學過的知識,包括自定義屬性,ObjectAnimator,ValueAnimator,RotateAnimation三種動畫,這又給我們進行復習的機會,說實話我對于這些動畫沒有了多大印象,除了ValueAnimator因為昨天才學的,今天他們又出現在了我的眼前,我一定要好好的把握住他們,不讓他們從我的手指間跑掉。這周又這樣結束了,時間轉瞬即逝,好好珍惜眼下吧!!!

2.技術

(1)ValueAnimator動畫實現波浪線的動畫
(2)利用畫筆繪制體格圓形和文本
(3)利用繼承ViewGroup實現布局和一些動畫的組合
(4)利用ValueAnimator和RotateAnimation實現加載動畫

3.技術實踐及其應用

(1)ValueAnimator動畫實現波浪線的動畫
在利用ValueAnimator動畫實現波浪線的動畫之前為我們必須要做一些準備工作
設置一些私有變量以及寫出它們對應的構造方法,有利于外部對他們進行設置

private ValueAnimator va;//動畫
    private Paint paint;//畫筆
    private Path path;//路徑

    float density=getResources().getDisplayMetrics().density;//密度
    private int wavelength= (int) (100*density);//波長
    private int wavecrest= (int) (100*density);//波峰

    private int speed;//變化動畫的速度

    private int lineColor=Color.BLACK;//線條顏色
    private int linesize=20 ;//線條粗細

構造方法

  //通過set方法來實現外部對屬性值的設置
    public void setWavelength(int wavelength) {
        this.wavelength = wavelength;
    }

    public void setWavecrest(int wavecrest) {
        this.wavecrest = wavecrest;
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
        paint.setColor(lineColor);
    }

    public void setLinesize(int linesize) {
        this.linesize = linesize;
        paint.setStrokeWidth(linesize);
    }

接下來就是在外部的設置(通過自定義屬性)
首先我們先要自定義屬性


image.png

image.png

我們屬性定義完后我們可以在xml中進行設置值

<swu.xcf.waveloading.Waveview
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        app:linecolor="@color/colorPrimaryDark"
        app:linesize="10"
        app:wavelength="50"
        app:wavecrest="50"
        />

當外部傳來值時,內部就要進行對值進行處理

private void initAttr(Context context, AttributeSet attrs){
        //讀取所有自定義屬性的值
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.Waveview);
        //讀取每一個屬性的值
        wavelength=typedArray.getInteger(R.styleable.Waveview_wavelength, (int) (100*density));
        wavecrest=typedArray.getInteger(R.styleable.Waveview_wavecrest,(int) (100*density));
        linesize=typedArray.getInteger(R.styleable.Waveview_linesize,10);
        lineColor=typedArray.getInteger(R.styleable.Waveview_linecolor,Color.BLACK);
    }

接下來就是進行繪制圖形了,首先我們還是要進行對畫筆進行初始化

 private void inite(){
        paint=new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(lineColor);
        paint.setStrokeWidth(linesize);
        paint.setStyle(Paint.Style.STROKE);
    }

由于這個繪制的圖形并不是規則的,所以我們要明確繪制的路徑,我們要對路徑進行初始化

private void initpath() {
        //創造曲線
        path=new Path();
        //計算多少個周期(有幾個完整的波)
        int count=getWidth()/wavelength;
        //移動設置起始點 距離x左邊的一個波長
        path.moveTo(-wavelength+speed,getHeight()/2);
        //獲取中心的坐標
        int ceterY= (int) getPivotY();
        //卻確定曲線的路徑
        for(int start=-wavelength+speed;start<getWidth();start+=wavelength){
            //畫上半周期
            path.cubicTo(start,ceterY,start+wavelength/4,ceterY-wavecrest,start+wavelength/2,ceterY);
            //畫下半周期
            path.cubicTo(start+wavelength/2,ceterY,start+(wavelength/4)*3,ceterY+wavecrest,start+wavelength,ceterY);
        }

    }

現在筆有了,路徑有了,接下來我們就是進行繪制了

@Override
    protected void onDraw(Canvas canvas) {
        //開始繪制
        initpath();
        canvas.drawPath(path,paint);
    }

但是當我們運行后發現這個波浪時靜態的,所以我們想到用一個動畫來實現

//開始動畫
    public void startWave(){
        va=ValueAnimator.ofInt(0,wavelength);
        va.setDuration(400);//動畫間隔時間
        va.setRepeatCount(ValueAnimator.INFINITE);//設置動畫重復的次數
        va.setRepeatMode(ValueAnimator.RESTART);//設置動畫的類型
        va.setInterpolator(new LinearInterpolator());//使動畫勻速
        //設置更新的監聽器
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //獲取當前值
                speed= (int) valueAnimator.getAnimatedValue();
                //刷新
                invalidate();
            }
        });
        va.start();//開始動畫
    }

但是我們又發現當我們我們進度滿后,動畫并沒有結束,所以我們寫了一一個專門用來結束動畫的函數

 //暫停動畫
    public void stopWave(){
        if(va!=null){
            va.cancel();
        }
    

效果:

錄制_2019_10_28_00_00_24_864.gif

(2)利用畫筆繪制體格圓形和文本
在這里并沒有什么新的知識和技術,都是在昨天的講過的,不知道的可以看上一篇推文,那片推文中有詳細的介紹。
首先我們還是要一些我們需要的屬性以及他們的set方法,方便外部對這些屬性進行設置值

Paint circlepaint;//畫圓的畫筆
    Paint textcircle;//繪制文本的畫筆
    private int centerYSpace;//和中心線的距離
    private int linesize=20;//線條粗細
    private int linecolor=Color.BLACK;//線條顏色
    private int textcolor=Color.BLACK;//文本顏色
    private int textsize=50;//文本大小

    private float progress;//進度

set方法

ublic void setLinesize(int linesize) {
        this.linesize = linesize;
        circlepaint.setStrokeWidth(linesize);
    }

    public void setLinecolor(int linecolor) {
        this.linecolor = linecolor;
        circlepaint.setColor(linecolor);
    }

    public void setTextcolor(int textcolor) {
        this.textcolor = textcolor;
        textcircle.setColor(textcolor);
    }

    public void setTextsize(int textsize) {
        this.textsize = textsize;
        textcircle.setTextSize(textsize);
    }

    public void setProgress(float progress) {
        this.progress = progress;
        //刷新
        invalidate();
    }

    public void setCenterYSpace(int centerYSpace) {
        this.centerYSpace = centerYSpace;
    }

然后對兩種畫筆進行初始化

 private void inite() {
        circlepaint=new Paint(Paint.ANTI_ALIAS_FLAG);//創建畫筆
        circlepaint.setStrokeWidth(linesize);//畫筆的粗細
        circlepaint.setColor(linecolor);//畫筆的顏色
        circlepaint.setStyle(Paint.Style.STROKE);//畫筆的風格(空心,實心)

        textcircle=new Paint(Paint.ANTI_ALIAS_FLAG);//創建畫筆
        textcircle.setStyle(Paint.Style.FILL);//畫筆的風格(空心,實心)
        textcircle.setColor(textcolor);//畫筆的顏色
        textcircle.setTextSize(textsize);//畫筆的粗細

    }

在onDraw方法中進行一些位置的設置,然后開始進行繪制

protected void onDraw(Canvas canvas) {
        //確定半徑
        int radius=Math.min(getWidth(),getHeight());
        //畫圓
        canvas.drawCircle(getPivotX(),getPivotX(),radius/2-linesize,circlepaint);
        //畫文本
        String text=(int)(progress*100)+"%";
        //計算文本寬度
        int width= (int) textcircle.measureText(text);
        //獲取文字矩陣fontMetrics
        Paint.FontMetricsInt fm=textcircle.getFontMetricsInt();
        //開始繪制
        canvas.drawText(text,getPivotX()-width/2,getPivotY()+(-fm.ascent)/2+centerYSpace,textcircle);
    }

效果:

image.png

(3)利用繼承ViewGroup實現布局和一些動畫的組合
首先我們要先創建一個類,這個類繼承于ViewGroup
image.png

image.png

創建后我們要實現ViewGroup里面的抽象方法
和自己的構造方法(得到外部給自己的值)

//抽象方法
 @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
   
    }
//構造方法
 public WaveLoadingView(Context context) {
        super(context);
    }

    public WaveLoadingView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
public float getProgress() {
        return progress;
    }

然后我們需要創建兩個視圖類(動畫)的對象和一個進度屬性

 private Waveview wv;
    private float progress;
    private cricleview cv;

我們要實現具體類的,對類的屬性進行設置以及實現具體的布局
所以我們要在 onLayout() 抽象方法中去實現。

@Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        //創建原視圖
        cv=new cricleview(getContext());
        cv.setLinecolor(Color.RED);
        cv.setLinesize(50);
        cv.setTextcolor(Color.RED);
        cv.setTextsize(60);
        cv.setCenterYSpace(-50);
        //對子視圖進行布局
        cv.layout(0,0,getWidth(),getHeight());
        //將子視圖添加到容器中
        addView(cv);

        //創建Waveview
        wv=new Waveview(getContext());
        wv.setLineColor(Color.RED);
        wv.setLinesize(5);
        wv.setWavecrest(30);
        wv.setWavelength(100);
        //布局
        wv.layout(getWidth()/4,getHeight()/2-30,getWidth()*3/4,getHeight()+30);
        //添加視圖
        addView(wv);
    }

效果:


錄制_2019_10_28_13_04_44_375.gif

(4)利用ValueAnimator和RotateAnimation實現加載動畫
首先我們需要兩張圖片,我們將看兩張圖片引到在

image.png

然后我們對兩張圖片添加到容器中去

private void inite() {
        ImageView inner=new ImageView(getContext());
        inner.setImageResource(R.drawable.m);
        addView(inner);

        outer=new ImageView(getContext());
        outer.setImageResource(R.drawable.y);
        addView(outer);
    }

然后我們對里面的圖片進行設置動畫(兩種方式ValueAnimator和RotateAnimation)

 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        /*
        RotateAnimation ra=new RotateAnimation(0,720,outer.getPivotX(),outer.getPivotY());
        ra.setDuration(300);
        ra.setRepeatCount(Animation.INFINITE);
        ra.setRepeatMode(Animation.RESTART);
        ra.setInterpolator(new LinearInterpolator());
        outer.startAnimation(ra);
        */
        ObjectAnimator oa=ObjectAnimator.ofFloat(outer,"rotation",0,360);
        oa.setDuration(1000);
        oa.setRepeatMode(ObjectAnimator.RESTART);
        oa.setRepeatCount(ObjectAnimator.INFINITE);
        oa.setInterpolator(new LinearInterpolator());
        oa.start();
    }

效果:


錄制_2019_10_28_00_40_45_649.gif
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容