SwipeRefreshLayout完美添加及完善上拉加载功能

本文介绍了如何在Android中使用SwipeRefreshLayout实现下拉刷新和上拉加载功能,详细讲解了原始代码的工作原理,并针对动画效果的异常问题进行了分析和改进。通过设置,可以自由开启或关闭下拉刷新和上拉加载,并自定义进度条颜色。
摘要由CSDN通过智能技术生成

转载请注明出处http://blog.csdn.net/u012036813/article/details/38959507,谢谢!


项目地址:https://git.oschina.net/whos/SwipeRefreshAndLoadLayout/wikis/home


关于Google推出的下拉刷新控件SwipeRefreshLayout的相关使用方法,大家可以去参考http://blog.csdn.net/geeklei/article/details/38876981,本文也借鉴了其中的一些内容和“颜路的博客”中《官方下拉刷新SwipeRefreshLayout增加上拉加载更多》一文。


话不多说,直接先上改造效果图(截屏时卡,凑合看吧):

下拉刷新和上拉加载

     

简单讲下原始代码的原理:

下拉时,计算手指移动距离,如果超过一个系统默认的临界值mTouchSlop,该事件就不下发到子控件进行处理,而是SwipeRefreshLayout自己处理。

变量mDistanceToTriggerSync指定了下拉刷新的临界值,如果下拉距离没有大于该值,则计算下拉距离和mDistanceToTriggerSync的比值,并用该值作为进度百分比对进度条mProgressBar进行设置,同时移动子控件(ListView之类)的位置,屏幕上可以看到进度条颜色缓慢拉长的动画,同时子控件向下移动。

如果下拉距离大于mDistanceToTriggerSync,则设置动画把子控件位置复位,然后启动下拉刷新的色条循环动画,并执行下拉刷新的监听事件。


关于进度条SwipeProgressBar的动画显示,Google的代码里埋藏了一个坑人的陷阱。现象就是如果你在底部加了进度条,动画效果异常,不会出现渐变的色条,只是生硬的转换。上面参考的文章里也碰到了这个问题。其实原因很简单,看下图:

把进度条SwipeProgressBar的高度设置大了后,可以看出其动画效果是在进度条的中心向外部循环画圆,每个循环中圆的颜色不同。重点是圆心的位置。

看SwipeProgressBar的如下代码,会发现在计算圆心高度cy的时候,取值是进度条高度的一半,这样的话圆心会一直在上面,底部进度条自然动画异常

    void draw(Canvas canvas) {
        final int width = mBounds.width();
        final int height = mBounds.height();
        final int cx = width / 2;
        final int cy = height / 2;
        boolean drawTriggerWhileFinishing = false;
        int restoreCount = canvas.save();
        canvas.clipRect(mBounds);

修改SwipeProgressBar的代码,使其圆心在所在进度条的中心:

    void draw(Canvas canvas) {
        final int width = mBounds.width();
        final int height = mBounds.height();
        final int cx = width / 2;
//        final int cy = height / 2;
        final int cy = mBounds.bottom - height / 2;
        boolean drawTriggerWhileFinishing = false;
        int restoreCount = canvas.save();
        canvas.clipRect(mBounds);

效果如图:



明白了原始代码的原理,就好入手进行修改了,修改的代码会在后面贴出来,注释很详细,这里就不具体分析了。对SDK<14的滑动部分暂时没有进行处理,直接返回了false,待后续改进。已改进


下面看修改后的功能:

1.可设置是否打开下拉刷新功能,可设置是否打开上拉加载功能,默认全部打开。

2.可设置是否在数据不满一屏的情况下打开上拉加载功能,默认关闭。

3.可单独设置上下进度条的颜色,也可同时设置一样的颜色。


啰嗦了这么多,上代码:

SwipeProgressBar:

package com.dahuo.learn.swiperefreshandload.view;

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;


/**
 * Custom progress bar that shows a cycle of colors as widening circles that
 * overdraw each other. When finished, the bar is cleared from the inside out as
 * the main cycle continues. Before running, this can also indicate how close
 * the user is to triggering something (e.g. how far they need to pull down to
 * trigger a refresh).
 */
final class SwipeProgressBar {

    // Default progress animation colors are grays.
    private final static int COLOR1 = 0xB3000000;
    private final static int COLOR2 = 0x80000000;
    private final static int COLOR3 = 0x4d000000;
    private final static int COLOR4 = 0x1a000000;

    // The duration of the animation cycle.
    private static final int ANIMATION_DURATION_MS = 2000;

    // The duration of the animation to clear the bar.
    private static final int FINISH_ANIMATION_DURATION_MS = 1000;

    // Interpolator for varying the speed of the animation.
    private static final Interpolator INTERPOLATOR = BakedBezierInterpolator.getInstance();

    private final Paint mPaint = new Paint();
    private final RectF mClipRect = new RectF();
    private float mTriggerPercentage;
    private long mStartTime;
    private long mFinishTime;
    private boolean mRunning;

    // Colors used when rendering the animation,
    private int mColor1;
    private int mColor2;
    private int mColor3;
    private int mColor4;
    private View mParent;

    private Rect mBounds = new Rect();

    public SwipeProgressBar(View parent) {
        mParent = parent;
        mColor1 = COLOR1;
        mColor2 = COLOR2;
        mColor3 = COLOR3;
        mColor4 = COLOR4;
    }

    /**
     * Set the four colors used in the progress animation. The first color will
     * also be the color of the bar that grows in response to a user swipe
     * gesture.
     *
     * @param color1 Integer representation of a color.
     * @param color2 Integer representation of a color.
     * @param color3 Integer representation of a color.
     * @param color4 Integer representation of a color.
     */
    void setColorScheme(int color1, int color2, int color3, int color4) {
        mColor1 = color1;
        mColor2 = color2;
        mColor3 = color3;
        mColor4 = color4;
    }

    /**
     * Update the progress the user has made toward triggering the swipe
     * gesture. and use this value to update the percentage of the trigger that
     * is shown.
     */
    void setTriggerPercentage(float triggerPercentage) {
        mTriggerPercentage = triggerPercentage;
        mStartTime = 0;
        ViewCompat.postInvalidateOnAnimation(mParent);
    }

    /**
     * Start showing the progress animation.
     */
    void start() {
        if (!mRunning) {
            mTriggerPercentage = 0;
            mStartTime = AnimationUtils.currentAnimationTimeMillis();
            mRunning = true;
            mParent.postInvalidate();
        }
    }

    /**
     * Stop showing the progress animation.
     */
    void stop() {
        if (mRunning) {
            mTriggerPercentage = 0;
            mFinishTime = AnimationUtils.currentAnimationTimeMillis();
            mRunning = false;
            mParent.postInvalidate();
        }
    }

    /**
     * @return Return whether the progress animation is currently running.
     */
    boolean isRunning() {
        return mRunning || mFinishTime > 0;
    }

    void draw(Canvas canvas) {
        final int width = mBounds.width();
        final int height = mBounds.height();
        final int cx = width / 2;
//        final int cy = height / 2;
        final int cy = mBounds.bottom - height / 2;
        boolean drawTriggerWhileFinishing = false;
        int restoreCount = canvas.save();
        canvas.clipRect(mBounds);

        if (mRunning || (mFinishTime > 0)) {
            long now = AnimationUtils.currentAnimationTimeMillis();
            long elapsed = (now - mStartTime) % ANIMATION_DURATION_MS;
            long iterations = (now - mStartTime) / ANIMATION_DURATION_MS;
            float rawProgress = (elapsed / (ANIMATION_DURATION_MS / 100f));

            // If we're not running anymore, that means we're running through
            // the finish animation.
            if (!mRunning) {
                // If the finish animation is done, don't draw anything, and
                // don't repost.
                if ((now - mFinishTime) >= FINISH_ANIMATION_DURATION_MS) {
                    mFinishTime = 0;
                    return;
                }

                // Otherwise, use a 0 opacity alpha layer to clear the animation
                // from the inside out. This layer will prevent 
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值