高仿QQ下拉刷新之LoadView

Posted FightSeeker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高仿QQ下拉刷新之LoadView相关的知识,希望对你有一定的参考价值。

开始之前,先把效果图贴上,一睹为快,相似度还是蛮高的,嘿嘿!


此加载状态提示,我分为了四个部分来写,分别是:

(1)加载当中,LoadIngView

(2)加载之前,即用户下拉的状态,LoadPreView

(3)加载成功,LoadSuccessView

(4)控件组合,LoadView,也即是我们xml布局用到的

下面一一来介绍一下涉及到的主要核心代码:

1.关于LoadInngView的核心代码,主要思想是,通过改变十二条短线圆柱的颜色,实现加载的循环效果。

首先初始化颜色,代码如下

    private void initColor()
        colorEvaluator = new ArgbEvaluator();
        colors = new int[count];
        for(int i = 0;i < count;i++)
            colors[i] = (int)colorEvaluator.evaluate(i*1.0f/(count-1),startColor,endColor);
        
    
很简单的一段代码,就是根据颜色插值器ArgbEvaluator,两种颜色,生成在startColor与endColor区间内的12中颜色

其次,就是初始化线段,代码如下

    private void initLoadingLines()
        loadingLines = new LoadingLine[count];
        for(int i = 0;i <count;i++)
            LoadingLine loadingLine = new LoadingLine();
            loadingLine.drawColor = colors[i];
            loadingLines[i] = loadingLine;
        
    
这段代码目的就是事先生成count条线段,并暂时初始化颜色。

再其次就是,初始化线段绘制的起始结束坐标,

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) 
        float delayAngle = 360.0f / count;
        LoadingLine loadingLine;
        double value;
        for(int i = 0;i < count;i++)
            loadingLine = loadingLines[i];
            value = startAngle * Math.PI / 180;
            loadingLine.startX = (int)Math.round(radius * Math.cos(value));
            loadingLine.startY = (int)Math.round(radius * Math.sin(value));
            loadingLine.endX = (int)Math.round(exactlySize / 2.5f * Math.cos(value));
            loadingLine.endY = (int)Math.round(exactlySize / 2.5f * Math.sin(value));
            startAngle += delayAngle;
        
        startAngle = 0;
    
这个就考验你的数学功力了,不说

最后,颜色的改变,其实也就是实现循环效果的一部分,

    private Runnable runnable = new Runnable() 
        @Override
        public void run() 
            postInvalidate();
            removeCallbacks(runnable);
            setColor(startIndex % count);
            startIndex++;
            postDelayed(runnable,DELAY_DURATION);
        
    ;

    /**
     * 设置显示颜色
     * @param index,线段颜色初始化位置
     */
    private void setColor(int index)
        int lineIndex;
        for(int i = 0;i < count;i++)
            lineIndex = index + i;
            loadingLines[lineIndex >= count?lineIndex - count:lineIndex].drawColor = colors[i];
        
    
index说明一下,这个是显示颜色数组的第一个颜色,然后依次循环为每一个线段在赋值颜色。

2.LoadPreView:
这个其实没啥好说的,就是一些图形的绘制。难度点在于怎么绘制下拉的状态,正常的图形绘制肯定是不行,所以这里用到了二阶贝塞尔曲线的绘制,绘制Path生成如下:

    /**
     * 重置贝塞尔曲线
     */
    private void resetBeaierPath()
         /* 四个点 */
        final float headerX1 = -mCurrentHeaderRadius;
        final float headerX2 = mCurrentHeaderRadius;
        final float headerY = 0;
        final float footerX1 = -mCurrentFooterRadius;
        final float footerX2 = mCurrentFooterRadius;
        final float footerY = delaY;

         /* 控制点 */
        final float anchorX1 = headerX1 / anchorPercent;
        float anchorY = delaY / anchorPercent;
        anchorY = anchorY > exactlySize / 1.5f?exactlySize / 1.5f:anchorY;
        final float anchorX2 = headerX2 / anchorPercent;

         /* 画贝塞尔曲线 */

        mPath.reset();
        mPath.moveTo(headerX1, headerY);
        mPath.quadTo(anchorX1, anchorY, footerX1, footerY);
        mPath.lineTo(footerX2, footerY);
        mPath.quadTo(anchorX2, anchorY, headerX2, headerY);
        mPath.lineTo(headerX1, headerY);
    
其实就是6个点的确定,(headerX1,headerY), (headerX2,headerY),(footerX1,footerY),(footerX2,footerY),(anchorX1,anchory),(anchorX2,anchorY),前面四个点做为固定点,是贝塞尔曲线闭合的4个点,后面两个是控制点。

另外再说下,这个方法

    private void resetValue(float percent)
        this.anchorPercent = 1.0f + percent;
        this.delaY = maxBezierLength * percent;
        this.mCurrentFooterRadius = (1 - percent >= 0.25f? 1- percent:0.25f) * (exactlySize / 2.0f - ringWidth);
        float p = 1.0f - percent / 3.0f;
        this.arrowRadius = exactlySize / 4.5f * p;
        this.triangleLength = applyDimension(TRIANGLE_LENGTH) * p;
        this.arcWidth = applyDimension(INNER_ARC_WIDTH) * p;
        this.mCurrentHeaderRadius = p * (exactlySize / 2.0f - ringWidth);
    
这是根据下拉的大小来实时更新各个参数的,能实现贝塞尔的下拉效果,这个参数的计算是必须的。

3.LoadSuccessView的绘制,这部分的绘制其实就是一个圆圈加对号以及文字的绘制,其中文字的绘制如下:

    /**
     * 绘制加载成功文字提示
     * @param canvas
     */
    private void drawText(Canvas canvas)
        canvas.save();
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        RectF targetRect = new RectF((padding + radius)*2,0,getWidth(),getHeight());
        int baseLine =  (int)((targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2);
        canvas.translate((padding + radius)*2,baseLine);
        canvas.drawText(TEXT,0,0,textPaint);
        canvas.restore();
    
文字的绘制,其中确定基线是重要的,直接影响到你文字绘制的高度问题,基线的确定如代码所写。

4.LoadView,这部分更没啥,动态添加控件嘛,这个不会就去找度娘或者谷歌吧。具体的实现方式可以看代码,在这俺就不贴咧。




源码下载地址,请指正!





以上是关于高仿QQ下拉刷新之LoadView的主要内容,如果未能解决你的问题,请参考以下文章

Android 修改源码自定义SwipeRefreshLayout样式——高仿微信朋友圈下拉刷新

高仿墨迹天气下拉拉伸图片

iOS仿微信朋友圈下拉刷新

高仿QQ6.0之側滑删除

Android仿苹果版QQ下拉刷新实现 ——打造简单平滑的通用下拉刷新控件

网易新闻client(高仿)