RecyClerView列表关于
简单使用
LinearLayoutManager 线性管理器(支持横向、纵向)
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布流式布局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// 如果可以确定每个 item 的高度是固定的,设置这个选项可以提高性能
recyclerView.setHasFixedSize(true);
// item 显示的动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(new MyAdapter());
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
public List<String> datas;
public MyAdapter(List<String> datas) {
this.datas = datas;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.mTextView.setText(datas.get(position));
}
@Override
public int getItemCount() {
return datas.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public ViewHolder(View view){
super(view);
mTextView = (TextView) view.findViewById(R.id.text);
}
}
}
多种布局
public class MyAdapter extends RecyclerView.Adapter {
public List<String> datas;
public MyAdapter(List<String> datas) {
this.datas = datas;
}
public enum ITEM_TYPE {
ITEM1, ITEM2
}
@Override
public int getItemViewType(int position) {
// Enum 类提供了一个 ordinal() 方法,返回枚举类型的序数
// ITEM_TYPE.ITEM1.ordinal() 代表0, ITEM_TYPE.ITEM2.ordinal() 代表1
return position % 2 == 0 ? ITEM_TYPE.ITEM1.ordinal() : ITEM_TYPE.ITEM2.ordinal();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 根据不同 viewType 加载不同的布局
if (viewType == ITEM_TYPE.ITEM1.ordinal()) {
View view1 = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false);
return new ViewHolder1(view1);
} else if (viewType == ITEM_TYPE.ITEM2.ordinal()) {
View view2 = LayoutInflater.from(parent.getContext()).inflate(R.layout.item2, parent, false);
return new ViewHolder2(view2);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (holder instanceof ViewHolder1) {
((ViewHolder1) holder).mTextView.setText(datas.get(position));
} else if (holder instanceof ViewHolder2) {
((ViewHolder2) holder).mTextView.setText(datas.get(position)+"abc");
}
}
@Override
public int getItemCount() {
return datas.size();
}
public static class ViewHolder1 extends RecyclerView.ViewHolder {
public TextView mTextView;
public ViewHolder(View view){
super(view);
mTextView = (TextView) view.findViewById(R.id.text);
}
}
public static class ViewHolder2 extends RecyclerView.ViewHolder {
public TextView mTextView;
public ViewHolder(View view){
super(view);
mTextView = (TextView) view.findViewById(R.id.big_text);
}
}
}
分隔线 ItemDecoration
自定义分隔线
定义分隔线 divider.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#7b7a7a"/>
<size android:height="1dp"/>
</shape>
自定义类继承 RecyclerView.ItemDecoration,重写回调方法
// 线性布局用
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
public class MyDecoration extends RecyclerView.ItemDecoration{
private Context mContext;
private Drawable mDivider;
private int mOrientation;
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
public MyDecoration(Context context, int orientation) {
this.mContext = context;
mDivider = context.getResources().getDrawable(R.drawable.divider);
setOrientation(orientation);
}
// 设置屏幕的方向
public void setOrientation(int orientation){
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == HORIZONTAL_LIST){
drawVerticalLine(c, parent, state);
}else {
drawHorizontalLine(c, parent, state);
}
}
// 画竖线, 这里的 parent 其实是显示在屏幕显示的这部分
public void drawVerticalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++){
final View child = parent.getChildAt(i);
// 获得 child 的布局信息
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
// 画横线
public void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state){
int top = parent.getPaddingTop();
int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++){
final View child = parent.getChildAt(i);
// 获得 child 的布局信息
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
// 由于 Divider 也有长宽高,每一个 Item 需要向下或者向右偏移
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if(mOrientation == HORIZONTAL_LIST){
// 画竖线,就是往右偏移一个分割线的宽度
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else {
// 画横线,就是往下偏移一个分割线的高度
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}
}
}
// 网格或瀑布流布局用
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
private Drawable mDivider;
public DividerGridItemDecoration(Context context) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private int getSpanCount(RecyclerView parent) {
// 列数
int spanCount = -1;
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
spanCount = ((StaggeredGridLayoutManager) layoutManager)
.getSpanCount();
}
return spanCount;
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin
+ mDivider.getIntrinsicWidth();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) {
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
if ((pos + 1) % spanCount == 0) { // 如果是最后一列,则不需要绘制右边
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
if ((pos + 1) % spanCount == 0) { // 如果是最后一列,则不需要绘制右边
return true;
}
} else {
childCount = childCount - childCount % spanCount;
if (pos >= childCount) // 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
}
private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) {
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
childCount = childCount - childCount % spanCount;
if (pos >= childCount) // 如果是最后一行,则不需要绘制底部
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
// StaggeredGridLayoutManager 且纵向滚动
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (pos >= childCount)
return true;
} else { // StaggeredGridLayoutManager 且横向滚动
// 如果是最后一行,则不需要绘制底部
if ((pos + 1) % spanCount == 0) {
return true;
}
}
}
return false;
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRaw(parent, itemPosition, spanCount, childCount)) { // 如果是最后一行,则不需要绘制底部
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount)) { // 如果是最后一列,则不需要绘制右边
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
}
}
}
使用自定义分隔线:
mRecyclerView.addItemDecoration(new MyDecoration(this, MyDecoration.VERTICAL_LIST));
使用自带的分隔线
mRecyclerView.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.HORIZONTAL));
可以更改自带分隔线的样式:
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:listDivider">@drawable/divider_bg</item>
</style>
可以自己画个分隔线 shape。
item 选择器
给 item 设置一个 selector,设置 android:state_focused 不同时不同的背景,关键是要在 item 根布局设置
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
item 有 EditText
TextWatcher 问题
EditText 添加 TextWatcher 后,每次执行刷新、添加数据之类的操作,即只要执行 onBindViewHolder 就会进入监听,导致数据错乱。
解决方法时一开始先移除监听:
holder.tvOrderGoodsQuantity.removeTextChangedListener((QunaitityWatcher) holder.tvOrderGoodsQuantity.getTag());
然后做完数据操作后,再添加:
QunaitityWatcher watcher = new QunaitityWatcher(holder.tvOrderGoodsQuantity, holder.tvOrderGoodsQuantity, mData, holder.tvOrderGoodsAmount);
holder.tvOrderGoodsQuantity.addTextChangedListener(watcher);
自定义 TextWatcher,把一些 View 作为参数传入,以免数据错乱,不然可能会传到其它 item 的 View 上。
private class QunaitityWatcher implements TextWatcher {
private EditText editText;
private GoodModel model;
private TextView tv;
private EditText et;
public QunaitityWatcher(EditText et, EditText editText, GoodModel model, TextView tv) {
this.et = et;
this.editText = editText;
this.model = model;
this.tv = tv;
et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus)
et.setText(Utils.subZeroAndDot(model.getScatterGoodQuantity()));
}
});
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String text = s.toString();
if (!TextUtils.isEmpty(text) && Utils.isDouble(text) && !text.startsWith(".")) {
double d = Double.parseDouble(text);
if (d <= 0) {
editText.setText("1"); // 默认的 1 件
d = 1;
} else {
int dotindex = text.indexOf(".");
if (dotindex > 0 && text.length() > dotindex + 3) {
s.delete(dotindex + 3, text.length());
} else {
d = Double.parseDouble(s.toString());
}
}
tv.setText("¥" + Utils.subZeroAndDot(d * model.getPrice()));
model.setScatterGoodQuantity(d);
EventBus.getDefault().post(new ChangeGoodQuantityEvent());
refreshQuantityAndPrice();
}
}
}
Edittext 获取不到焦点
因为 EditText 默认 FocusableInTouchMode 为 false,需设置
et.setFocusableInTouchMode(true);
et.requestFocus();
是否到达最底部
方法一:
public static boolean isVisBottom(RecyclerView recyclerView){
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
// 屏幕中最后一个可见子项的 position
int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();
// 当前屏幕所看到的子项个数
int visibleItemCount = layoutManager.getChildCount();
// 当前 RecyclerView 的所有子项个数
int totalItemCount = layoutManager.getItemCount();
// RecyclerView 的滑动状态
int state = recyclerView.getScrollState();
if(visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 && state == recyclerView.SCROLL_STATE_IDLE){
return true;
} else {
return false;
}
}
方法二:
public static boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) return false;
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
>= recyclerView.computeVerticalScrollRange())
return true;
return false;
}
computeVerticalScrollExtent() 是当前屏幕显示的区域高度,
computeVerticalScrollOffset() 是当前屏幕之前滑过的距离,
而 computeVerticalScrollRange() 是整个 View 控件的高度。
方法三:
RecyclerView.canScrollVertically(1) 的返回值表示是否能向上滚动,false 表示已经滚动到底部
RecyclerView.canScrollVertically(-1) 的返回值表示是否能向下滚动,false 表示已经滚动到顶部
跨列
复杂的不规则列(有的行显示的列数多,有的行显示的列数少,并且每列显示的内容页不一样),使用 GridLayoutManager.SpanSizeLookup 的相关功能实现,新建 GridLayoutManager 的时候列数填写所有可能列数的最小公倍数。再结合 adapter 中的:
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
// 设置对应 position 位置的 item 的跨列数,比如第一行占两列,其他行每个 Item 占一列
return position == 0 ? 2 : 1;
}
});
recyclerView.setLayoutManager(layoutManager);
智能
智能是什么玩意?有什么用?智能主要体现 SmartRefreshLayout 对未知布局的自动识别上,这样可以让我们更高效的实现我们所需的功能,也可以实现一些非寻常的功能。下面通过自定义Header 和 嵌套Layout作为内容 来解释 SmartRefreshLayout 的智能之处。
自定义Header
我们来看这一下这个伪代码例子:
<SmartRefreshLayout>
<ClassicsHeader/>
<TextView/>
<ClassicsFooter/>
</SmartRefreshLayout>
在Android Studio 中的预览效果图

对比代码和我们预想的一样,那我们来对代码做一些改动,ClassicsHeader换成一个简单的TextView,看看会发生什么?
<SmartRefreshLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:background="#444"
android:textColor="#fff"
android:text="看看我会不会变成Header"/>
<TextView/>
<ClassicsFooter/>
</SmartRefreshLayout>
在Android Studio 中的预览效果图 和 运行效果图
我们注意看右边的图,仔细观察手指触摸的位置和下拉效果。可以看到在列表已经滚动到中部时,轻微下拉列表是不会触发刷新的,但是如果是触摸固定的布局,则可以触发下拉。从这里可以看出 SmartRefreshLayout 对滚动边界的判断是动态的,智能的!当然如果 SmartRefreshLayout 的智能还是不能满足你,可以通过 setListener 自己实现滚动边界的判断,更为准确!
这时发现我们我们替换的 TextView 自动就变成了Header,只是它还不会动。要动起来?
接着我们来改代码:
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.3'//一个开源gif控件
<SmartRefreshLayout>
<pl.droidsonroids.gif.GifImageView
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop"
android:src="@mipmap/gif_header_repast"/>
<ListView/>
<ClassicsFooter/>
</SmartRefreshLayout>
在 Android Studio 中的预览效果图 和 运行效果图

哈哈!一行Java代码都不用写,就完成了一个自定义的Header
嵌套Layout作为内容
如果boos要求在列表的前面固定一个广告条怎么办?这好办呀,一般我们会开开心心的下下这样的代码:
<LinearLayout
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:text="我就是boos要求加上的广告条啦"/>
<SmartRefreshLayout>
<ListView/>
</SmartRefreshLayout>
</LinearLayout>
但是在运行下拉刷新的时候,我们发现 Header是在广告条之下的,看着会别扭~,其实我们可以试试另一种方式,把广告条写到 RefreshLayout内部,看看会发生什么?
<SmartRefreshLayout>
<LinearLayout
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:text="我就是boos要求加上的广告条啦"/>
<ListView/>
</LinearLayout>
</SmartRefreshLayout>
由于伪代码过于简单,而且运行效果过于丑陋,这里还是贴出在实际项目中的实际情况吧~


我们注意看右边的图,仔细观察手指触摸的位置和下拉效果。可以看到在列表已经滚动到中部时,轻微下拉列表是不会触发刷新的,但是如果是触摸固定的布局,则可以触发下拉。从这里可以看出 SmartRefreshLayout 对滚动边界的判断是动态的,智能的!当然如果 SmartRefreshLayout 的智能还是不能满足你,可以通过 setListener 自己实现滚动边界的判断,更为准确!
功能
简单的介绍了两大特点框架和智能,接下来也说说SmartRefreshLayout还具有的其他常用功能吧~
- 支持所有的 View(AbsListView、RecyclerView、WebView....View) 和多层嵌套的 Layout
- 支持自定义并且已经集成了很多炫酷的 Header 和 Footer
- 支持和ListView的同步滚动 和 RecyclerView、AppBarLayout、CoordinatorLayout 的嵌套滚动 NestedScrolling.
- 支持在Android Studio Xml 编辑器中预览 效果
- 支持分别在 Default(默认)、Xml、JavaCode 等三个地方设置 Header 和 Footer.
- 支持自动刷新、自动上拉加载(自动检测列表滚动到底部,而不用手动上拉).
- 支持通用的刷新监听器 OnRefreshListener 和更详细的滚动监听 OnMultiPurposeListener.
- 支持自定义回弹动画的插值器,实现各种炫酷的动画效果.
- 支持设置主题来适配任何场景的App,不会出现炫酷但很尴尬的情况.
- 支持设置多种滑动方式来适配各种效果的Header和Footer:位置平移、尺寸拉伸、背后固定、顶层固定、全屏
- 支持内容尺寸自适应 Content-wrap_content
- 支持继承重写和扩展功能,内部实现没有 private 方法和字段,继承之后都可以重写覆盖
- 支持越界回弹(Listview、RecyclerView、ScrollView、WebView...View)
使用
简单用例
1.在 buld.gradle 中添加依赖
compile 'com.android.support:appcompat-v7:25.3.1'//版本随意
compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.4'
compile 'com.scwang.smartrefresh:SmartRefreshHeader:1.0.4'//没有使用特殊Header,可以不加这行
2.在XML布局文件中添加 SmartRefreshLayout
<?xml version="1.0" encoding="utf-8"?>
<com.scwang.smartrefresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
android:background="#fff" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
3.在 Activity 或者 Fragment 中添加代码
RefreshLayout refreshLayout = (RefreshLayout)findViewById(R.id.refreshLayout);
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
refreshlayout.finishRefresh(2000);
}
});
refreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() {
@Override
public void onLoadmore(RefreshLayout refreshlayout) {
refreshlayout.finishLoadmore(2000);
}
});
使用指定的 Header 和 Footer
1.方法一 全局设置
public class App extends Application {
static {//static 代码段可以防止内存泄露
//设置全局的Header构建器
SmartRefreshLayout.setDefaultRefreshHeaderCreater(new DefaultRefreshHeaderCreater() {
@Override
public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);//全局设置主题颜色
return new ClassicsHeader(context).setSpinnerStyle(SpinnerStyle.Translate);//指定为经典Header,默认是 贝塞尔雷达Header
}
});
//设置全局的Footer构建器
SmartRefreshLayout.setDefaultRefreshFooterCreater(new DefaultRefreshFooterCreater() {
@Override
public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
//指定为经典Footer,默认是 BallPulseFooter
return new ClassicsFooter(context).setSpinnerStyle(SpinnerStyle.Translate);
}
});
}
}
注意:方法一 设置的Header和Footer的优先级是最低的,如果同时还使用了方法二、三,将会被其他方法取代
2.方法二 XML布局文件指定
<com.scwang.smartrefresh.layout.SmartRefreshLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/smartLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#444444"
app:srlPrimaryColor="#444444"
app:srlAccentColor="@android:color/white"
app:srlEnablePreviewInEditMode="true">
<!--srlAccentColor srlPrimaryColor 将会改变 Header 和 Footer 的主题颜色-->
<!--srlEnablePreviewInEditMode 可以开启和关闭预览功能-->
<com.scwang.smartrefresh.layout.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/padding_common"
android:background="@android:color/white"
android:text="@string/description_define_in_xml"/>
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
注意:方法二 XML设置的Header和Footer的优先级是中等的,会被方法三覆盖。而且使用本方法的时候,Android Studio 会有预览效果,如下图:

不过不用担心,只是预览效果,运行的时候只有下拉才会出现~