基于RecyclerView通用适配自定义下拉刷新
来源:互联网 发布:淘宝卖家论坛社区 编辑:程序博客网 时间:2024/05/14 06:21
天气热,人也变的懒散了,晚上如汗蒸,睡眠很不好,精神状态也不好。
一、前言
自从使用了RecyclerView
,就爱上了它,灵活性非常的强大,效果绚丽,如果想进一步了解,请关注:
RecyclerView 之通用适配
在通用适配篇中使用的SwipeRefreshLayout
实现的下拉刷新功能,本篇带大家实现自定义的下拉刷新,先来啾啾效果图:
PullRefreshLoadView(下拉刷新)
PullRefreshLoadView
下拉控件有4个状态,分别是:
STATE_PULL_TO_REFRESH 下拉刷新状态
STATE_RELEASE_TO_REFRESH 释放立即刷新状态
STATE_REFRESHING 正在刷新状态
STATE_REFRESHED 刷新完成状态
实现的原理:重写RecyclerView
的onTouchEvent
方法,获取getRawY
差值动态计算PullRefreshLoadView
的高度。
原理还是比较简单的,但这里有2点你需要注意:
1、setVisibility(View.INVISIBLE)
无效,在刷新状态的时需要对箭头图标进行隐藏,发现View.INVISIBLE
不管用,这个就纠结了,网上几乎找不到这方面的问题,后来看到一篇文章就说加一句clearAnimation();
靠,还真解决了:
mArrowIv.clearAnimation();mArrowIv.setVisibility(View.INVISIBLE);
2、无限循环动画的匿名updatelistener
里面直接执行invalidate
方法,由于对view
的强引用,导致view
无法被正常回收,进一步导致view
的context
的activity
无法被回收,最终产生内存泄露。解决方案就是重写一个updatelistener
,在构造函数中实现对view
的弱引用:
private static class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener { private WeakReference<BallSpinFadeLoader> mWeakReference; public MyUpdateListener(BallSpinFadeLoader ballSpinFadeLoader) { mWeakReference = new WeakReference<BallSpinFadeLoader>(ballSpinFadeLoader); } @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { BallSpinFadeLoader ball = mWeakReference.get(); if (ball == null) { return; } }}
下面是PullRefreshLoadView
源码:
package com.github.baserecycleradapter.widget;import android.animation.ValueAnimator;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.Animation;import android.view.animation.RotateAnimation;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import com.github.baserecycleradapter.R;/** * Created by Administrator on 8/24 0024. */public class PullRefreshLoadView extends LinearLayout { private Context mContext; //上下文 private LinearLayout mContainer; private ImageView mArrowIv; //箭头 private TextView mStatusTv; //下拉刷新 释放刷新 刷新完成 private BallSpinFadeLoader mLoader; //loading 图标 private int mState; //状态 private int mHeight; //高度 private Animation mArrowDownAnim;//向下动画 private Animation mArrowUpAnim; //向上动画 public final static int STATE_PULL_TO_REFRESH = 0; public final static int STATE_RELEASE_TO_REFRESH = 1; public final static int STATE_REFRESHING = 2; public final static int STATE_REFRESHED = 3; public final static String PULL_TO_REFRESH = "下拉刷新"; public final static String RELEASE_TO_REFRESH = "释放立即刷新"; public final static String REFRESHING = "正在刷新..."; public final static String REFRESHED = "刷新完成"; public PullRefreshLoadView(Context context) { this(context, null); } public PullRefreshLoadView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PullRefreshLoadView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { mContext = context; mState = STATE_PULL_TO_REFRESH; mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate( R.layout.rv_refresh, null); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); lp.setMargins(0, 0, 0, 0); setLayoutParams(lp); setPadding(0, 0, 0, 0); addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0)); setGravity(Gravity.BOTTOM); mArrowIv = (ImageView) mContainer.findViewById(R.id.iv_arrow); mStatusTv = (TextView) mContainer.findViewById(R.id.tv_refresh_status); mLoader = (BallSpinFadeLoader) mContainer.findViewById(R.id.ball_loader); mArrowDownAnim = new RotateAnimation(180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mArrowDownAnim.setDuration(180); mArrowDownAnim.setFillAfter(true); mArrowUpAnim = new RotateAnimation(0.0f, 180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mArrowUpAnim.setDuration(180); mArrowUpAnim.setFillAfter(true); measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); mHeight = getMeasuredHeight(); } /** * @param resId */ public void setArrowImageView(int resId) { if (mArrowIv != null) { mArrowIv.setImageResource(resId); } } public int getState() { return mState; } public int getVisibleHeight() { LayoutParams lp = (LayoutParams) mContainer.getLayoutParams(); return lp.height; } public void setVisibleHeight(int height) { if (height <= 0) height = 0; LayoutParams lp = (LayoutParams) mContainer.getLayoutParams(); lp.height = height; mContainer.setLayoutParams(lp); } public void refreshComplete() { setState(STATE_REFRESHED); reset(); } /** * @param delta */ public void onMove(float delta) { if (getVisibleHeight() > 0 || delta > 0) { setVisibleHeight((int) (delta + getVisibleHeight())); if (mState <= STATE_RELEASE_TO_REFRESH) { if (getVisibleHeight() > mHeight) { setState(STATE_RELEASE_TO_REFRESH); } else { setState(STATE_PULL_TO_REFRESH); } } } } public boolean releaseAction() { boolean isOnRefresh = false; int height = getVisibleHeight(); int destHeight = 0; if (height == 0) isOnRefresh = false; if (mState == STATE_REFRESHING) { destHeight = mHeight; } if (height > mHeight && mState < STATE_REFRESHING) { setState(STATE_REFRESHING); destHeight = mHeight; isOnRefresh = true; } smoothScrollTo(destHeight); return isOnRefresh; } public void reset() { smoothScrollTo(0); postDelayed(new Runnable() { @Override public void run() { setState(STATE_PULL_TO_REFRESH); } }, 200); } /** * @param state */ public void setState(int state) { if (state == mState) return; if (state == STATE_REFRESHING) { if (!mLoader.isLoading()) { mLoader.startAnimator(); } mArrowIv.clearAnimation(); mStatusTv.setText(REFRESHING); mLoader.setVisibility(View.VISIBLE); mArrowIv.setVisibility(View.INVISIBLE); } else if (state == STATE_PULL_TO_REFRESH) { mArrowIv.setVisibility(View.VISIBLE); mLoader.setVisibility(View.INVISIBLE); mStatusTv.setText(PULL_TO_REFRESH); if (mState == STATE_RELEASE_TO_REFRESH) { mArrowIv.startAnimation(mArrowDownAnim); } else if (mState == STATE_REFRESHING) { mArrowIv.clearAnimation(); } } else if (state == STATE_RELEASE_TO_REFRESH) { mArrowIv.setVisibility(View.VISIBLE); mLoader.setVisibility(View.INVISIBLE); mStatusTv.setText(RELEASE_TO_REFRESH); if (mState != STATE_RELEASE_TO_REFRESH) { mArrowIv.clearAnimation(); mArrowIv.startAnimation(mArrowUpAnim); } } else if (state == STATE_REFRESHED) { mArrowIv.clearAnimation(); mStatusTv.setText(REFRESHED); mArrowIv.setVisibility(View.INVISIBLE); mLoader.setVisibility(View.INVISIBLE); } mState = state; } /** * @param destHeight */ private void smoothScrollTo(int destHeight) { ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), destHeight); animator.setDuration(300).start(); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setVisibleHeight((int) animation.getAnimatedValue()); } }); animator.start(); }}
接着来看看RecyclerView
的onTouchEvent
方法:
@Overridepublic boolean onTouchEvent(MotionEvent e) { if (mLastY == -1) { mLastY = e.getRawY(); } switch (e.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = e.getRawY(); break; case MotionEvent.ACTION_MOVE: if (isScrollTop()) { float deltaY = e.getRawY() - mLastY; mPullRefreshLoadView.onMove(deltaY / 3); mLastY = e.getRawY(); if (mPullRefreshLoadView.getVisibleHeight() > 0 && mPullRefreshLoadView.getState() < mPullRefreshLoadView.STATE_REFRESHING) { return false; } } break; default: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_OUTSIDE: mLastY = -1; // reset if (mPullRefreshLoadView.releaseAction()) { if (mCompleteListener != null) { mCompleteListener.onRefreshComplete(); } } break; } return super.onTouchEvent(e);}
源码地址,如果你喜欢,还请 star
- 基于RecyclerView通用适配自定义下拉刷新
- android自定义通用下拉刷新
- 自定义RecyclerView实现下拉刷新,加载更多
- 给RecyclerView自定义上拉,下拉刷新
- Recyclerview下拉刷新干货(自定义)
- 自定义的RecyclerView, 下拉刷新,加载更多.
- 自定义View:通用的下拉刷新
- 基于MJRefresh的自定义下拉刷新
- 支持下拉刷新、上拉加载的RecyclerView,基于PullToRefresh
- recyclerView 下拉刷新
- SwipeRefreshLayout+RecyclerView下拉刷新
- SwipeRefreshLayout+RecyclerView 下拉刷新
- recyclerview下拉自动刷新
- RecyclerView下拉刷新实现
- RecyclerView的下拉刷新
- 手写RecyclerView下拉刷新
- Android RecyclerView下拉刷新
- RecyclerView加下拉刷新
- JNI学习之C语言第4天
- Dialog设置为满宽
- 什么才算是真正的编程能力?
- LeetCode | Minimum Path Sum
- ios自制电话本-swift
- 基于RecyclerView通用适配自定义下拉刷新
- Intellij从无到有创建项目:梳理web项目各目录及配置作用
- Java---代理Proxy
- Reader——FileReader的使用示例
- 聚类
- flume sink hdfs异常
- 24.leetcode Merge k Sorted Lists(hard)[归并k个有序链表]
- 源码安装Memcached服务器及其2种PHP客户端
- 服务器底层框架及 RPC