最近项目已经接近尾声了,由于一些原因,我可能又要找新的工作了,啊啊啊,有点忧伤。
之前有在新浪写过一写博客,现在准备在CSDN上写博客了,CSDN博客-最大IT写作分享平台,很多资料都可以在这找到,所有我也搬家了。
自己也写了好几个项目了,但是博客还没有多少,其实有很多东西都需要记记得,温故而知新嘛!趁不忙,就记录记录。
好了 ,上面的可以忽略,下面正式开始了!
下拉刷新,上拉加载更多
地址:https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More
优点:
这个框架的扩展性还是很强的,头部和底部都可以自定义,
它其中可以嵌套任何控件,ListView、GridView、ScrollView、RecyclerView,甚至TextView。
更多样式参照GitHub中的源码
一.jar包的引用
开发工具是AS
在gradle添加到项目中,我这里是1.0.6,最新版可以到githup上看
compile 'in.srain.cube:ptr-load-more:1.0.6'
二、使用方法
首先在你需要刷新和加载的地方,最外层加入
in.srain.cube.views.ptr.PtrClassicFrameLayout
以我的为例,我这是给gridview加刷新和加载更多
在xml中
<in.srain.cube.views.ptr.PtrClassicFrameLayout android:id="@+id/rotate_header_grid_view_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:ptr_duration_to_close_either="1000"
app:ptr_keep_header_when_refresh="true"
app:ptr_pull_to_fresh="false"
app:ptr_ratio_of_header_height_to_refresh="1.2"
app:ptr_resistance="1.7">
<GridView android:id="@+id/myPoints_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/margin_ten" android:layout_marginLeft="@dimen/margin_ten" android:layout_marginRight="@dimen/margin_ten"
android:layout_marginTop="@dimen/margin_ten"
android:fadingEdge="none"
android:horizontalSpacing="@dimen/margin_ten" android:listSelector="@android:color/transparent" android:numColumns="2" android:overScrollMode="never" android:scrollbars="none" android:verticalSpacing="@dimen/margin_ten">
</GridView></in.srain.cube.views.ptr.PtrClassicFrameLayout>
<!-- ptr:ptr_duration_to_close_either:头部和底部回弹时间 ptr:ptr_keep_header_when_refresh:刷新过程中是否保留头部 ptr:ptr_pull_to_fresh:下拉刷新/释放刷新,默认是释放刷新 ptr:ptr_ratio_of_header_height_to_refresh:触发刷新时移动的位置比例,指的是与头部的比例 ptr:ptr_resistance:阻尼系数,越大下拉越吃力 -->
在Activity中
使用默认样式
//初始化
@ViewInject(R.id.rotate_header_grid_view_frame)
private PtrClassicFrameLayout mPtrFrame;
//在oncreate中
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_points); initReFresh(); }
/**
* 设置下拉刷新上拉加载
*/
private void initReFresh() {
//设置下拉刷新上拉加载
mPtrFrame.disableWhenHorizontalMove(true);//解决横向滑动冲突
mPtrFrame.setPtrHandler(new PtrDefaultHandler2() {
@Override
public void onRefreshBegin(PtrFrameLayout frame) {
mPtrFrame.postDelayed(new Runnable() {
@Override
public void run() {
//刷新数据
}
}, 1000);
}
@Override
public void onLoadMoreBegin(PtrFrameLayout frame) {
mPtrFrame.postDelayed(new Runnable() {
@Override
public void run() {
//加载更多
}
}, 1000);
}
@Override
public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) {
return super.checkCanDoLoadMore(frame, gridView, footer);
}
@Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return super.checkCanDoRefresh(frame, gridView, header);
}
}
);
}
//结束刷新和加载更多的动画,在你成功请求到数据后写入
mPtrFrame.refreshComplete();
默认样式就是这样了
自定义头的部和底部
自定时都继承PtrUIHandler
自定义的头部文件
MyHeadView
package com.example.ruidun.ShanXunApplication.view;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.ruidun.ShanXunApplication.R;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrUIHandler;
import in.srain.cube.views.ptr.indicator.PtrIndicator;
/**
*
* 项目名称:¥{PROJECT_NAME}
* 创建人:潇潇
*
*/
public class MyHeadView extends FrameLayout implements PtrUIHandler {
private TextView tvLoading;
private View view;
//箭头
private ImageView mArrowImageView;
//开始加载的动画
private ProgressBar mProgressBar;
//动画
private Animation mRotateUpAnim;
//显示当前进度的textview
private TextView mHintTextView;
private Animation mRotateDownAnim;
private final int ROTATE_ANIM_DURATION = 180;
public MyHeadView(Context context) {
this(context, null);
}
public MyHeadView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyHeadView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//实例化控件
private void init() {
view = LayoutInflater.from(getContext()).inflate(R.layout.xlistview_header, this, false);
addView(view);
tvLoading = (TextView) view.findViewById(R.id.xlistview_header_hint_textview);
mArrowImageView = (ImageView) view.findViewById(R.id.xlistview_header_arrow);
mProgressBar = (ProgressBar) view.findViewById(R.id.xlistview_header_progressbar);
mHintTextView = (TextView) view.findViewById(R.id.xlistview_header_hint_textview);
// 初始情况,设置下拉刷新view高度为0
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateUpAnim.setFillAfter(true);
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateDownAnim.setFillAfter(true);
}
//重写方法
@Override
public void onUIReset(PtrFrameLayout frame) {
//重置
}
@Override
public void onUIRefreshPrepare(PtrFrameLayout frame) {
//准备刷新 //重置时,将动画置为初始状态
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mRotateUpAnim);
mHintTextView.setText(R.string.xlistview_header_hint_ready);
}
@Override
public void onUIRefreshBegin(PtrFrameLayout frame) {
//开始刷新 显示刷新进度跟文本 //开始刷新,启动动画
mArrowImageView.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
tvLoading.setText("正在加载");
}
@Override
public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) {
//刷新完成 设置文本 设置进度隐藏
tvLoading.setText("加载完毕");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mArrowImageView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
}
}, 500);
}
@Override
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {
final int mOffsetToRefresh = frame.getOffsetToRefresh();
final int currentPos = ptrIndicator.getCurrentPosY();
final int lastPos = ptrIndicator.getLastPosY();
if (currentPos < mOffsetToRefresh) {
//未到达刷新线
if (status == PtrFrameLayout.PTR_STATUS_PREPARE) {
mArrowImageView.startAnimation(mRotateDownAnim);
tvLoading.setText("下拉刷新");
}
} else if (currentPos > mOffsetToRefresh) {
//到达或超过刷新线
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
mArrowImageView.clearAnimation();
tvLoading.setText("释放刷新");
}
}
}
//设置背景色
public void setHeadColor(int color) {
view.setBackgroundColor(color);
}
}
自定义底部布局跟自定义头布局都是一样
MyFooterView
package com.example.ruidun.ShanXunApplication.view;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.example.ruidun.ShanXunApplication.R;
import java.text.SimpleDateFormat;
import java.util.Date;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrUIHandler;
import in.srain.cube.views.ptr.indicator.PtrIndicator;
/**
*
* 项目名称:¥{PROJECT_NAME}
* 创建人:潇潇
*
*/
public class MyFooterView extends FrameLayout implements PtrUIHandler {
private final static String KEY_SharedPreferences = "cube_ptr_classic_last_update";
private static SimpleDateFormat sDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private int mRotateAniTime = 150;
protected RotateAnimation mFlipAnimation;
protected RotateAnimation mReverseFlipAnimation;
//当前加载进度描述
protected TextView mTitleTextView;
//加载动画
private View mProgressBar;
private long mLastUpdateTime = -1;
private String mLastUpdateTimeKey;
private boolean mShouldShowLastUpdate;
private MyFooterView.LastUpdateTimeUpdater mLastUpdateTimeUpdater = new MyFooterView.LastUpdateTimeUpdater();
public MyFooterView(Context context) {
super(context);
initViews(null);
}
public MyFooterView(Context context, AttributeSet attrs) {
super(context, attrs);
initViews(attrs);
}
public MyFooterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initViews(attrs);
}
//初始化布局
protected void initViews(AttributeSet attrs) {
TypedArray arr = getContext().obtainStyledAttributes(attrs, in.srain.cube.views.ptr.R.styleable.PtrClassicHeader, 0, 0);
if (arr != null) {
mRotateAniTime = arr.getInt(in.srain.cube.views.ptr.R.styleable.PtrClassicHeader_ptr_rotate_ani_time, mRotateAniTime);
}
buildAnimation();
View header = LayoutInflater.from(getContext()).inflate(R.layout.xlistview_footer, this);
mTitleTextView = (TextView) header.findViewById(R.id.xlistview_footer_hint_textview);
mProgressBar = header.findViewById(R.id.xlistview_footer_progressbar);
resetView();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mLastUpdateTimeUpdater != null) {
mLastUpdateTimeUpdater.stop();
}
}
public void setRotateAniTime(int time) {
if (time == mRotateAniTime || time == 0) {
return;
}
mRotateAniTime = time;
buildAnimation();
}
/**
* Specify the last update time by this key string
*
* @param key
*/
public void setLastUpdateTimeKey(String key) {
if (TextUtils.isEmpty(key)) {
return;
}
mLastUpdateTimeKey = key;
}
/**
* Using an object to specify the last update time.
*
* @param object
*/
public void setLastUpdateTimeRelateObject(Object object) {
setLastUpdateTimeKey(object.getClass().getName() + "footer");
}
//加载时的动画效果
protected void buildAnimation() {
mFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(mRotateAniTime);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(mRotateAniTime);
mReverseFlipAnimation.setFillAfter(true);
}
private void resetView() {
hideRotateView();
mProgressBar.setVisibility(INVISIBLE);
}
private void hideRotateView() {
// mRotateView.clearAnimation();
// mRotateView.setVisibility(INVISIBLE);
}
@Override
public void onUIReset(PtrFrameLayout frame) {
//重置
resetView();
mShouldShowLastUpdate = true;
tryUpdateLastUpdateTime();
}
@Override
public void onUIRefreshPrepare(PtrFrameLayout frame) {
//准备加载更多 //重置时,将动画置为初始状态
mShouldShowLastUpdate = true;
tryUpdateLastUpdateTime();
mLastUpdateTimeUpdater.start();
mProgressBar.setVisibility(INVISIBLE);
// mRotateView.setVisibility(VISIBLE);
mTitleTextView.setVisibility(VISIBLE);
if (frame.isPullToRefresh()) {
//释放加载
mTitleTextView.setText("松开载入更多");
} else {
//上拉
mTitleTextView.setText("查看更多");
}
}
@Override
public void onUIRefreshBegin(PtrFrameLayout frame) {
//开始加载
mShouldShowLastUpdate = false;
hideRotateView();
mProgressBar.setVisibility(VISIBLE);
//正在加载中
mTitleTextView.setVisibility(GONE);
mTitleTextView.setText(in.srain.cube.views.ptr.R.string.cube_ptr_loading);
tryUpdateLastUpdateTime();
mLastUpdateTimeUpdater.stop();
}
@Override
public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) {
//加载完成
if (isHeader) {
return;
}
hideRotateView();
mProgressBar.setVisibility(INVISIBLE);
//加载完成
mTitleTextView.setVisibility(VISIBLE);
mTitleTextView.setText(getResources().getString(in.srain.cube.views.ptr.R.string.cube_ptr_load_complete));
// update last update time
SharedPreferences sharedPreferences = getContext().getSharedPreferences(KEY_SharedPreferences, 0);
if (!TextUtils.isEmpty(mLastUpdateTimeKey)) {
mLastUpdateTime = new Date().getTime();
sharedPreferences.edit().putLong(mLastUpdateTimeKey, mLastUpdateTime).commit();
}
}
private void tryUpdateLastUpdateTime() {
if (TextUtils.isEmpty(mLastUpdateTimeKey) || !mShouldShowLastUpdate) {
} else {
String time = getLastUpdateTime();
if (TextUtils.isEmpty(time)) {
} else {
}
}
}
private String getLastUpdateTime() {
if (mLastUpdateTime == -1 && !TextUtils.isEmpty(mLastUpdateTimeKey)) {
mLastUpdateTime = getContext().getSharedPreferences(KEY_SharedPreferences, 0).getLong(mLastUpdateTimeKey, -1);
}
if (mLastUpdateTime == -1) {
return null;
}
long diffTime = new Date().getTime() - mLastUpdateTime;
int seconds = (int) (diffTime / 1000);
if (diffTime < 0) {
return null;
}
if (seconds <= 0) {
return null;
}
StringBuilder sb = new StringBuilder();
sb.append(getContext().getString(in.srain.cube.views.ptr.R.string.cube_ptr_last_update));
if (seconds < 60) {
sb.append(seconds + getContext().getString(in.srain.cube.views.ptr.R.string.cube_ptr_seconds_ago));
} else {
int minutes = (seconds / 60);
if (minutes > 60) {
int hours = minutes / 60;
if (hours > 24) {
Date date = new Date(mLastUpdateTime);
sb.append(sDataFormat.format(date));
} else {
sb.append(hours + getContext().getString(in.srain.cube.views.ptr.R.string.cube_ptr_hours_ago));
}
} else {
sb.append(minutes + getContext().getString(in.srain.cube.views.ptr.R.string.cube_ptr_minutes_ago));
}
}
return sb.toString();
}
@Override
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) {
final int mOffsetToRefresh = frame.getOffsetToRefresh();
final int currentPos = ptrIndicator.getCurrentPosY();
final int lastPos = ptrIndicator.getLastPosY();
if (currentPos < mOffsetToRefresh && lastPos >= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
crossRotateLineFromBottomUnderTouch(frame);
// if (mRotateView != null) {
// mRotateView.clearAnimation();
// mRotateView.startAnimation(mReverseFlipAnimation);
// }
}
} else if (currentPos > mOffsetToRefresh && lastPos <= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
crossRotateLineFromTopUnderTouch(frame);
// if (mRotateView != null) {
// mRotateView.clearAnimation();
// mRotateView.startAnimation(mFlipAnimation);
// }
}
}
}
private void crossRotateLineFromTopUnderTouch(PtrFrameLayout frame) {
if (!frame.isPullToRefresh()) {
mTitleTextView.setVisibility(VISIBLE);
mTitleTextView.setText("松开载入更多");
}
}
private void crossRotateLineFromBottomUnderTouch(PtrFrameLayout frame) {
mTitleTextView.setVisibility(VISIBLE);
if (frame.isPullToRefresh()) {
mTitleTextView.setText("松开载入更多");
} else {
mTitleTextView.setText("查看更多");
}
}
private class LastUpdateTimeUpdater implements Runnable {
private boolean mRunning = false;
private void start() {
if (TextUtils.isEmpty(mLastUpdateTimeKey)) {
return;
}
mRunning = true;
run();
}
private void stop() {
mRunning = false;
removeCallbacks(this);
}
@Override
public void run() {
tryUpdateLastUpdateTime();
if (mRunning) {
postDelayed(this, 1000);
}
}
}
}
在Activity中使用吧头布局和底部加上就ok了
/**
* 设置下拉刷新上拉加载
*/
private void initReFresh() {
MyFooterView fView = new MyFooterView(MyPointsActivity.this);//自定义底部加载更多
mPtrFrame.setFooterView(fView);
mPtrFrame.addPtrUIHandler(fView);
MyHeadView hView = new MyHeadView(MyPointsActivity.this); //自定义头部 刷新
mPtrFrame.setKeepHeaderWhenRefresh(true);//刷新时保留头部
mPtrFrame.setHeaderView(hView);
mPtrFrame.addPtrUIHandler(hView);
//设置下拉刷新上拉加载
mPtrFrame.disableWhenHorizontalMove(true);//解决横向滑动冲突
mPtrFrame.setPtrHandler(new PtrDefaultHandler2() {
@Override
public void onRefreshBegin(PtrFrameLayout frame) {
mPtrFrame.postDelayed(new Runnable() {
@Override
public void run() {
//刷新
}
}, 1000);
}
@Override
public void onLoadMoreBegin(PtrFrameLayout frame) {
mPtrFrame.postDelayed(new Runnable() {
@Override
public void run() {
//加载更多
}
}, 1000);
}
@Override
public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) {
return super.checkCanDoLoadMore(frame, gridView, footer);
}
@Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return super.checkCanDoRefresh(frame, gridView, header);
}
}
);
}