猫眼电影下拉刷新效果实现

无入侵的猫眼下拉刷新,无需重写RecyclerView,像SwipeRefreshLayout一样使用简单

最近在做一个高仿的猫眼App,观察猫眼电影App的下拉刷新后,发现其中还是有小细节的,所以决定自己动手撸了一个猫眼下拉刷新(其实是网上实在没有找到可以抄的代码。。),结合SuperRefreshLayout加上自定义的一个刷新头部达到了猫眼App的下拉刷新效果


先上图

1716281-47296fa4c3109c9b.gif
file.gif

效果和正版基本上是一样的,接下来贴出实现方法和思路
由于是基于SuperRefreshLayout重写的下拉刷新的接口实现,所以原有的功能都会有(无入侵,支持RecyclerView,ScrollView,etc)

下拉刷新几个阶段:

1.下拉过程中,达到一定的距离后红圈开始逐渐显示
2.还未达到可以刷新的距离时向上滑动,红圈会逐渐消失
3.当达到刷新距离时,松手红圈开始转动

需要编写的几个类

1.刷新的头部(红圈和灰色猫眼icon)
2.实现SuperSwipeRefreshLayout.OnPullRefreshListener 接口

先看头部View

主要实现在onDraw方法

public class RefreshView extends ImageView {

private Paint mPaint;
private float progress;//进度,就是显示的程度
private boolean isAnimate;//判断是否在旋转
private int rotateProgress;//旋转角度
private Handler mHandler;

public RefreshView(Context context) {
    this(context, null);
}

public RefreshView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public RefreshView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

private void init() {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    rotateProgress = 0;
    progress = 0f;
    mHandler = new Handler();
}

@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int minWidth = (int) (this.getWidth() * progress);
    int minHeight = (int) (this.getHeight() * progress);
    //开始滑动的时候才进行绘制
    if (minWidth > 1 && minHeight > 1) {

        Bitmap inner = BitmapFactory.decodeResource(getResources(), R.drawable.bg_pull_process);
        Bitmap circle = BitmapFactory.decodeResource(getResources(), R.drawable.ic_progress_out);

        float scaleW = (float) getWidth() / (float) inner.getWidth();
        float scaleH = (float) getHeight() / (float) inner.getHeight();
        int scaleWidth = (int) (inner.getWidth() * scaleW);
        int scaleHeight = (int) (inner.getHeight() * scaleH);
        //画内部的灰色猫icon,canvas画图,大小根据图片的
        canvas.drawBitmap(inner, null, new Rect(0, 0, scaleWidth, scaleHeight), mPaint);

        Matrix matrix = new Matrix();
        //顺时针旋转180度,因为一开始应该是从下网上画图片
        matrix.postRotate(rotateProgress, (float) scaleWidth / 2.0f, (float) scaleHeight / 2.0f);
        //创建一个新的可缩放的bitmap
        Bitmap temp_circle = Bitmap.createScaledBitmap(circle, scaleWidth, scaleHeight, true);

        //进度最大为1f,超过设为1f
        if (progress >= 1.0f) {
            progress = 1.0f;
        }

       //创建一个bitmap,其实就是从下到上画一个图,
        // progress每次变动都会重新绘制外圈, 
        // createBitmap最后一个参数就是所画图片的高度,
        // 因为是根据显示程度来绘制,所以高度*(progress) 其中progess<=1,就会有渐变的效果

        Bitmap mask_outter_circle = Bitmap.createBitmap(temp_circle, 0, 0,
                temp_circle.getWidth(), progress == 1.0f ?
                        temp_circle.getHeight()
                        : (int) (temp_circle.getHeight() * progress));
        //画红圈
        canvas.drawBitmap(mask_outter_circle, matrix, mPaint);

        inner.recycle();
        temp_circle.recycle();
        mask_outter_circle.recycle();
        circle.recycle();
    }
}

/**
 * 设置红色圆圈显示程度
 */
public void setProgress(float progress) {
    this.progress = progress;
    this.invalidate();
}

/**
 * 开始旋转动画
 */
public void startAnimate() {
    if (!isAnimate) {
        isAnimate = true;
        mHandler.post(mRunnable);
    }

}

/**
 * 结束旋转动画
 */
public void stopAnimate() {
    isAnimate = false;
    mHandler.removeCallbacks(mRunnable);
    rotateProgress = 180;
    progress = 0f;
}

private Runnable mRunnable = new Runnable() {

    @Override
    public void run() {
        rotateProgress += 8;
        if (isAnimate) {
            mHandler.postDelayed(mRunnable, 10);
        }
        RefreshView.this.invalidate();
    }
};  }

实现SuperSwipeRefreshLayout.OnPullRefreshListener,完成下拉刷新的逻辑

`

public class MyPullToRefreshListener implements  SuperSwipeRefreshLayout.OnPullRefreshListener {

private OnRefreshListener mOnRefreshListener;
private boolean isRefresh;//是否可以刷新
private int mScrollDistance;//滑动距离
private RefreshView refreshView;//刷新的头部
private int height;//头部高度
private SuperSwipeRefreshLayout mSwipeRefreshLayout;
private final int scrollPx;//需要滑动的距离


public MyPullToRefreshListener(Context context, SuperSwipeRefreshLayout superSwipeRefreshLayout) {

    this.mSwipeRefreshLayout = superSwipeRefreshLayout;
    setupRefreshView(context);
    scrollPx = UiUtils.dp2px(context, 25);
}


private void setupRefreshView(Context context) {
    refreshView = new RefreshView(context);
    mSwipeRefreshLayout.setHeaderView(refreshView);
    height = mSwipeRefreshLayout.getHeaderHeight();
}

/**
 * 加载成功之后回调
 */
public void refreshDone() {
    //RxJava的延迟操作700毫秒停止动画
    Observable.timer(700, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
            .map(new Func1<Long, Void>() {
                @Override
                public Void call(Long aLong) {
                    //停止旋转
                    refreshView.stopAnimate();
                    //刷新结束
                    mSwipeRefreshLayout.setRefreshing(false);
                    return null;
                }
            })
            .subscribe();
}
/**
 * 刷新操作
 */
@Override
  public void onRefresh() {
    if (mOnRefreshListener != null) {
        mOnRefreshListener.refresh();
        refreshView.startAnimate();
    }
}

//根据滑动的距离来对View的进行绘制
@Override
public void onPullDistance(int distance) {
    if (mScrollDistance > distance) {
        
        //当不在刷新状态并且滑动距离超过scrollPx之后才开始变色
        if (!isRefresh && distance > scrollPx) {
        // Log.d("滑动", "onPullDistance: 向上变颜色");
        //渐变程度,其实就是一个线性渐变的函数,y/x = scale;
        //由于需要滑动到一定的程度再进行渐变,
        // 函数为 (y-scrollPx)/x = scale------->(y-scrollPx)/x = y/x  
        //其中y = 滑动距离,x = 刷新布局的高度
            float scale = ((float) distance - scrollPx) / (((2 * height * scrollPx) / distance));
            refreshView.setProgress(scale <= 0f ? 0f : scale);
        }
    } else {
        if (!isRefresh && distance > scrollPx) {
            float scale = ((float) distance - scrollPx) / (((2 * height * scrollPx) / distance));
            refreshView.setProgress(scale > 1f ? 1f : scale);
        //  Log.d("滑动", "onPullDistance: 向下变颜色" + distance + "---" + height + "---scale:" + scale);
        }
    }
    mScrollDistance = distance;
}

@Override
public void onPullEnable(boolean enable) {
    isRefresh = enable;
}

public void setOnRefreshListener(OnRefreshListener OnRefreshListener) {
    this.mOnRefreshListener = OnRefreshListener;
}

/**
 * 刷新回调,在该方法中执行刷新数据操作
 */
public interface OnRefreshListener {
    void refresh();
}}

使用方法

XML包裹需要下拉刷新的控件

1716281-e482c0a4a5fa5750.png
Paste_Image.png

Activity/Fragment代码

    MyPullToRefreshListener pullToRefreshListener = new  MyPullToRefreshListener(mContext,swip);
    pullToRefreshListener.setOnRefreshListener(new MyPullToRefreshListener.OnRefreshListener() {
        @Override
        public void refresh() {
           //实现你的刷新功能
        }
    });
    swip.setOnPullRefreshListener(pullToRefreshListener);
    
    //刷新成功或者失败后调用
    pullToRefreshListener.refreshDone();

最后,语文学的差,表达能力欠佳,写了这么多也不知道自己表达清楚没有,但是效果还是出来了,第一次写简书,恳请各位包容。

项目是持续在更新的高仿猫眼电影,没有单独的Demo,如果有需要请留言,会单独开一个工程Demo

项目地址:https://github.com/Cicinnus0407/CatEye

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值