微信截图_20191202161856.png
![瀑布流的效果图,至于刷新加载的动效,就暂时没有录啦,为方便你直接copy使用,所以都是设的文字---图片你难得找]
先来说说思路
首先,瀑布流的布局跟上拉加载和下拉刷新是两个独立的东西,两者并没有半毛钱关系,不是只有列表类的东西才能刷新加载。
然后说说我的引用
就recyclerView的使用来说,我觉得这篇例子写的比我好
我是传送门
关于刷新加载的动画及其他,可看github源码
我是传送门
然后说代码,总共需要五个文件
步骤一
引入刷新加载的库及recyclerView
implementation group: 'androidx.recyclerview', name: 'recyclerview', version: '1.1.0-alpha01'
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-32'//刷新
创建Activity及对应的layout
activity
package com.example.test.more;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.os.Bundle;
import android.widget.Toast;
import com.example.test.R;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.constant.SpinnerStyle;
import com.scwang.smartrefresh.layout.footer.BallPulseFooter;
import com.scwang.smartrefresh.layout.header.BezierRadarHeader;
import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MoretestActivity extends AppCompatActivity {
private List<More> moreList = new ArrayList<>();
private RecyclerView recyclerView;
private MoreAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_moretest);
//加载数据
init();
//适配器布局
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
adapter = new MoreAdapter(moreList);
recyclerView.setAdapter(adapter);
//下拉刷新及上拉加载
RefreshLayout refreshLayout = (RefreshLayout) findViewById(R.id.refreshLayout);
//设置 Header 为 贝塞尔雷达 样式 更多样式以及自定义样式查看 github https://github.com/scwang90/SmartRefreshLayout
refreshLayout.setRefreshHeader(new BezierRadarHeader(this).setEnableHorizontalDrag(true));
//设置 Footer 为 球脉冲 样式
refreshLayout.setRefreshFooter(new BallPulseFooter(this).setSpinnerStyle(SpinnerStyle.Scale));
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshlayout) {
//进行刷新过程的逻辑操作,次数刷新在已有数据头部装载数据,完成后调用finishRefresh方法
boolean aa = initRefresh();
if (aa) {
//数据装载成功的逻辑
refreshlayout.finishRefresh();
adapter.dataChange();
//refreshlayout.finishRefresh(1000/*,false*/);//传入false表示刷新失败,数字则是多久后关闭
} else {
Toast.makeText(MoretestActivity.this, "加载失败", Toast.LENGTH_SHORT).show();
refreshlayout.finishRefresh(false);//传入false表示刷新失败
}
}
});
refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(RefreshLayout refreshlayout) {
//进行加载更多过程的逻辑操作,加载更多在已有数据尾部装载数据,完成后调用finishRefresh方法
boolean aa = initLoadMore();
if (aa) {
//数据装载成功的逻辑
refreshlayout.finishLoadMore();
adapter.dataChange();
//refreshlayout.finishRefresh(1000/*,false*/);//传入false表示刷新失败,数字则是多久后关闭
} else {
Toast.makeText(MoretestActivity.this, "加载失败", Toast.LENGTH_SHORT).show();
refreshlayout.finishRefresh(false);//传入false表示刷新失败
}
}
});
}
//初始化数据
private void init() {
for (int i = 0; i < 3; i++) {
More aa = new More(getRandomLengthName("aaaa"));
moreList.add(aa);
More bb = new More(getRandomLengthName("bbbb"));
moreList.add(bb);
More cc = new More(getRandomLengthName("cccc"));
moreList.add(cc);
More dd = new More(getRandomLengthName("dddd"));
moreList.add(dd);
More ee = new More(getRandomLengthName("eeee"));
moreList.add(ee);
More ff = new More(getRandomLengthName("ffff"));
moreList.add(ff);
More gg = new More(getRandomLengthName("gggg"));
moreList.add(gg);
}
}
//上拉加载时装载的数据,需装入数据尾部
private boolean initLoadMore() {
List<More> loadList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
More aa = new More(getRandomLengthName("1111"));
loadList.add(aa);
More bb = new More(getRandomLengthName("2222"));
loadList.add(bb);
More cc = new More(getRandomLengthName("3333"));
loadList.add(cc);
More dd = new More(getRandomLengthName("4444"));
loadList.add(dd);
More ee = new More(getRandomLengthName("5555"));
loadList.add(ee);
More ff = new More(getRandomLengthName("6666"));
loadList.add(ff);
More gg = new More(getRandomLengthName("7777"));
loadList.add(gg);
}
//由于需装入尾部,所以以moreList为主,需返回装载结果来判断是否加载成功
boolean a = moreList.addAll(loadList);
return a;
}
//下拉刷新时装载的数据,需装入数据头部
private boolean initRefresh() {
List<More> refreshList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
More aa = new More(getRandomLengthName("qqqq"));
refreshList.add(aa);
More bb = new More(getRandomLengthName("wwww"));
refreshList.add(bb);
More cc = new More(getRandomLengthName("pppp"));
refreshList.add(cc);
More dd = new More(getRandomLengthName("llll"));
refreshList.add(dd);
More ee = new More(getRandomLengthName("oooo"));
refreshList.add(ee);
More ff = new More(getRandomLengthName("uuuu"));
refreshList.add(ff);
More gg = new More(getRandomLengthName("yyyy"));
refreshList.add(gg);
}
//由于需装入尾部,所以以moreList为主,需返回装载结果来判断是否加载成功
boolean a = refreshList.addAll(moreList);
//注意数据添加数据的方式,不能直接=,要先将原数组清空,再添加
moreList.clear();
moreList.addAll(refreshList);
return a;
}
/**
* 根据name产生随机长度的字符串
*
* @param name 母字符串
* @return 加长版的字符串
*/
private String getRandomLengthName(String name) {
Random random = new Random();
int length = random.nextInt(20) + 1; // 产生1-20的随机数
StringBuilder builder = new StringBuilder();//此处有StringBuilder和StringBuffer类可用,两者都可append数据,前者更快,后者是同步的 即线程安全
for (int i = 0; i < length; i++) {
builder.append(name);
}
return builder.toString();//添加完成后需转换为字符串
}
}
layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".more.MoretestActivity">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
创建adapter及recyclerView所使用的样式layout及数据类
adapter
package com.example.test.more;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import com.example.test.R;
import java.util.List;
public class MoreAdapter extends RecyclerView.Adapter<MoreAdapter.ViewHolder> {
private List<More> moreList;
static class ViewHolder extends RecyclerView.ViewHolder {
View moreView;
TextView moreName;
ViewHolder(View view) {
super(view);
moreView = view;
moreName = (TextView) view.findViewById(R.id.morename);
}
}
MoreAdapter(List<More> fruitList) {
moreList = fruitList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.more_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.moreView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
More fruit = moreList.get(position);
Toast.makeText(view.getContext(), "you clicked view" + fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
//此处留该部分注释掉代码是说明在recyclerView中,同一块view内的不同控件可以设置不同的点击事件,于本次测试并没什么卵用
// holder.fruitImage.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// int position = holder.getAdapterPosition();
// Fruit fruit = mFruitList.get(position);
// Toast.makeText(view.getContext(), "you clicked image" + fruit.getName(), Toast.LENGTH_SHORT).show();
// }
// });
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
More more = moreList.get(position);
holder.moreName.setText(more.getName());
}
@Override
public int getItemCount() {
return moreList.size();
}
//数据改变后刷新数据
void dataChange() {
// 刷新全部可见的item,notifyDataSetChanged()
// 刷新指定item,notifyItemChanged(int)
// 从指定位置开始刷新指定个item,notifyItemRangeChanged(int,int)
// 插入、移动一个并自动刷新,notifyItemInserted(int)、notifyItemMoved(int)、notifyItemRemoved(int)
// 局部刷新,notifyItemChanged(int, Object)
notifyDataSetChanged();
}
}
样式layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#419991"
android:id="@+id/morename"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginStart="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_10"/>
</LinearLayout>
数据类
package com.example.test.more;
public class More {
private String name;
public String getName() {
return name;
}
public More(String name){
this.name = name;
}
}
完工!关于文件名和注意事项我都已经写在代码注释中啦,告辞!