public class MyRecycleview extends RelativeLayout implements View.OnTouchListener {
private int touchSlop;//判断为滚动的最小距离
private MarginLayoutParams headparams;//顶部布局管理器
private MarginLayoutParams bottomparams;//底部部布局管理器
private LayoutParams params, bparams;//设置布局摆放位置的容器
private View headview; //顶部布局文件
private View bottomview;//底部布局文件
private int startTop;//顶部布局初始偏移量
private int startBot;//底部布局初始偏移量
private Boolean once = true; //设置onLayout执行一次的标志位
private boolean cantopull = true;//判断当前是否可以执行下拉操作
private boolean cantopullUp = false;//判断当前是否可以执行上拉操作
private Boolean isMoving = false;//标志是否正在下拉;
private RecyclerView mrecyclerView;
private LinearLayoutManager mlinearlayoutmanager;
private int Ydwon, Ymove, distance;//记录手指触摸及移动时相对应的Y的坐标值
private int currentMarg; //头部布局当前的偏移量
private Boolean canRefresh = false; //标志是否下拉到了刷新的位置
private RefreshListener listener; //监听回调的内部接口
private int status = 0;//当前状态
private TextView head_text, bottom_text;//顶部和底部的文字
public MyRecycleview(Context context) {
this(context, null);
}
public MyRecycleview(Context context, AttributeSet attrs) {
super(context, attrs);
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
//拿到顶部布局
headview = LayoutInflater.from(context).inflate(R.layout.myrecycleview_headview, null, false);
head_text = (TextView) headview.findViewById(R.id.pullText);
//设置为屏幕水平居中
params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL, TRUE);
addView(headview, params);
headparams = (MarginLayoutParams) headview.getLayoutParams();
bottomview = LayoutInflater.from(context).inflate(R.layout.mrecycleview_bottom, null, false);
bottom_text = (TextView) bottomview.findViewById(R.id.bottom_text);
bparams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//设置为居父类布局的底部
bparams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, TRUE);
addView(bottomview, bparams);
bottomparams = (MarginLayoutParams) bottomview.getLayoutParams();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed && once) {
once = false;
startTop = headview.getHeight();
headparams.topMargin = -startTop;
headview.setLayoutParams(headparams);
startBot = bottomview.getHeight();
bottomparams.bottomMargin = -startBot;
bottomview.setLayoutParams(bottomparams);
mrecyclerView = (RecyclerView) getChildAt(2);
mrecyclerView.setOnTouchListener(this);
}
} //对recycleview进行事件监听
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//判断是否可进行下滑
isenableToPull();
if (cantopull) {
//如果可以下拉
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
Ydwon = (int) motionEvent.getRawY();
break;
case MotionEvent.ACTION_MOVE:
Ymove = (int) motionEvent.getRawY();
distance = Ymove - Ydwon;
if (distance > 20 && status != 1) {
//满足下拉条件
currentMarg = -startTop + distance / 3;
status = 2;//正在下拉状态
//如果是处于下拉,或者下拉到了最底部,则需要刷新下拉头的文字信息
head_text.setText("下拉加载更多");
if (currentMarg > startTop) { canRefresh = true; currentMarg = startTop; status = 4;//松开即可刷新
head_text.setText("松开刷新");
}
//正在滑动,不允许判断是否到达顶部
isMoving = true;
headparams.topMargin = currentMarg;
headview.setLayoutParams(headparams);
} else {
return false;
}
break;
case MotionEvent.ACTION_UP:
if (canRefresh) {
// 顶部布局回弹至上方
new ToprefreshTask().execute(-30);
} else {
//隐藏顶部布局
new HideTop().execute(-30);
}
//判断滑动结束,可以再次判断是否到达顶部
isMoving = false;//下拉结束
break;
}
//这里是底部上拉加载的模块,原理几乎和顶部下拉加载一样,就没过多实现
else if (cantopullUp) {
//可以模仿着下拉刷新实现,只是下拉变成了上拉,我相信你肯定能ok的
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
}
return false;
}
//判断是否滑到顶部,或者底部
private void isenableToPull() {
mrecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (!recyclerView.canScrollVertically(-1)) {
//滑动到了顶部可以下拉
cantopull = true;
cantopullUp = false;
} else if (!recyclerView.canScrollVertically(1)) {
//滑动到了底部,可以上拉
cantopull = false;
cantopullUp = true;
} else {
/**
*ismoving是判断当在下拉时,列表滚动到了不是顶部的位置,这时,顶部布局就无法复原了,
* 这里加个标志位,当手指还在拖拽下拉条时,返回当前是否到达顶部,当手指松开屏幕时,ismoving
* 变为FALSE,回到初始状态,可以判断是否到达顶部了;
*/
if (!isMoving) {
cantopull = false;
cantopullUp = false;
}
}
}
});
}
//头部下拉到进行刷新时调用
class ToprefreshTask extends AsyncTask<Integer, Integer, Integer> {
@Override
protected Integer doInBackground(Integer... integers) {
int topmarg = headparams.topMargin;
while (true) {
topmarg = topmarg + integers[0];
;
//当回到顶部时,跳出
if (topmarg <= 0) {
topmarg = 0;
break;
}
publishProgress(topmarg);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
publishProgress(0);
status = 1;
if (listener != null) {
listener.Refresh();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
headparams.topMargin = values[0];
headview.setLayoutParams(headparams);
}
}
//隐藏头部的布局文件
class HideTop extends AsyncTask<Integer, Integer, Integer> {
@Override
protected Integer doInBackground(Integer... integers) {
int topmarg = headparams.topMargin;
while (true) {
topmarg = topmarg + integers[0];
//当回到顶部时,跳出
if (topmarg <= -startTop) {
topmarg = -startTop;
break;
}
publishProgress(topmarg);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
publishProgress(-startTop);
return topmarg;
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
headparams.topMargin = integer;
headview.setLayoutParams(headparams);
canRefresh = false;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
headparams.topMargin = values[0];
headview.setLayoutParams(headparams);
}
}
//设置外部调用的的方法
public void setRefreshListener(RefreshListener listener) {
this.listener = listener;
}
//设置外部的监听回调接口
public interface RefreshListener {
void Refresh();
}
public void FinishRefresh()
{
new HideTop().execute(-30);
status = 3;//下拉刷新结束状态;
}
}
//上边,需要自定义一个顶部布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="100dp"
>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_toRightOf="@+id/pullText"
android:background="@drawable/head_backview"/>
<TextView
android:layout_centerVertical="true"
android:id="@+id/pullText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"/>
</RelativeLayout>
//最后在主布局里面添加该自定义的view
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.test.demo.view.MyRecycleview
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/myrecycleview">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyclew"/>
</com.example.test.demo.view.MyRecycleview>
</LinearLayout>
//在代码中进行初始化,和下拉监听
myRecycleview.setRefreshListener(new MyRecycleview.RefreshListener() {
@Override
public void Refresh() {
//这里用个延时,模拟向服务器请求数据
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
myRecycleview.FinishRefresh();
}
});
}