转载:【江清清的博客】
目录
SwipeRefrshLayout
Google官方更新的一个Widget,可以实现下拉刷新的效果。
setOnRefreshListener(OnRefreshListener):添加下拉刷新监听器
setRefreshing(boolean):显示或者隐藏刷新进度条
isRefreshing():检查是否处于刷新状态
setColorSchemeResources():设置进度条的颜色主题,最多设置四种,以前的setColorScheme()方法已经弃用了。
RecyclerView+SwpieRefreshLayout实现下拉刷新效果
布局文件
<?xmlversion="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"android:layout_width="match_parent"
android:layout_height="match_parent">
<includelayout="@layout/common_top_bar_layout"/>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/demo_swiperefreshlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="vertical"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/demo_recycler"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
></android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
onRefresh()
在Activity中获取SwipeRefreshLayout控件并且设置OnRefreshListener监听器,同时实现里边的onRefresh()方法,在该方法中进行网络请求最新数据,然后刷新RecyclerView列表同时设置SwipeRefreshLayout的进度Bar的隐藏或者显示效果。
demo_swiperefreshlayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
Log.d("zttjiangqq","invoke onRefresh...");
new Handler().postDelayed(newRunnable() {
@Override
public void run() {
List<String> newDatas = new ArrayList<String>();
for (int i = 0; i <5; i++) {
int index = i + 1;
newDatas.add("new item" + index);
}
adapter.addItem(newDatas);
demo_swiperefreshlayout.setRefreshing(false);
Toast.makeText(RecyclerRefreshActivity.this, "更新了五条数据...", Toast.LENGTH_SHORT).show();
}
}, 5000);
}
});
RecyclerView.Adapter
public class RefreshRecyclerAdapter extends RecyclerView.Adapter<RefreshRecyclerAdapter.ViewHolder>{
private LayoutInflater mInflater;
private List<String> mTitles=null;
public RefreshRecyclerAdapter(Context context){
this.mInflater=LayoutInflater.from(context);
this.mTitles=new ArrayList<String>();
for (int i=0;i<20;i++){
int index=i+1;
mTitles.add("item"+index);
}
}
/**
* item显示类型
* @param parent
* @param viewType
* @return
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final Viewview=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
//这边可以做一些属性设置,甚至事件监听绑定
//view.setBackgroundColor(Color.RED);
ViewHolder viewHolder=new ViewHolder(view);
return viewHolder;
}
/**
* 数据的绑定显示
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.item_tv.setText(mTitles.get(position));
holder.itemView.setTag(position);
}
@Override
public int getItemCount() {
return mTitles.size();
}
//自定义的ViewHolder,持有每个Item的的所有界面元素
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView item_tv;
public ViewHolder(View view){
super(view);
item_tv = (TextView)view.findViewById(R.id.item_tv);
}
}
//添加数据
public void addItem(List<String> newDatas) {
//mTitles.add(position, data);
//notifyItemInserted(position);
newDatas.addAll(mTitles);
mTitles.removeAll(mTitles);
mTitles.addAll(newDatas);
notifyDataSetChanged();
}
public void addMoreItem(List<String> newDatas) {
mTitles.addAll(newDatas);
notifyDataSetChanged();
}
}
RecyclerView设置滚动事件加入上拉加载
LayoutManger给我们提供了以下几个方法来让开发者方便的获取到屏幕上面的顶部item和顶部item相关的信息:
findFirstVisibleItemPosition()
findFirstCompletlyVisibleItemPosition()
findLastVisibleItemPosition()
findLastCompletlyVisibleItemPosition()
setOnScrollListener
通过监听滑动(滚动)事件,然后在里边判断是否已经滑动到最底部来加载更多的数据
//RecyclerView滑动监听
demo_recycler.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState ==RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 ==adapter.getItemCount()) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
List<String> newDatas = new ArrayList<String>();
for (int i = 0; i< 5; i++) {
int index = i +1;
newDatas.add("more item" + index);
}
adapter.addMoreItem(newDatas);
}
},1000);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView,dx, dy);
lastVisibleItem =linearLayoutManager.findLastVisibleItemPosition();
}
});
RecyclerView加入FootView实现上拉加载
让用户知道确实在上拉加载的过程吧,例如加载一个底部的进度布局。这样一想,那么我们就按照ListView方式addFootView()呗,不过很可惜的是RecyclerView没有给我们提供addFootView(),有一个getItemViewType()返回是普通item还是底部刷新item
布局状态标志
加入布局状态标志-用来判断此时加载是普通Item还是foot view:
private static final int TYPE_ITEM =0; // 普通Item View
private static final intTYPE_FOOTER = 1; // 底部FootView
getItemCount()
重写getItemCount()方法,返回的Item数量在数据的基础上面+1,增加一项FootView布局项
public int getItemCount() {
return mTitles.size()+1;
}
getItemViewType
public int getItemViewType(int position) {
// 最后一个item设置为footerView
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
onCreateViewHolder
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//进行判断显示类型,来创建返回不同的View
if(viewType==TYPE_ITEM){
Viewview=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
//这边可以做一些属性设置,甚至事件监听绑定
//view.setBackgroundColor(Color.RED);
ItemViewHolder itemViewHolder=new ItemViewHolder(view);
return itemViewHolder;
}else if(viewType==TYPE_FOOTER){
Viewfoot_view=mInflater.inflate(R.layout.recycler_load_more_layout,parent,false);
//这边可以做一些属性设置,甚至事件监听绑定
//view.setBackgroundColor(Color.RED);
FootViewHolder footViewHolder=new FootViewHolder(foot_view);
return footViewHolder;
}
return null;
}
onBindViewHolder
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(holder instanceof ItemViewHolder) {
((ItemViewHolder)holder).item_tv.setText(mTitles.get(position));
holder.itemView.setTag(position);
}else if(holder instanceof FootViewHolder){
FootViewHolderfootViewHolder=(FootViewHolder)holder;
switch (load_more_status){
case PULLUP_LOAD_MORE:
footViewHolder.foot_view_item_tv.setText("上拉加载更多...");
break;
case LOADING_MORE:
footViewHolder.foot_view_item_tv.setText("正在加载更多数据...");
break;
}
}
}
RefreshFoot Adapter
packagecom.chinaztt.fda.adapter;
public class RefreshFootAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
//上拉加载更多
public static final int PULLUP_LOAD_MORE=0;
//正在加载中
public static final int LOADING_MORE=1;
//上拉加载更多状态-默认为0
private int load_more_status=0;
private LayoutInflater mInflater;
private List<String> mTitles=null;
private static final intTYPE_ITEM = 0; //普通Item View
private static final intTYPE_FOOTER = 1; //顶部FootView
public RefreshFootAdapter(Context context){
this.mInflater=LayoutInflater.from(context);
this.mTitles=new ArrayList<String>();
for (int i=0;i<20;i++){
int index=i+1;
mTitles.add("item"+index);
}
}
/**
* item显示类型
* @param parent
* @param viewType
* @return
*/
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//进行判断显示类型,来创建返回不同的View
if(viewType==TYPE_ITEM){
Viewview=mInflater.inflate(R.layout.item_recycler_layout,parent,false);
//这边可以做一些属性设置,甚至事件监听绑定
//view.setBackgroundColor(Color.RED);
ItemViewHolder itemViewHolder=new ItemViewHolder(view);
return itemViewHolder;
}else if(viewType==TYPE_FOOTER){
Viewfoot_view=mInflater.inflate(R.layout.recycler_load_more_layout,parent,false);
//这边可以做一些属性设置,甚至事件监听绑定
//view.setBackgroundColor(Color.RED);
FootViewHolder footViewHolder=new FootViewHolder(foot_view);
return footViewHolder;
}
return null;
}
/**
* 数据的绑定显示
* @param holder
* @param position
*/
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(holder instanceof ItemViewHolder) {
((ItemViewHolder)holder).item_tv.setText(mTitles.get(position));
holder.itemView.setTag(position);
}else if(holder instanceof FootViewHolder){
FootViewHolder footViewHolder=(FootViewHolder)holder;
switch (load_more_status){
case PULLUP_LOAD_MORE:
footViewHolder.foot_view_item_tv.setText("上拉加载更多...");
break;
case LOADING_MORE:
footViewHolder.foot_view_item_tv.setText("正在加载更多数据...");
break;
}
}
}
/**
* 进行判断是普通Item视图还是FootView视图
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
// 最后一个item设置为footerView
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
@Override
public int getItemCount() {
return mTitles.size()+1;
}
//自定义的ViewHolder,持有每个Item的的所有界面元素
public static class ItemViewHolder extends RecyclerView.ViewHolder {
public TextView item_tv;
public ItemViewHolder(View view){
super(view);
item_tv = (TextView)view.findViewById(R.id.item_tv);
}
}
/**
* 底部FootView布局
*/
public static class FootViewHolder extends RecyclerView.ViewHolder{
private TextView foot_view_item_tv;
public FootViewHolder(View view) {
super(view);
foot_view_item_tv=(TextView)view.findViewById(R.id.foot_view_item_tv);
}
}
//添加数据
public void addItem(List<String> newDatas) {
//mTitles.add(position, data);
//notifyItemInserted(position);
newDatas.addAll(mTitles);
mTitles.removeAll(mTitles);
mTitles.addAll(newDatas);
notifyDataSetChanged();
}
public void addMoreItem(List<String> newDatas) {
mTitles.addAll(newDatas);
notifyDataSetChanged();
}
/**
* //上拉加载更多
* PULLUP_LOAD_MORE=0;
* //正在加载中
* LOADING_MORE=1;
* //加载完成已经没有更多数据了
* NO_MORE_DATA=2;
* @param status
*/
public void changeMoreStatus(int status){
load_more_status=status;
notifyDataSetChanged();
}
}
setOnScrollListener
Adaper中我还定义一个changeMoreStatus()方法和两个字符串常量可以来进行修改FootView中字符串提醒文本的。
整体Activity中还是设置监听RecyclerView的滚动事件.
demo_recycler.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState ==RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 ==adapter.getItemCount()) {
adapter.changeMoreStatus(RefreshFootAdapter.LOADING_MORE);
newHandler().postDelayed(new Runnable() {
@Override
public void run() {
List<String> newDatas = new ArrayList<String>();
for (int i = 0; i< 5; i++) {
int index = i +1;
newDatas.add("more item" + index);
}
adapter.addMoreItem(newDatas);
adapter.changeMoreStatus(RefreshFootAdapter.PULLUP_LOAD_MORE);
}
}, 2500);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView,dx, dy);
lastVisibleItem =linearLayoutManager.findLastVisibleItemPosition();
}
});
SwipeRefreshLayout 、RecyclerView冲突下拉冲突的解决方案
出现RecyclerView没有滑动到顶部,手指向下滑动时,触发了SwipeRefreshLayout的刷新事件,造成了冲突。
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int topRowVerticalPosition =
(recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
RecyclerView与ScrollView滑动冲突问题
参考文章:
【Android 手势冲突】Colin带你彻底解决RecyclerView与ScrollView滑动冲突问题,并实现RecyclerView悬停导航栏(附demo哦)
实现原理
在进到页面中默认把滑动事件交给ScrollView,同时屏蔽RecyclerView的滑动事件;在RecyclerView滑动到顶部的时候,把滑动事件交给RecyclerView。
判断RecyclerView是否滑动到了屏幕顶部了呢?通过recyclerview的getTop方法得到recyclerview距离顶部的距离,然后通过scrollView的getScrollY方法得到ScrollView滑动的距离,只需要比较这两个值。
解决滑动冲突需要知道view传递
如何把事件传给内部View?
只需要在ScrollView滑动到某个位置后 getScrollY() >= recyclerView.getChildAt(0).getTop();
使用接口回调,并且让RecyclerView在接口回调里,getParent().requestdisallowintercept()。
RecyclerView如何把事件传给外部?
需要给RecyclerView设置ontouchlistener,然后在RecyclerView滑动到第一个item recyclerView.getChildAt(0).getTop()<=0;
并且正在向下滑动时,requestdisallowintercept(false)来让ScrollView拦截。
外部拦截法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch(ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//必须返回false,否则子控件永远无法拿到焦点
return false;
case MotionEvent.ACTION_MOVE:
if(事件交给子控件的条件) {
return false;
} else {
return super.onInterceptTouchEvent(ev);
}
case MotionEvent.ACTION_UP:
//必须返回false,否则子控件永远无法拿到焦点
return false;
default:
return super.onInterceptTouchEvent(ev);
}
}
内部拦截法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch(ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//父容器禁止拦截
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if(事件交给父容器的条件) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}