自定义SmartRefreshLayout下拉刷新Header和上拉加载Footer
废话不多说,先看效果图;
1.这是默认效果(一般情况可以满足需求。但如果需要自定义时,就无法处理了。) SmartRefreshLayout框架,提供了部分刷新动画,但个人认为针对列表刷新动画来说,所提供的的动画不适合。所以还需要自己处理。
2.这是自定义效果(如果需要有自己的动画就要自定义,动画自己添加进去图片即可。)
上图的刷新动画图集是由39张图片组成的帧动画;下拉刷新是由34个图片组成的帧动画。(图片我就不一一贴出来了,如果需要请下载源码中获取)。
SmartRefreshLayout框架(github上很火的一个刷新框架)
(地址:https://github.com/scwang90/SmartRefreshLayout)
特点:强大,稳定,成熟的下拉刷新框架;炫酷、多样、实用、美观的Header和Footer;
功能:
- 支持横向刷新,支持多点触摸,支持AndroidX
- 支持 Header 和 Footer 交换混用,支持淘宝二楼和二级刷新
- 支持所有可滚动视图的越界回弹, 支持嵌套多层的视图结构
- 支持设多种滑动方式:平移、拉伸、背后固定、顶层固定、全屏
- 支持所有的 View(AbsListView、RecyclerView、WebView…View)
- 支持自定义并且已经集成了很多炫酷的 Header 和 Footer.
- 支持和 ListView 的无缝同步滚动 和 CoordinatorLayout 的嵌套滚动 .
- 支持自动刷新、自动上拉加载(自动检测列表惯性滚动到底部,而不用手动上拉).
- 支持自定义回弹动画的插值器,实现各种炫酷的动画效果等等…
如果需要,希望能够帮助到你。
下面开始上代码。
- 第一步,自定义SmartRefreshLayout
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.scwang.smart.refresh.layout.SmartRefreshLayout;
/**
* @author mr.cc
* created at 2020/12/22 16:45
* discroption
*/
public class MySmartRefreshLayout extends SmartRefreshLayout {
MyHeaderView mHeaderView;
public MySmartRefreshLayout (Context context) {
this(context, null);
}
public MySmartRefreshLayout (Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySmartRefreshLayout (Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
mHeaderView= new MyHeaderView(context);
mHeaderView.setLayoutParams(layoutParams);
addView(mHeaderView, 0);
}
}
注:其中的MyHeaderView 为自定义刷新头。
- 第二步:自定义MyHeaderView
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.constant.RefreshState;
import com.scwang.smart.refresh.layout.simple.SimpleComponent;
/**
* @author mr.cc
* created at 2020/12/22 16:46
* discroption
*/
public class MyHeaderView extends SimpleComponent {
public static String REFRESH_HEADER_PULLING = "下拉可以刷新";//"下拉可以刷新";
public static String REFRESH_HEADER_LOADING = "正在加载...";//"正在加载...";
public static String REFRESH_HEADER_RELEASE = "释放立即刷新";
public static String REFRESH_HEADER_FINISH = "刷新成功";//"刷新完成";
public static String REFRESH_HEADER_FAILED = "刷新失败";//"刷新失败";
// private TextView mTitleText;
AnimationDrawable animDrawable;
public MyHeaderView(Context context) {
this(context, null);
}
public MyHeaderView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View view = LayoutInflater.from(context).inflate(R.layout.miyuan_refresh_head, this);
ImageView ref_head_img = view.findViewById(R.id.ref_head_img);
animDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.my_refresh_head);
ref_head_img.setImageDrawable(animDrawable);
// mTitleText = view.findViewById(R.id.txt);
}
@Override
public int onFinish(@NonNull RefreshLayout layout, boolean success) {
if (success) {
// mTitleText.setText(REFRESH_HEADER_FINISH);
animDrawable.stop();
} else {
animDrawable.stop();
// mTitleText.setText(REFRESH_HEADER_FAILED);
}
super.onFinish(layout, success);
return 500; //延迟500毫秒之后再弹回
}
@Override
public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
switch (newState) {
case PullDownToRefresh: //下拉过程
// mTitleText.setText(REFRESH_HEADER_PULLING);
animDrawable.start();
break;
case ReleaseToRefresh: //松开刷新
// mTitleText.setText(REFRESH_HEADER_RELEASE);
break;
case Refreshing: //loading中
// mTitleText.setText(REFRESH_HEADER_LOADING);
break;
}
}
}
- 第三步,在layout里面新建一个layout,命名为miyuan_refresh_head,视为刷新头布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="60dp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center|center_vertical"
android:orientation="vertical">
<ImageView
android:id="@+id/ref_head_img"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:src="@mipmap/loading_36"/>
</LinearLayout>
- 第四步:在drawable里面新增一个文件,命名为my_refresh_head,视为刷新的动画。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:drawable="@mipmap/loading_1" android:duration="50"/>
<item android:drawable="@mipmap/loading_2" android:duration="50"/>
<item android:drawable="@mipmap/loading_3" android:duration="50"/>
<item android:drawable="@mipmap/loading_4" android:duration="50"/>
<item android:drawable="@mipmap/loading_5" android:duration="50"/>
<item android:drawable="@mipmap/loading_6" android:duration="50"/>
<item android:drawable="@mipmap/loading_7" android:duration="50"/>
<item android:drawable="@mipmap/loading_8" android:duration="50"/>
<item android:drawable="@mipmap/loading_9" android:duration="50"/>
<item android:drawable="@mipmap/loading_10" android:duration="50"/>
<item android:drawable="@mipmap/loading_11" android:duration="50"/>
<item android:drawable="@mipmap/loading_12" android:duration="50"/>
<item android:drawable="@mipmap/loading_13" android:duration="50"/>
<item android:drawable="@mipmap/loading_14" android:duration="50"/>
<item android:drawable="@mipmap/loading_15" android:duration="50"/>
<item android:drawable="@mipmap/loading_16" android:duration="50"/>
<item android:drawable="@mipmap/loading_17" android:duration="50"/>
<item android:drawable="@mipmap/loading_18" android:duration="50"/>
<item android:drawable="@mipmap/loading_19" android:duration="50"/>
<item android:drawable="@mipmap/loading_20" android:duration="50"/>
<item android:drawable="@mipmap/loading_21" android:duration="50"/>
<item android:drawable="@mipmap/loading_22" android:duration="50"/>
<item android:drawable="@mipmap/loading_23" android:duration="50"/>
<item android:drawable="@mipmap/loading_24" android:duration="50"/>
<item android:drawable="@mipmap/loading_25" android:duration="50"/>
<item android:drawable="@mipmap/loading_26" android:duration="50"/>
<item android:drawable="@mipmap/loading_27" android:duration="50"/>
<item android:drawable="@mipmap/loading_28" android:duration="50"/>
<item android:drawable="@mipmap/loading_29" android:duration="50"/>
<item android:drawable="@mipmap/loading_30" android:duration="50"/>
<item android:drawable="@mipmap/loading_31" android:duration="50"/>
<item android:drawable="@mipmap/loading_32" android:duration="50"/>
<item android:drawable="@mipmap/loading_33" android:duration="50"/>
<item android:drawable="@mipmap/loading_34" android:duration="50"/>
<item android:drawable="@mipmap/loading_35" android:duration="50"/>
<item android:drawable="@mipmap/loading_36" android:duration="50"/>
<item android:drawable="@mipmap/loading_37" android:duration="50"/>
<item android:drawable="@mipmap/loading_38" android:duration="50"/>
<item android:drawable="@mipmap/loading_39" android:duration="50"/>
</animation-list>
注:@mipmap/loading_1为刷新真图片。
至此,自定义刷新功能已经完成,自定义加载功能与自定义刷新功能一样。下面给出代码:
- 第一步:自定义加载功能如下:
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.constant.RefreshState;
import com.scwang.smart.refresh.layout.simple.SimpleComponent;
/**
* 自定义FooterView
*/
public class MyFooterView extends SimpleComponent {
AnimationDrawable animDrawable;
static TextView srl_classics_title;
static ImageView ref_foot_img;
public MyFooterView(Context context) {
this(context, null);
}
public MyFooterView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyFooterView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View view = LayoutInflater.from(context).inflate(R.layout.miyuan_refresh_footer, this);
ref_foot_img = view.findViewById(R.id.ref_foot_img);
srl_classics_title = view.findViewById(R.id.srl_classics_title);
animDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.my_refresh_foot);
ref_foot_img.setImageDrawable(animDrawable);
animDrawable.start();
}
@Override
public int onFinish(@NonNull RefreshLayout layout, boolean success) {
if (success) {
// mTitleText.setText(REFRESH_HEADER_FINISH);
} else {
// mTitleText.setText(REFRESH_HEADER_FAILED);
}
super.onFinish(layout, success);
return 500; //延迟500毫秒之后再弹回
}
@Override
public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
}
protected static boolean mNoMoreData = false;
public static void setmNoMoreData(boolean noMoreData){
mNoMoreData = noMoreData;
if(mNoMoreData){
ref_foot_img.setVisibility(GONE);
srl_classics_title.setVisibility(VISIBLE);
srl_classics_title.setText("我也是有底线的~");
}else{
ref_foot_img.setVisibility(VISIBLE);
srl_classics_title.setVisibility(GONE);
srl_classics_title.setText("正在加载,别慌嘛~");
}
mNoMoreData = false;
}
@Override
public boolean setNoMoreData(boolean noMoreData) {
Log.i("noMoreData", "noMoreData=" + noMoreData);
return true;
}
/**
* 设置数据全部加载完成,将不能再次触发加载功能
*/
// @Override
// public boolean setNoMoreData(boolean noMoreData) {
// if (mNoMoreData != noMoreData) {
// mNoMoreData = noMoreData;
// if (noMoreData) {
// ref_foot_img.setVisibility(GONE);
// srl_classics_title.setVisibility(VISIBLE);
// srl_classics_title.setText("我也是有底线的~");
// } else {
// srl_classics_title.setText("正在加载,别慌嘛~");
srl_classics_title.setVisibility(GONE);
// }
// }
// return true;
// }
}
- 第二步:在layout里面新建一个layout,命名为miyuan_refresh_footer,视为加载头布局。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="match_parent"
android:layout_height="60dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/ref_foot_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@mipmap/two_loading00"/>
<TextView
android:id="@+id/srl_classics_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textColor="#000000"
android:textSize="18dp"/>
</RelativeLayout>
- 第三步:在drawable里面新增一个文件,命名为my_refresh_foot,视为加载的动画。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:drawable="@mipmap/two_loading00" android:duration="50"/>
<item android:drawable="@mipmap/two_loading01" android:duration="50"/>
<item android:drawable="@mipmap/two_loading02" android:duration="50"/>
<item android:drawable="@mipmap/two_loading03" android:duration="50"/>
<item android:drawable="@mipmap/two_loading04" android:duration="50"/>
<item android:drawable="@mipmap/two_loading05" android:duration="50"/>
<item android:drawable="@mipmap/two_loading06" android:duration="50"/>
<item android:drawable="@mipmap/two_loading07" android:duration="50"/>
<item android:drawable="@mipmap/two_loading08" android:duration="50"/>
<item android:drawable="@mipmap/two_loading09" android:duration="50"/>
<item android:drawable="@mipmap/two_loading10" android:duration="50"/>
<item android:drawable="@mipmap/two_loading11" android:duration="50"/>
<item android:drawable="@mipmap/two_loading12" android:duration="50"/>
<item android:drawable="@mipmap/two_loading13" android:duration="50"/>
<item android:drawable="@mipmap/two_loading14" android:duration="50"/>
<item android:drawable="@mipmap/two_loading15" android:duration="50"/>
<item android:drawable="@mipmap/two_loading16" android:duration="50"/>
<item android:drawable="@mipmap/two_loading17" android:duration="50"/>
<item android:drawable="@mipmap/two_loading18" android:duration="50"/>
<item android:drawable="@mipmap/two_loading19" android:duration="50"/>
<item android:drawable="@mipmap/two_loading20" android:duration="50"/>
<item android:drawable="@mipmap/two_loading21" android:duration="50"/>
<item android:drawable="@mipmap/two_loading22" android:duration="50"/>
<item android:drawable="@mipmap/two_loading23" android:duration="50"/>
<item android:drawable="@mipmap/two_loading24" android:duration="50"/>
<item android:drawable="@mipmap/two_loading25" android:duration="50"/>
<item android:drawable="@mipmap/two_loading26" android:duration="50"/>
<item android:drawable="@mipmap/two_loading27" android:duration="50"/>
<item android:drawable="@mipmap/two_loading28" android:duration="50"/>
<item android:drawable="@mipmap/two_loading29" android:duration="50"/>
<item android:drawable="@mipmap/two_loading30" android:duration="50"/>
<item android:drawable="@mipmap/two_loading31" android:duration="50"/>
<item android:drawable="@mipmap/two_loading32" android:duration="50"/>
<item android:drawable="@mipmap/two_loading33" android:duration="50"/>
</animation-list>
到这,加载也就完了。如何使用呢,请继续往下看:
到这一步,所有的自定义代码都已经结束,使用方法也很简单,推荐在界面activity_main布局中直接使用即可。
<cszs.sanhua.com.testsmartdemo.MySmartRefreshLayout
android:id="@+id/fragment_one_refreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srlEnablePreviewInEditMode="true"
app:srlEnableFooterFollowWhenLoadFinished="true"
app:srlEnableLoadMoreWhenContentNotFull="false"
app:srlEnableFooterFollowWhenNoMoreData="true">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<cszs.sanhua.com.testsmartdemo.MyFooterView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srlAccentColor="#000000"/>
</cszs.sanhua.com.testsmartdemo.MySmartRefreshLayout>
大功告成,因为自定义加载这块的回调处理的还是有一点问题,所以在使用的时候有一点地方需要注意,请在MyFooterView 里面认真阅读注释。
以上就是所有的代码
附上demo源码。
源码:源码请点这里…
q:486789970
email:[email protected]
如果有什么问题,欢迎大家指导。并相互联系,希望能够通过文章互相学习。
---财财亲笔