zoukankan      html  css  js  c++  java
  • 仿易讯clientloading效果

    以下来实现一个loading效果。详细效果例如以下:
    这里写图片描写叙述
    首先对这个效果进行拆分,它由以下部分组成:

    • 1 一个”闪电”样式的图案。
    • 2 “闪电”图案背后是一个圆角矩形;
    • 3 “闪电”图案上面有一层颜色不断”飘过”

    拆分完效果后。思考下如何实现。以下是我的思考过程。

    • 1 android sdk并没有提供这种控件,非常显然是须要自己定义控件。
    • 2 非常显然是一个View而不是ViewGroup。所以能够继承View;
    • 3 重点是onDraw的逻辑;
    • 4 如何绘制”闪电”的图案?能够通过Path绘制;
    • 5 如何绘制”闪电”背后的圆角矩形?canvas.drawRoundRect;
    • 6 如何实现”闪电”的动效?细致观察,发现上方那层颜色的运动规律是从0~闪电高度不断扩大。到达闪电高度的时候,高度不断减小直到0。所以能够通过控制高度的方式实现。

      仅仅要有两个变量scanTop/scanBottom记录绘制的上下界限就可以。然后控制scanTop/scanBottom进行变化就可以。如何控制变化非常显然能够通过post/postDelayed实现。

      另外一个难点是如何绘制部分”闪电”?思索一番,能够通过canvas.clipRect的方式控制绘制区域。这样间接实现了我们须要的效果;

    • 7 核心逻辑实现之后,须要考虑到应该让这个自己定义控件支持wrap_content.这必定须要重写onMeasure,并考虑到父容器的MeasureSpec(view的默认实现下wrap_content和match_parent效果一样)。
    • 8 须要让这个控件支持padding。所以得在measure和draw的过程中充分考虑到padding这个因素;
    • 9 当view被detach的时候,须要remove掉动画。
    • 10 应该提供几个默认大小,比方small/midium/large,这能够通过自己定义属性实现。

    大致思考完之后。能够写代码了。

    首先是measure过程:

    @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            //须要计算自己实际须要的宽高
            //须要把padding考虑进来
            //须要考虑父容器的測量规则
    
            int width,height;
    
            width = (int)mViewMinWidth+getPaddingLeft()+getPaddingRight();
            height = (int)mViewMinHeight+getPaddingTop()+getPaddingBottom();
    
            setMeasuredDimension(getMeasuredSize(widthMeasureSpec, width), getMeasuredSize(heightMeasureSpec, height));
        }

    通过getMeasuredSize计算考虑父容器限制后的实际大小:

    private int getMeasuredSize(int measureSpec,int desiredSize){
    
            int result;
    
            int mode = MeasureSpec.getMode(measureSpec);
            int size = MeasureSpec.getSize(measureSpec);
    
            switch (mode){
                case MeasureSpec.EXACTLY:
                    result = size;
                    break;
                default:
                    result = desiredSize;
                    if(mode == MeasureSpec.AT_MOST)
                        result = Math.min(result,size);
                    break;
            }
    
            return result;
    
        }

    然后是draw的过程:

    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            mPaint.setColor(mViewBackground);
            //假设xml中设置layout_width/layout_height大于默认宽高。那么居中(不同意小于默认宽高)
            if(getWidth()-getPaddingLeft()-getPaddingRight() > (int)mViewMinWidth || getHeight()-getPaddingTop()-getPaddingBottom() > (int)mViewMinHeight){
               canvas.translate((getWidth()-mViewMinWidth)/2.0f,(getHeight()-mViewMinHeight)/2.0f);
            }
            //画圆角矩形
            canvas.drawRoundRect(mBounds, dp2px(5), dp2px(5), mPaint);
            //平移到圆角矩形中心点,画闪电
            canvas.translate((mViewMinWidth - mDefaultWidth) / 2.0f, (mViewMinHeight - mDefaultHeight) / 2.0f);
            mPaint.setColor(mBackgroundColor);
    
            canvas.drawPath(mThunderPath, mPaint);
            mPaint.setColor(mCoverColor);
            //通过clicpRect的方式控制可绘制区域(在外界看来好像有闪动的动画效果)
            canvas.clipRect(getPaddingLeft(), mScanTop + getPaddingTop(), mDefaultWidth + getPaddingLeft(), mScanBottom + getPaddingTop());
            canvas.drawPath(mThunderPath, mPaint);
        }

    mScanTop/mScanBottom变量能够通过post()进行改变:

    class AnimRunnable implements Runnable{
            @Override
            public void run() {
                if (!flag) {
                    mScanBottom += mGap;
                    if (mScanBottom >= mDefaultHeight) {
                        mScanBottom = (int) mDefaultHeight;
                        flag = true;
                    }
                    postInvalidate();
                    post(this);
                } else {
                    mScanTop += mGap;
                    if (mScanTop >= mDefaultHeight) {
                        mScanTop = mScanBottom = 0;
                        flag = false;
                        postInvalidate();
                        postDelayed(this, 700);
                    } else {
                        postInvalidate();
                        post(this);
                    }
                }
            }
        }
    private void startAnim() {
            mRunnable = new AnimRunnable();
            post(mRunnable);
        }

    核心代码就这么多。


    完整代码在这里:https://github.com/Rowandjj/ThunderLoadingView

  • 相关阅读:
    多线程 C#解决方案小结
    程序员的灯下黑:Handson,Handson,Handson!
    有一家银行每天早上都在你的帐户里存入86,400
    3D流水线[引用]
    诸葛亮著作
    Vista 用户头像存储路径
    C# 关闭显示器的函数
    程序员的灯下黑:管理还是技术?兴趣优先
    VS1.4挤房+MH的登陆器
    失眠的调养
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7239057.html
Copyright © 2011-2022 走看看