學習水波進度條--自定義view(一)

其實吧這個東西我一直很想學習的,但是一直不知道,怎么開始跑代碼。
正好看到一篇很厲害的代碼原始帖子,沒有對比沒有傷害。。來讓我互相傷害吧。

完整代碼下載

先來一貼 貝塞爾曲線開發的藝術,作者是大神不介紹,這篇文章,寫的很好理解,貝塞爾曲線,我就不嘮叨了。

如果你已經看完,這個帖子那么我感覺,你絕對值得,曲線是什么了。但是代碼中用到了一個

 android path rQuadTo() 這個方法,

我簡答解釋一下:
rQuadTo(float dx1, float dy1, float dx2, float dy2)
利用quadTo定義絕對坐標
quadTo 舉例

path.moveTo(300,400);  
path.quadTo(500,300,500,500);  

等同rQuadTo

path.moveTo(300,400);  
path.rQuadTo(200,-100,200,100)  

quadto 控制點是,500,300
rquadto 控制點是,300+200,400-100
這個例子是不是可以看懂了。這個才是關鍵。

我們開始擼代碼吧。
紅標文件講解 這里埋了雷,其實是脫離窗口。


AndroidManifest.xml

main

activity_main.xml

主類中并沒有什么特別是吧,一個intent 其實是一個sever,,我們放在后面說,我們先看,這個自定義view


MainActivity.java

一般自定義view基本遵循以下這四個方法。默默記住就好了。基本是固定的【嘿哈】。一個讀代碼的方法,先debug這重點代碼,然后運行看運行邏輯。

view 自定義基本框架
1、自定義View的屬性
2、在View的構造方法中獲得我們自定義的屬性
3、重寫onMesure
4、重寫onDraw

一個手機識別類,代碼很簡單,當前類,定義一個雙擊和單擊事件。


手勢識別類

構造方法,把上面的手勢識別,添加到,自己的view中。

public WaterProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        this.mContext = context;

        getAttrValue(attrs);

        //初始化畫筆的相關屬性
        initPaint();
        mProgressPath = new Path();

        mGestureDetector = new GestureDetector(context,new MyGestureDetector());
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                //將觸摸事件交由mGestureDetector處理
                mGestureDetector.onTouchEvent(motionEvent);

                return true;
            }
        });

    }

其實這個雙擊動畫,就是Handler 在玩,并沒有什么特別的,關鍵點是,setprogress(0) 先清空進度,看到了吧,這就是,if為什么這樣判斷了。然后每次都重新繪制,動畫就開始了。


雙擊動畫

每個自定義的view基本都會,用onDraw ,其實我感覺如果你不用onDraw其實完全可以通過基本組件組合出來。

 @Override
    protected synchronized void onDraw(Canvas canvas) {
        float ratio = getProgress()*1.0f/getMax();
        //去邊界的寬高
        int width = getWidth()-getPaddingLeft()-getPaddingRight();
        int height = getHeight()-getPaddingTop()-getPaddingBottom();

        //畫圓 
        mPaintCanvas.drawCircle(width/2,height/2,height/2,mCirclePaint);

        //畫進度
        mProgressPath.reset();
        //從右上邊開始draw path
        int rightTop = (int) ((1-ratio)*height);
        mProgressPath.moveTo(width,rightTop);
        mProgressPath.lineTo(width,height);
        mProgressPath.lineTo(0,height);
        mProgressPath.lineTo(0,rightTop);
        //畫貝塞爾曲線,形成波浪線 這里的波浪個數 其實這里為什么用高呢,,
        //其實我想說,用寬也行,因為是個圓形,,哈哈,是不是,很逗比,
        int count = (int) Math.ceil(height*1.0f/(mRippleTop *4));
        //不是單擊animation狀態
        if(!isSingleTapAnimation&&getProgress()>0) {
            float top = (mTargetProgress-getProgress())*1.0f/mTargetProgress* mRippleTop;
            for(int i=0; i<count; i++) {
                mProgressPath.rQuadTo(mRippleTop,-top,2* mRippleTop,0);
                mProgressPath.rQuadTo(mRippleTop,top,2* mRippleTop,0);
            }
        } else {
            //單擊animation狀態
//mSingleTapAnimationCount 單機動畫的次數,默認是50 這里其實就是想讓動畫每次的固定搞度提升。
            float top = (mSingleTapAnimationCount*1.0f/50)*10;
            //奇偶數時曲線切換
            if(mSingleTapAnimationCount%2==0) {
                for(int i=0; i<count; i++) {
                    mProgressPath.rQuadTo(mRippleTop *2,-top*2,2* mRippleTop,0);
                    mProgressPath.rQuadTo(mRippleTop *2,top*2,2* mRippleTop,0);
                }
            } else {
                for(int i=0; i<count; i++) {
                    mProgressPath.rQuadTo(mRippleTop *2,top*2,2* mRippleTop,0);
                    mProgressPath.rQuadTo(mRippleTop *2,-top*2,2* mRippleTop,0);
                }
            }

        }
        mProgressPath.close();
        mPaintCanvas.drawPath(mProgressPath,mProgressPaint);

        //畫進度文字
        String text = ((int)(ratio*100))+"%";
        //獲得文字的寬度
        float textWidth = mTextPaint.measureText(text);
        Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
        //descent+ascent為負數,所以是減而不是加
        float baseLine = height*1.0f/2 - (metrics.descent+metrics.ascent)/2;
        mPaintCanvas.drawText(text,width/2-textWidth/2,baseLine,mTextPaint);

        canvas.drawBitmap(mBitmap,0,0,null);
    }

還有一個重點代碼,SRC_IN 給你一個連接隨便一個連接,你就可以知道他是什么了,簡答到,你喊媽媽我餓了一樣。

    private void initPaint() {
        mCirclePaint = new Paint();
        mCirclePaint.setColor(mCircleColor);
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setDither(true);

        mProgressPaint = new Paint();
        mProgressPaint.setColor(mProgressColor);
        mProgressPaint.setAntiAlias(true);
        mProgressPaint.setDither(true);
        mProgressPaint.setStyle(Paint.Style.FILL);
//setXfermode模式 SRC_IN 
        mProgressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        mTextPaint = new Paint();
        mTextPaint.setColor(mTextColor);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setDither(true);
        mTextPaint.setTextSize(mTextSize);
    }

重點代碼結束,自定義這個波浪并沒有什么特別的,重點就是,貝塞爾曲線,其他的,都不難偶。~~

下一帖預告,看看 intent中,類做什么的。

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

推薦閱讀更多精彩內容

  • 帖子太長,我換一個新帖子,以為,兩個代碼并沒有什么重疊的東西,可以分來來講,先看之前的intent吧,僅僅是一個,...
    姬94閱讀 243評論 0 0
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,536評論 25 708
  • 系列文章之 Android中自定義View(一)系列文章之 Android中自定義View(二)系列文章之 And...
    YoungerDev閱讀 4,474評論 3 11
  • 每次聽到某大牛談論自定義View,頓時敬佩之心,如滔滔江水連綿不絕,心想我什么時候能有如此境界,好了,心動不如行動...
    Code4Android閱讀 2,183評論 6 25
  • 許久無雨。冬天的第一場雨,帶著颼颼的冷意。這樣的雨天,不能跑步,也沒有在樓下跳繩。就像期待里的約會落空一樣的失落。...
    雨中葳蕤閱讀 438評論 1 6