Android实现简单的下拉刷新pulltorefresh
网上下拉刷新的DEMO很多,但是总有各种不满意的地方,有些会下拉卡住,有些回弹不流畅,有些性能太低会各种卡顿,有些emptyView无法下拉......
自己写的才是最合适自己的,代码很简单,也很容易修改,稍微阅读下代码就能改出自己需要的各种效果。
首先,重写ListView,自定义Touch事件,为了使emptyView也可下拉,emptyView也加上Touch事件。如果要实现GridView,把这里的ListView改成GridView即可。
PullableListView:
publicclassPullableListViewextendsListView{
privatebooleaninited;
privatefloatdensity;
privateintmDownY,mMoveY;
privateintmPullY;
privatebooleanisPull;
privatePullListenermPullListener;
privateVelocityTrackermVelocityTracker;
publicinterfacePullListener{
publicbooleanonPullDownStart();
publicvoidonPullDown(intmoveY);
publicvoidonPullDownDrop();
}
publicPullableListView(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
init();
}
publicPullableListView(Contextcontext,AttributeSetattrs){
super(context,attrs);
init();
}
publicPullableListView(Contextcontext){
super(context);
init();
}
privatevoidinit(){
if(!inited){
density=getResources().getDisplayMetrics().density;
}
}
publicvoidsetPullListener(PullListenermPullListener){
this.mPullListener=mPullListener;
}
publicbooleanisPulling(){
returnisPull;
}
@Override
publicvoidsetEmptyView(ViewemptyView){
super.setEmptyView(emptyView);
//重写emptyView的Touch事件,使显示emptyView时也可以下拉刷新
emptyView.setOnTouchListener(newOnTouchListener(){
@Override
publicbooleanonTouch(Viewv,MotionEventev){
if(mVelocityTracker==null){
mVelocityTracker=VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
switch(ev.getAction()){
caseMotionEvent.ACTION_DOWN:
mDownY=(int)ev.getY();
break;
caseMotionEvent.ACTION_MOVE:
mMoveY=(int)ev.getY();
if(!isPull){
mVelocityTracker.computeCurrentVelocity(1000,8000f);
if(mVelocityTracker.getYVelocity()>500//下拉速度大于500
&&Math.abs(mMoveY-mDownY)>20*density){//下拉距离超过20dp
mPullY=mMoveY;
if(mPullListener.onPullDownStart()){
isPull=true;
}
}
}else{
//阻尼下拉(随着下拉距离增加,阻力增加)
mPullListener.onPullDown(mMoveY-mPullY+v.getScrollY());
//等阻力下拉(阻力恒定,不随下拉距离增加而增加)
//mPullListener.onPullDown(mMoveY-mPullY);
if(mMoveY<mPullY){
isPull=false;
}
returntrue;
}
break;
caseMotionEvent.ACTION_UP:
if(mVelocityTracker!=null){
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker=null;
}
if(isPull){
mPullY=0;
isPull=false;
mPullListener.onPullDownDrop();
returntrue;
}
break;
}
returntrue;
}
});
}
@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
if(isPull){
//正在下拉时,阻住Touch事件向下传递,同时会向各个ChildView发送ACTION_CANLE事件,
//使之前捕捉到了ACTION_DOWN事件的ChildView回复到正常状态
returntrue;
}
returnsuper.onInterceptTouchEvent(ev);
}
@Override
publicbooleanonTouchEvent(MotionEventev){
if(mVelocityTracker==null){
mVelocityTracker=VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
switch(ev.getAction()){
caseMotionEvent.ACTION_DOWN:
mDownY=(int)ev.getY();
break;
caseMotionEvent.ACTION_MOVE:
mMoveY=(int)ev.getY();
if(!isPull){
if(getFirstVisiblePosition()==0){
Viewview=getChildAt(0);
mVelocityTracker.computeCurrentVelocity(1000,8000f);
if(mVelocityTracker.getYVelocity()>500//下拉速度大于500
&&(view==null||view.getTop()==getPaddingTop())//已拉动到顶部
&&Math.abs(mMoveY-mDownY)>15*density){//下拉距离超过20dp
mPullY=mMoveY;
if(mPullListener.onPullDownStart()){
//根据返回值确认是否进入下拉状态
isPull=true;
}
}
}
}else{
//阻尼下拉(随着下拉距离增加,阻力增加)
mPullListener.onPullDown(mMoveY-mPullY);
//等阻力下拉(阻力恒定,不随下拉距离增加而增加)
//mPullListener.onPullDown(mMoveY-mPullY-getScrollY());
if(mMoveY<mPullY){
isPull=false;
}
returntrue;
}
break;
caseMotionEvent.ACTION_UP:
if(mVelocityTracker!=null){
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker=null;
}
if(isPull){
mPullY=0;
isPull=false;
mPullListener.onPullDownDrop();
returntrue;
}
break;
caseMotionEvent.ACTION_CANCEL:
break;
}
returnsuper.onTouchEvent(ev);
}
}
然后是外层的LinearyLayer,监听PullableListView的下拉回调,实现下拉效果。同时提供ListView(GridView)的外部接口,如setEmptyView(Viewview),setAdapter(ListAdapteradapter)...等等,这里只提供部分我需要使用的,可以根据自身需求去提供外部接口。
代码中R.drawable.pulltorefresh和R.drawable.loading分别是下拉箭头和刷新滚动条的图片,这里不提供了,自己随意找两张图片贴上就行了。
PullToRefreshView:
publicclassPullToRefreshViewextendsLinearLayout{
protectedstaticfinalStringTAG="PullToRefreshView";
/**
*下拉阻力系数
*/
privatestaticfinalfloatSCALL_PULL_DOWW=2.0f;
privateViewmView;
privatePullableListViewmListView;
privateTextViewmPullTv;
privateImageViewmProgressBar;
privateViewmPullV;
privateViewmEmptyView;
privatebooleanisInited;
privatebooleancanRefresh;
privatebooleanisRefreshing;
privatebooleanisPullable=true;
privateintmOrMargin;
privateObjectAnimatormArrowRotateAnimator;
privateAnimationmProAnimation;
privatePullToRefreshListenermPullToRefreshListener;
publicPullToRefreshView(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
initView(context);
}
publicPullToRefreshView(Contextcontext,AttributeSetattrs){
super(context,attrs);
initView(context);
}
publicPullToRefreshView(Contextcontext){
super(context);
initView(context);
}
publicinterfacePullToRefreshListener{
/**
*dodatarefreshhere
*/
publicvoidonRefreshStart();
/**
*doviewupdatehere
*/
publicvoidonRefreshFinished();
}
privatevoidinitView(Contextcontext){
if(!isInited){
isInited=true;
mView=LayoutInflater.from(context).inflate(R.layout.view_pulltorefresh,null);
mProgressBar=(ImageView)mView.findViewById(R.id.iv_pulltorefresh_arrow);
mProgressBar.setImageResource(R.drawable.pulltorefresh);
mPullTv=(TextView)mView.findViewById(R.id.tv_pulltorefresh);
mPullV=mView.findViewById(R.id.ly_pulltorefresh_pull);
mListView=(PullableListView)mView.findViewById(R.id.gv_smarturc_urcs);
mListView.setPullListener(mPullListener);
LayoutParamslp=newLayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
addView(mView,lp);
LayoutParamslParams=(LayoutParams)mPullV.getLayoutParams();
mOrMargin=lParams.topMargin;
mProAnimation=AnimationUtils.loadAnimation(getContext(),
R.anim.anim_progressbar);
}
}
privatePullListenermPullListener=newPullListener(){
@Override
publicbooleanonPullDownStart(){
if(isRefreshing||!isPullable){
returnfalse;
}
mPullTv.setText("下拉刷新");
mProgressBar.setRotation(0f);
mProgressBar.setImageResource(R.drawable.pulltorefresh);
if(mProgressBar.getAnimation()!=null){
mProgressBar.clearAnimation();
}
returntrue;
}
@Override
publicvoidonPullDown(intmoveY){
if(isRefreshing||!isPullable){
return;
}
moveY=(int)Math.max(0,moveY/SCALL_PULL_DOWW);
mView.scrollTo(0,-moveY);
mEmptyView.scrollTo(0,-moveY);
if(!canRefresh
&&Math.abs(mView.getScrollY())>Math.abs(mOrMargin)){
mPullTv.setText("松开刷新");
canRefresh=true;
if(mArrowRotateAnimator!=null){
mArrowRotateAnimator.cancel();
}
floatrotation=mProgressBar.getRotation();
mArrowRotateAnimator=ObjectAnimator.ofFloat(mProgressBar,"rotation",
rotation,180f);
mArrowRotateAnimator.setDuration(100).start();
}elseif(canRefresh
&&Math.abs(mView.getScrollY())<=Math.abs(mOrMargin)){
mPullTv.setText("下拉刷新");
canRefresh=false;
if(mArrowRotateAnimator!=null){
mArrowRotateAnimator.cancel();
}
floatrotation=mProgressBar.getRotation();
mArrowRotateAnimator=ObjectAnimator.ofFloat(mProgressBar,"rotation",
rotation,0f);
mArrowRotateAnimator.setDuration(100).start();
}
}
@Override
publicvoidonPullDownDrop(){
if(canRefresh){
setRefreshing();
}else{
isRefreshing=false;
backTo(mView.getScrollY(),0);
}
}
};
privatevoidbackTo(finalintfrom,finalintto){
ObjectAnimator.ofInt(mView,"scrollY",from,to).setDuration(300)
.start();
ObjectAnimator.ofInt(mEmptyView,"scrollY",from,to).setDuration(300)
.start();
}
/**
*设置为正在刷新状态
*/
publicvoidsetRefreshing(){
isRefreshing=true;
mProgressBar.setImageResource(R.drawable.loading);
mProgressBar.startAnimation(mProAnimation);
mPullTv.setText("正在刷新");
backTo(mView.getScrollY(),mOrMargin);
if(mPullToRefreshListener!=null){
mPullToRefreshListener.onRefreshStart();
}
}
/**
*刷新完成
*/
publicvoidsetRrefreshFinish(){
if(isRefreshing){
isRefreshing=false;
backTo(mView.getScrollY(),0);
}
if(mPullToRefreshListener!=null){
mPullToRefreshListener.onRefreshFinished();
}
}
publicvoidsetPullable(booleanpullable){
isPullable=pullable;
}
publicvoidsetPullToRefreshListener(
PullToRefreshListenermPullToRefreshListener){
this.mPullToRefreshListener=mPullToRefreshListener;
}
publicvoidsetAdapter(ListAdapteradapter){
mListView.setAdapter(adapter);
}
publicvoidsetEmptyView(ViewemptyView){
mListView.setEmptyView(emptyView);
this.mEmptyView=emptyView;
}
publicvoidsetOnItemClickListener(OnItemClickListeneritemClickListener){
mListView.setOnItemClickListener(itemClickListener);
}
publicvoidsetOnItemLongClickListener(OnItemLongClickListeneritemLongClickListener){
mListView.setOnItemLongClickListener(itemLongClickListener);
}
}
layout-view_pulltorefresh:
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#cccccc" android:orientation="vertical"> <LinearLayout android:id="@+id/ly_pulltorefresh_pull" android:layout_width="wrap_content" android:layout_height="48dp" android:layout_gravity="center_horizontal" android:layout_marginTop="-48dp"> <ImageView android:id="@+id/iv_pulltorefresh_arrow" android:layout_width="20dp" android:layout_height="match_parent" android:scaleType="fitCenter" android:src="@drawable/pulltorefresh"/> <TextView android:id="@+id/tv_pulltorefresh" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginBottom="4dp" android:layout_marginLeft="8dp" android:gravity="center" android:textColor="@android:color/white" android:textSize="16sp"/> </LinearLayout> <com.example.pulltorefresh.PullableListView android:id="@+id/gv_smarturc_urcs" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:overScrollMode="never" android:scrollingCache="false"> </com.example.pulltorefresh.PullableListView> </LinearLayout>
anim-anim_progressbar:
<?xmlversion="1.0"encoding="utf-8"?> <rotatexmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%" android:repeatCount="infinite" android:repeatMode="restart" android:duration="800" android:interpolator="@android:anim/linear_interpolator"/>
最后是DEMOACTIVITY:
publicclassPullToRefreshActivityextendsActivity{
privatePullToRefreshViewmPullToRefreshView;
privateList<String>data=newArrayList<String>();
privateMyAdaptermAdapter;
privateHandlermHandler;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
//TODOAuto-generatedmethodstub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pulltorefresh);
mHandler=newHandler();
mPullToRefreshView=(PullToRefreshView)findViewById(R.id.pullToRefreshView1);
mAdapter=newMyAdapter();
mPullToRefreshView.setAdapter(mAdapter);
mPullToRefreshView.setEmptyView(findViewById(R.id.empty));
mPullToRefreshView.setOnItemLongClickListener(newOnItemLongClickListener(){
@Override
publicbooleanonItemLongClick(AdapterView<?>parent,Viewview,intposition,longid){
Toast.makeText(getApplicationContext(),"Longclick:"+data.get(position),
Toast.LENGTH_SHORT).show();
returntrue;
}
});
mPullToRefreshView.setOnItemClickListener(newOnItemClickListener(){
@Override
publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){
Toast.makeText(getApplicationContext(),data.get(position),Toast.LENGTH_SHORT)
.show();
}
});
mPullToRefreshView.setPullToRefreshListener(newPullToRefreshListener(){
@Override
publicvoidonRefreshStart(){
//模拟刷新数据
mHandler.postDelayed(newRunnable(){
@Override
publicvoidrun(){
data.add(String.valueOf((int)(Math.random()*1000)));
mPullToRefreshView.setRrefreshFinish();
}
},2000);
}
@Override
publicvoidonRefreshFinished(){
//更新视图
mAdapter.notifyDataSetChanged();
}
});
//mHandler.postDelayed(newRunnable(){
//@Override
//publicvoidrun(){
////TODOAuto-generatedmethodstub
//mPullToRefreshView.setRefreshing();
//}
//},500);
}
publicclassMyAdapterextendsBaseAdapter{
@Override
publicintgetCount(){
//TODOAuto-generatedmethodstub
returndata.size();
}
@Override
publicObjectgetItem(intposition){
//TODOAuto-generatedmethodstub
returndata.get(position);
}
@Override
publiclonggetItemId(intposition){
//TODOAuto-generatedmethodstub
returnposition;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
//TODOAuto-generatedmethodstub
if(convertView==null){
convertView=newTextView(PullToRefreshActivity.this);
}
TextViewtextView=(TextView)convertView;
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP,40f);
textView.setPadding(30,30,30,30);
textView.setText(data.get(position));
returnconvertView;
}
}
}
layout-activity_pulltorefresh:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.pulltorefresh.PullToRefreshView android:id="@+id/pullToRefreshView1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:layout_alignParentTop="true"> </com.example.pulltorefresh.PullToRefreshView> <LinearLayout android:id="@+id/empty" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:padding="60dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="NODATA"/> </LinearLayout> </RelativeLayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。