SwipeRefreshLayout是google官方下拉刷新组件,俗称“彩虹条”。
SwipeRefreshLayout组件只接受一个子组件:即需要刷新的那个组件。(其实通过文档我们可以知道SwipeRefreshLayout只不过是继承了ViewGroup。),但是这个组件只支持下拉刷新,不支持上拉加载更多的操作。因此,需要简单的扩展一下这个组件以实现上拉下载的目的。
SwipRefreshLayout中的重要方法,具体如下:
1、setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener):设置手势滑动监听器。
2、setProgressBackgroundColor(int colorRes):设置进度圈的背景色。
3、setColorSchemeResources(int… colorResIds):设置进度动画的颜色。 //加载颜色是循环播放的,只要没有完成刷新就会一直循环
4、setRefreshing(Boolean refreshing):设置组件的刷洗状态。
5、setSize(int size):设置进度圈的大小,只有两个值:DEFAULT、LARGE
简单的实现:
layout
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_widget"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#ffff0000"
android:dividerHeight="10dp"/>
</android.support.v4.widget.SwipeRefreshLayout>
注意:首先须把你的support library的版本升级到19.1或更新
activity 中核心代码
private Handler handler = new Handler(){//模拟网络请求结束
@Override
public void handleMessage(Message msg) {
mSwipeRefreshWidget.setRefreshing(false);
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
//下拉刷新控件
mSwipeRefreshWidget = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget);
// mSwipeRefreshWidget.setColorScheme(R.color.color1, R.color.color2, R.color.color3, R.color.color4);//设置进度条颜色
// 这句话是为了,第一次进入页面的时候显示加载进度条
mSwipeRefreshWidget.setProgressViewOffset(false, 0, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()));
mSwipeRefreshWidget.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {//下拉刷新监听事件
@Override
public void onRefresh() {
// 此处在现实项目中,请换成网络请求数据代码,sendRequest .....
mSwipeRefreshWidget.setRefreshing(true);
handler.sendEmptyMessageDelayed(0, 3000);
}
});
//RecyclerView 控件,用来代替listview的新控件
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
//LinearLayoutManager 现行管理器,支持横向、纵向。
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//设置横向滚动
mRecyclerView.setLayoutManager(layoutManager);
//设置Item增加、移除的动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割线(该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况。方便我们去随意的改变)
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
//设置adapter
mAdapter = new HomeAdapter(this, mDatas);
mAdapter.setOnItemClickLitener(new HomeAdapter.OnItemClickLitener()
{
@Override
public void onItemClick(View view, int position)
{
Toast.makeText(MainActivity.this, position + " click",
Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position)
{
Toast.makeText(MainActivity.this, position + " long click",
Toast.LENGTH_SHORT).show();
mAdapter.removeData(position);
}
});
mRecyclerView.setAdapter(mAdapter);
//mRecyclerView滚动监听事件,用来触发上拉加载事件
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView,
int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& lastVisibleItem + 1 == mAdapter.getItemCount()) {
mSwipeRefreshWidget.setRefreshing(true);
// 此处在现实项目中,请换成网络请求数据代码,sendRequest .....
handler.sendEmptyMessageDelayed(0, 3000);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = layoutManager.findLastVisibleItemPosition();
}
});
}
/**
* 初始化数据
*/
protected void initData()
{
mDatas = new ArrayList<String>();
for (int i = 'A'; i < 'z'; i++)
{
mDatas.add("" + (char) i);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.menu_main, menu);
inboxMenuItem = menu.findItem(R.id.id_action_add);
inboxMenuItem.setActionView(R.layout.menu_item_view);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.id_action_add:
mAdapter.addData(1);
break;
case R.id.id_action_delete:
mAdapter.removeData(1);
break;
}
return true;
}
}
adapter
package com.heshidai.recyclerviewdemo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
/**
* @author wankun
* @desc
* @date 2015/12/4 13:50
*/
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> {
private Context mContext;
private List<String> data;
public HomeAdapter(Context mContext, List<String> data) {
this.mContext = mContext;
this.data = data;
}
public interface OnItemClickLitener
{
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
private OnItemClickLitener mOnItemClickLitener;
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
{
this.mOnItemClickLitener = mOnItemClickLitener;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(mContext).inflate(R.layout.item_home, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position)
{
holder.tv.setText(data.get(position));
// holder.mView.setLayoutParams(new ViewGroup.LayoutParams((200 + ((position*position)%5) * 200), (200 + ((position*position)%5) * 200)));
// 如果设置了回调,则设置点击事件
if (mOnItemClickLitener != null)
{
holder.itemView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.itemView, pos);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View v)
{
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
@Override
public int getItemCount()
{
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder
{
View mView;
TextView tv;
public MyViewHolder(View view)
{
super(view);
mView = view;
tv = (TextView) view.findViewById(R.id.id_num);
}
}
public void addData(int position) {
data.add(position, "Insert One");
notifyItemInserted(position);//注意这里不是adapter.notifyDataSetChanged()
}
public void removeData(int position) {
data.remove(position);
notifyItemRemoved(position);//注意这里不是adapter.notifyDataSetChanged()
}
}
这里 mSwipeRefreshWidget.setOnRefreshListener()方法中监听下拉动作,触发刷新时间( 在通过handler 来模拟网络请求,结束下拉刷新)又通过mRecyclerView滚动监听事件,判断最后一个item是否完全显示,用来触发上拉加载事件。
其中,在handler消息接收方法中调用 mSwipeRefreshWidget.setRefreshing(false),结束等待动画
在mRecyclerView滚动监听事件中调用mSwipeRefreshWidget.setRefreshing(true)开启等待动画,并调刷新方法。
通过源码我们发现SwipeRefreshLayout中的两个重要的属性:
private MaterialProgressDrawable mProgress;
private CircleImageView mCircleView;
这两个属性正是用于实现进度动画效果的,在方法createProgressView中,我们看到mCircleView最终加入到了SwipeRefreshLayout中。
private void createProgressView() {
mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT, CIRCLE_DIAMETER/2);
mProgress = new MaterialProgressDrawable(getContext(), this);
mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);
mCircleView.setImageDrawable(mProgress);
mCircleView.setVisibility(View.GONE);
addView(mCircleView);
}
同时我们也可以查看到CirlceImageView继承了ImageView,MaterialProgressDrawabel继承了Drawable 。源码:
class CircleImageView extends ImageView
class MaterialProgressDrawable extends Drawable implements Animatable