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

  • 相关阅读:
    Best Time to Buy and Sell Stock III
    Valid Palindrome
    Longest Substring Without Repeating Characters
    Copy List with Random Pointer
    Add Two Numbers
    Recover Binary Search Tree
    Anagrams
    ZigZag Conversion
    Merge k Sorted Lists
    Distinct Subsequences
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7239057.html
Copyright © 2011-2022 走看看