Androidドロップダウンで素晴らしいアニメーションをリフレッシュ

14307 ワード

以前は、従来のドロップダウン効果とは異なり、ほとんどのドロップダウンリフレッシュは円形の進捗バーが回転していますが、このドロップダウンリフレッシュは絶えず充填されている効果です.これはカスタムViewだと思っていたが、その後、慕課網のappを逆コンパイルしてリソースを抽出したときに多くの画像を見た.それはおそらく慕課網app内部の実現はフレームアニメーションがこのような効果を達成したはずだ.この効果を見たとき、この間カスタムコントロールを習っていたので、本能的な反応はカスタムでした.まず、慕課網の効果を見てみましょう.以下の図
package cn.edu.zafu.view;  

import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.Bitmap.Config;  
import android.graphics.BitmapFactory;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Path;  
import android.graphics.PorterDuff;  
import android.graphics.PorterDuffXfermode;  
import android.util.AttributeSet;  
import android.view.View;  

/** * @author lizhangqu * * 2015-3-5 */  
public class CustomView extends View {  
    private PorterDuffXfermode porterDuffXfermode;// Xfermode 
    private Paint paint;//    
    private Bitmap bitmap;//     
    private int width, height;//      
    private Path path;//            
    private Canvas mCanvas;//             
    private Bitmap bg;//      

    private float controlX, controlY;//         ,           ,       ,                
    private float waveY;//       

    private boolean isIncrease;//             

    private boolean isReflesh = true;//            ,   true 

    /** * @return      */  
    public boolean isReflesh() {  
        return isReflesh;  
    }  

    /** *          * * @param isReflesh */  
    public void setReflesh(boolean isReflesh) {  
        this.isReflesh = isReflesh;  
        //   
        postInvalidate();  
    }  

    /** * @param context */  
    public CustomView(Context context) {  
        this(context, null);  
    }  

    /** * @param context * @param attrs */  
    public CustomView(Context context, AttributeSet attrs) {  
        this(context, attrs, 0);  
    }  

    /** * @param context * @param attrs * @param defStyle */  
    public CustomView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        init();  
    }  

    /** *       */  
    private void init() {  
        //       
        paint = new Paint();  
        paint.setAntiAlias(true);  
        paint.setDither(true);  
        paint.setStyle(Paint.Style.FILL);  
        paint.setColor(Color.parseColor("#ffc9394a"));  
        //        
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mooc);  
        //            
        width = bitmap.getWidth();  
        height = bitmap.getHeight();  

        //       
        waveY = 7 / 8F * height;  
        controlY = 17 / 16F * height;  

        //    Xfermode 
        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);  
        //    path 
        path = new Path();  
        //       
        mCanvas = new Canvas();  
        //   bitmap 
        bg = Bitmap.createBitmap(width, height, Config.ARGB_8888);  
        //     bitmap     
        mCanvas.setBitmap(bg);  

    }  

    @Override  
    protected void onDraw(Canvas canvas) {  
        //     ,  bg  
        drawTargetBitmap();  
        //             ,      ,       
        canvas.drawBitmap(bg, getPaddingLeft(), getPaddingTop(), null);  
        if (isReflesh) {  
            //   ,  boolean  isReflesh    ,          ,   true    
            invalidate();  
        }  
    }  

    private void drawTargetBitmap() {  
        //   path 
        path.reset();  
        //      
        bg.eraseColor(Color.parseColor("#00ffffff"));  

        //      x         x         
        if (controlX >= width + 1 / 2 * width) {  
            isIncrease = false;  
        }  
        //      x         x         
        else if (controlX <= -1 / 2 * width) {  
            isIncrease = true;  
        }  

        //              x         
        controlX = isIncrease ? controlX + 10 : controlX - 10;  
        if (controlY >= 0) {  
            //      
            controlY -= 1;  
            waveY -= 1;  
        } else {  
            //         
            waveY = 7 / 8F * height;  
            controlY = 17 / 16F * height;  
        }  

        //          
        path.moveTo(0, waveY);  
        //        controlX,controlY   
        path.cubicTo(controlX / 2, waveY - (controlY - waveY),  
                (controlX + width) / 2, controlY, width, waveY);  
        //         
        path.lineTo(width, height);  
        path.lineTo(0, height);  
        //      
        path.close();  

        //                   
        // http://blog.csdn.net/aigestudio/article/details/41960507 

        mCanvas.drawBitmap(bitmap, 0, 0, paint);//     logo 
        paint.setXfermode(porterDuffXfermode);//   Xfermode 
        mCanvas.drawPath(path, paint);//          
        paint.setXfermode(null);//   Xfermode 
    }  

    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        //             
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
        //        
        int width, height;  

        if (widthMode == MeasureSpec.EXACTLY) {  
            //    
            width = widthSize;  
        } else {  
            //          
            width = this.width + getPaddingLeft() + getPaddingRight();  
            ;  
            if (widthMode == MeasureSpec.AT_MOST) {  
                //       
                width = Math.min(width, widthSize);  
            }  

        }  

        if (heightMode == MeasureSpec.EXACTLY) {  
            //    
            height = heightSize;  
        } else {  
            //          
            height = this.height + getPaddingTop() + getPaddingBottom();  
            ;  
            if (heightMode == MeasureSpec.AT_MOST) {  
                //       
                height = Math.min(height, heightSize);  
            }  

        }  
        //        logo     ,         MeasureSpec   ,         ,            
        setMeasuredDimension(width, height);  

    }  

}  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/ll"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  
    <cn.edu.zafu.view.CustomView   
        android:id="@+id/cv"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:padding="20dp"  
        android:layout_centerInParent="true"  
        android:background="#0000ff"  
        />  
</RelativeLayout>  

塗りつぶしの効果を停止するには、関数setRefreshでisRefresh変数をfalseに設定します.全体の実現過程はまだ比較的簡単で、基本的に注釈はすべてはっきり言って、ここでももう繰り返しません.文章の中で関連する2つの知識点(図形の混合モードとベッセル曲線)の関連内容は次の2つの文章の図形の混合モードを参考にします.http://blog.csdn.net/aigestudio/article/details/41316141ベッセル曲線http://blog.csdn.net/aigestudio/article/details/41960507いずれも愛兄の文章で、個人的には細かく書かれていると思います.