github地址:https://github.com/tslearner/SwipeToLoadLayout
下拉刷新动画:箭头 和最后更新时间
配置:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
dependencies {
compile 'com.github.Aspsine:SwipeToLoadLayout:1.0.3'
}
MainActivity:
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List list;
MyAdapter myAdapter;
SwipeToLoadLayout swipeToLoadLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
swipeToLoadLayout=(SwipeToLoadLayout)findViewById(R.id.swipeToLoad);
recyclerView=(RecyclerView)findViewById(R.id.swipe_target);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add("原始数据");
}
myAdapter = new MyAdapter(this,list);
//为recyclerView设置适配器
recyclerView.setAdapter(myAdapter);
//为swipeToLoadLayout设置下拉刷新监听者
swipeToLoadLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
for (int i = 0; i < 20; i++) {
list.add(0,"刷新获得的数据");
}
myAdapter.notifyDataSetChanged();
//设置下拉刷新结束
swipeToLoadLayout.setRefreshing(false);
}
});
//为swipeToLoadLayout设置上拉加载更多监听者
swipeToLoadLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
for (int i = 0; i < 20; i++) {
list.add("加载更多获得的数据");
}
myAdapter.notifyDataSetChanged();
//设置上拉加载更多结束
swipeToLoadLayout.setLoadingMore(false);
}
});
}
}
MyAdapter:
public class MyAdapter extends RecyclerView.Adapter {
List list;
public MyAdapter(Context context, List data) {
super();
list=data;
}
@Override
public int getItemCount() {
return list.size();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
String a=(String)list.get(position);
holder.tv.setText(a);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public ViewHolder(View v) {
super(v);
tv = (TextView) v.findViewById(R.id.text);
}
}
}
布局:
item.xml:
LoadMoreFooterView:
public class LoadMoreFooterView extends TextView implements SwipeTrigger, SwipeLoadMoreTrigger {
public LoadMoreFooterView(Context context) {
super(context);
}
public LoadMoreFooterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onLoadMore() {
setText("LOADING MORE");
}
@Override
public void onPrepare() {
setText("");
}
@Override
public void onMove(int yScrolled, boolean isComplete, boolean automatic) {
if (!isComplete) {
if (yScrolled <= -getHeight()) {
setText("RELEASE TO LOAD MORE");
} else {
setText("SWIPE TO LOAD MORE");
}
} else {
setText("LOAD MORE RETURNING");
}
}
@Override
public void onRelease() {
setText("LOADING MORE");
}
@Override
public void onComplete() {
setText("COMPLETE");
}
@Override
public void onReset() {
setText("");
}
}
RefreshHeaderView:
public class RefreshHeaderView extends TextView implements SwipeRefreshTrigger, SwipeTrigger {
public RefreshHeaderView(Context context) {
super(context);
}
public RefreshHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onRefresh() {
setText("REFRESHING");
}
@Override
public void onPrepare() {
setText("");
}
@Override
public void onMove(int yScrolled, boolean isComplete, boolean automatic) {
if (!isComplete) {
if (yScrolled >= getHeight()) {
setText("RELEASE TO REFRESH");
} else {
setText("SWIPE TO REFRESH");
}
} else {
setText("REFRESH RETURNING");
}
}
@Override
public void onRelease() {
}
@Override
public void onComplete() {
setText("COMPLETE");
}
@Override
public void onReset() {
setText("");
}
}
修改RefreshHeaderView样式;
public class RefreshHeaderView extends LinearLayout implements SwipeRefreshTrigger, SwipeTrigger {
String TAG="RefreshHeaderView";
private Context mContext;
private TextView tv;
private RoundProgressBar mRoundProgressBar;
public RefreshHeaderView(Context context) {
super(context);
init(context);
}
public RefreshHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void init(Context context){
mContext=context;
LayoutInflater.from(context).inflate(R.layout.refresh_header, this);
}
@Override
protected void onFinishInflate() {
Log.d(TAG, "onFinishInflate: ");
super.onFinishInflate();
initView();
}
public void initView(){
tv=(TextView)findViewById(R.id.text);
mRoundProgressBar=(RoundProgressBar)findViewById(R.id.roundProgressBar2);
mRoundProgressBar.setMax(100);
mRoundProgressBar.setProgress(80);
}
@Override
public void onRefresh() {
Log.d(TAG, "onRefresh: ");
tv.setText("正在刷新数据中");
}
@Override
public void onPrepare() {
Log.d(TAG, "onPrepare: ");
tv.setText("下拉后刷新");
}
@Override
public void onMove(int yScrolled, boolean isComplete, boolean automatic) {
if (!isComplete) {
if (yScrolled >= getHeight()) {
tv.setText("释放立即刷新");
} else {
tv.setText("下拉后刷新");
}
} /*else {
tv.setText("REFRESH RETURNING");
}*/
}
@Override
public void onRelease() {
Log.d(TAG, "onRelease: ");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete: ");
tv.setText("完成刷新");
}
@Override
public void onReset() {
Log.d(TAG, "onReset: ");
tv.setText("");
}
}
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
android:layout_width="50dip"
android:layout_height="50dip"
android_custom:roundColor="#D1D1D1"
android_custom:roundProgressColor="@android:color/black"
android_custom:textColor="#9A32CD"
android_custom:textIsDisplayable="false"
android_custom:roundWidth="4dip"
android_custom:textSize="18sp"/>
android:layout_height="wrap_content"
android:id="@+id/text"
android:text=""
android:layout_gravity="center_vertical"/>
public class RoundProgressBar extends View {
/**
* 画笔对象的引用
*/
private Paint paint;
/**
* 圆环的颜色
*/
private int roundColor;
/**
* 圆环进度的颜色
*/
private int roundProgressColor;
/**
* 中间进度百分比的字符串的颜色
*/
private int textColor;
/**
* 中间进度百分比的字符串的字体
*/
private float textSize;
/**
* 圆环的宽度
*/
private float roundWidth;
/**
* 最大进度
*/
private int max;
/**
* 当前进度
*/
private int progress;
/**
* 是否显示中间的进度
*/
private boolean textIsDisplayable;
/**
* 进度的风格,实心或者空心
*/
private int style;
public static final int STROKE = 0;
public static final int FILL = 1;
public RoundProgressBar(Context context) {
this(context, null);
}
public RoundProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
TypedArray mTypedArray = getContext().obtainStyledAttributes(attrs,
R.styleable.RoundProgressBar);
//获取自定义属性和默认值
roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor, Color.RED);
roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, Color.GREEN);
textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, Color.GREEN);
textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 15);
roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 5);
max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100);
textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true);
style = mTypedArray.getInt(R.styleable.RoundProgressBar_style, 0);
mTypedArray.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 画最外层的大圆环
*/
int centre = getWidth()/2; //获取圆心的x坐标
int radius = (int) (centre - roundWidth/2); //圆环的半径
paint.setColor(roundColor); //设置圆环的颜色
paint.setStyle(Paint.Style.STROKE); //设置空心
paint.setStrokeWidth(roundWidth); //设置圆环的宽度
paint.setAntiAlias(true); //消除锯齿
canvas.drawCircle(centre, centre, radius, paint); //画出圆环
Log.e("log", centre + "");
/**
* 画进度百分比
*/
paint.setStrokeWidth(0);
paint.setColor(textColor);
paint.setTextSize(textSize);
paint.setTypeface(Typeface.DEFAULT_BOLD); //设置字体
int percent = (int)(((float)progress / (float)max) * 100); //中间的进度百分比,先转换成float在进行除法运算,不然都为0
float textWidth = paint.measureText(percent + "%"); //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
if(textIsDisplayable && percent != 0 && style == STROKE){
canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize/2, paint); //画出进度百分比
}
/**
* 画圆弧 ,画圆环的进度
*/
//设置进度是实心还是空心
paint.setStrokeWidth(roundWidth); //设置圆环的宽度
paint.setColor(roundProgressColor); //设置进度的颜色
RectF oval = new RectF(centre - radius, centre - radius, centre
+ radius, centre + radius); //用于定义的圆弧的形状和大小的界限
switch (style) {
case STROKE:{
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(oval, 0, 360 * progress / max, false, paint); //根据进度画圆弧
break;
}
case FILL:{
paint.setStyle(Paint.Style.FILL_AND_STROKE);
if(progress !=0)
canvas.drawArc(oval, 0, 360 * progress / max, true, paint); //根据进度画圆弧
break;
}
}
}
public synchronized int getMax() {
return max;
}
/**
* 设置进度的最大值
* @param max
*/
public synchronized void setMax(int max) {
if(max < 0){
throw new IllegalArgumentException("max not less than 0");
}
this.max = max;
}
/**
* 获取进度.需要同步
* @return
*/
public synchronized int getProgress() {
return progress;
}
/**
* 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
* 刷新界面调用postInvalidate()能在非UI线程刷新
* @param progress
*/
public synchronized void setProgress(int progress) {
if(progress < 0){
throw new IllegalArgumentException("progress not less than 0");
}
if(progress > max){
progress = max;
}
if(progress <= max){
this.progress = progress;
postInvalidate();
}
}
public int getCricleColor() {
return roundColor;
}
public void setCricleColor(int cricleColor) {
this.roundColor = cricleColor;
}
public int getCricleProgressColor() {
return roundProgressColor;
}
public void setCricleProgressColor(int cricleProgressColor) {
this.roundProgressColor = cricleProgressColor;
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
}
public float getTextSize() {
return textSize;
}
public void setTextSize(float textSize) {
this.textSize = textSize;
}
public float getRoundWidth() {
return roundWidth;
}
public void setRoundWidth(float roundWidth) {
this.roundWidth = roundWidth;
}
}
SwipeToLoadLayout常用属性:
app:refresh_enabled:设置是否可以下拉刷新
app:load_more_enabled:设置是否可以上拉加载更多
app:swipe_style:设置下拉刷新与上拉加载的样式,其值为classic,above,blew或scale
app:refresh_trigger_offset:触发下拉刷新的偏移量,默认值是下拉刷新头部的高度
app:load_more_trigger_offset:触发上拉加载更多的偏移量,默认值是上拉加载更多的高度
app:refresh_final_drag_offset:下拉刷新最大可以拖动的偏移量
app:load_more_final_drag_offset:上拉加载更多最大可以拖动的偏移量
app:release_to_refreshing_scrolling_duration:释放下拉刷新持续滚动的时间
app:release_to_loading_more_scrolling_duration:释放上拉加载更多持续滚动的时间
app:refresh_complete_delay_duration:下拉刷新完成延迟的持续时间
app:load_more_complete_delay_duration:上拉加载更多完成延迟的持续时间
app:refresh_complete_to_default_scrolling_duration:默认完成下拉刷新持续滚动时间
app:load_more_complete_to_default_scrolling_duration: 默认完成上拉加载更多持续滚动时间
app:default_to_refreshing_scrolling_duration:默认下拉刷新滚动时间
app:default_to_loading_more_scrolling_duration:默认上拉加载更多滚动时间