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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。