上拉刷新,下拉加载PullToRefreshLayout

  
  
//监听事件
layout . setOnRefreshListener ( new OnRefreshListener () {
public void onRefresh ( PullToRefreshLayout pullToRefreshLayout ) {
// setJson();
// pullToRefreshLayout.refreshFinish(PullToRefreshLayout.SUCCEED);
}
public void onLoadMore ( PullToRefreshLayout pullToRefreshLayout ) {
index += 10 ;
setJson ();
pullToRefreshLayout . loadmoreFinish ( PullToRefreshLayout . SUCCEED );
}
});
/ Pullable . java
public interface Pullable
{
boolean canPullDown ();
boolean canPullUp ();
}
/ pullToRefresh / PullableListView . java
import android.content.Context ;
import android.util.AttributeSet ;
import android.widget.ListView ;
public class PullableListView extends ListView implements Pullable
{
public PullableListView ( Context context )
{
super ( context );
}
public PullableListView ( Context context , AttributeSet attrs )
{
super ( context , attrs );
}
public PullableListView ( Context context , AttributeSet attrs , int defStyle )
{
super ( context , attrs , defStyle );
}
public boolean canPullDown ()
{
if ( getCount () == 0 )
{
return true ;
} else if ( getFirstVisiblePosition () == 0
&& getChildAt ( 0 ). getTop () >= 0 )
{
return true ;
} else
return false ;
}
public boolean canPullUp ()
{
if ( getCount () == 0 )
{
return true ;
} else if ( getLastVisiblePosition () == ( getCount () - 1 ))
{
if ( getChildAt ( getLastVisiblePosition () - getFirstVisiblePosition ()) != null
&& getChildAt (
getLastVisiblePosition ()
- getFirstVisiblePosition ()). getBottom () <= getMeasuredHeight ())
return true ;
}
return false ;
}
}
/ pullToRefresh / PullToRefreshLayout . java
import java.util.Timer ;
import java.util.TimerTask ;
import com.example.demo.R ;
import android.content.Context ;
import android.os.AsyncTask ;
import android.os.Handler ;
import android.os.Message ;
import android.util.AttributeSet ;
import android.util.Log ;
import android.view.MotionEvent ;
import android.view.View ;
import android.view.ViewGroup ;
import android.view.animation.AnimationUtils ;
import android.view.animation.LinearInterpolator ;
import android.view.animation.RotateAnimation ;
import android.widget.RelativeLayout ;
import android.widget.TextView ;
public class PullToRefreshLayout extends RelativeLayout
{
public static final String TAG = "PullToRefreshLayout" ;
public static final int INIT = 0 ;
public static final int RELEASE_TO_REFRESH = 1 ;
public static final int REFRESHING = 2 ;
public static final int RELEASE_TO_LOAD = 3 ;
public static final int LOADING = 4 ;
public static final int DONE = 5 ;
private int state = INIT ;
private OnRefreshListener mListener ;
public static final int SUCCEED = 0 ;
public static final int FAIL = 1 ;
private float downY , lastY ;
public float pullDownY = 0 ;
private float pullUpY = 0 ;
private float refreshDist = 200 ;
private float loadmoreDist = 200 ;
private MyTimer timer ;
public float MOVE_SPEED = 8 ;
private boolean isLayout = false ;
private boolean isTouch = false ;
private float radio = 2 ;
private RotateAnimation rotateAnimation ;
private RotateAnimation refreshingAnimation ;
private View refreshView ;
private View pullView ;
private View refreshingView ;
private View refreshStateImageView ;
private TextView refreshStateTextView ;
private View loadmoreView ;
private View pullUpView ;
private View loadingView ;
private View loadStateImageView ;
private TextView loadStateTextView ;
private View pullableView ;
private int mEvents ;
private boolean canPullDown = true ;
private boolean canPullUp = true ;
private Context mContext ;
Handler updateHandler = new Handler ()
{
@Override
public void handleMessage ( Message msg )
{
MOVE_SPEED = ( float ) ( 8 + 5 * Math . tan ( Math . PI / 2
/ getMeasuredHeight () * ( pullDownY + Math . abs ( pullUpY ))));
if (! isTouch )
{
if ( state == REFRESHING && pullDownY <= refreshDist )
{
pullDownY = refreshDist ;
timer . cancel ();
} else if ( state == LOADING && - pullUpY <= loadmoreDist )
{
pullUpY = - loadmoreDist ;
timer . cancel ();
}
}
if ( pullDownY > 0 )
pullDownY -= MOVE_SPEED ;
else if ( pullUpY < 0 )
pullUpY += MOVE_SPEED ;
if ( pullDownY < 0 )
{
pullDownY = 0 ;
pullView . clearAnimation ();
if ( state != REFRESHING && state != LOADING )
changeState ( INIT );
timer . cancel ();
requestLayout ();
}
if ( pullUpY > 0 )
{
pullUpY = 0 ;
pullUpView . clearAnimation ();
if ( state != REFRESHING && state != LOADING )
changeState ( INIT );
timer . cancel ();
requestLayout ();
}
Log . d ( "handle" , "handle" );
requestLayout ();
if ( pullDownY + Math . abs ( pullUpY ) == 0 )
timer . cancel ();
}
};
public void setOnRefreshListener ( OnRefreshListener listener )
{
mListener = listener ;
}
public PullToRefreshLayout ( Context context )
{
super ( context );
initView ( context );
}
public PullToRefreshLayout ( Context context , AttributeSet attrs )
{
super ( context , attrs );
initView ( context );
}
public PullToRefreshLayout ( Context context , AttributeSet attrs , int defStyle )
{
super ( context , attrs , defStyle );
initView ( context );
}
private void initView ( Context context )
{
mContext = context ;
timer = new MyTimer ( updateHandler );
rotateAnimation = ( RotateAnimation ) AnimationUtils . loadAnimation (
context , R . anim . reverse_anim );
refreshingAnimation = ( RotateAnimation ) AnimationUtils . loadAnimation (
context , R . anim . rotating );
LinearInterpolator lir = new LinearInterpolator ();
rotateAnimation . setInterpolator ( lir );
refreshingAnimation . setInterpolator ( lir );
}
private void hide ()
{
timer . schedule ( 5 );
}
public void refreshFinish ( int refreshResult )
{
refreshingView . clearAnimation ();
refreshingView . setVisibility ( View . GONE );
switch ( refreshResult )
{
case SUCCEED:
refreshStateImageView . setVisibility ( View . VISIBLE );
refreshStateTextView . setText ( R . string . refresh_succeed );
refreshStateImageView
. setBackgroundResource ( R . drawable . refresh_succeed );
break ;
case FAIL:
default :
refreshStateImageView . setVisibility ( View . VISIBLE );
refreshStateTextView . setText ( R . string . refresh_fail );
refreshStateImageView
. setBackgroundResource ( R . drawable . refresh_failed );
break ;
}
if ( pullDownY > 0 )
{
new Handler ()
{
@Override
public void handleMessage ( Message msg )
{
changeState ( DONE );
hide ();
}
}. sendEmptyMessageDelayed ( 0 , 1000 );
} else
{
changeState ( DONE );
hide ();
}
}
public void loadmoreFinish ( int refreshResult )
{
loadingView . clearAnimation ();
loadingView . setVisibility ( View . GONE );
switch ( refreshResult )
{
case SUCCEED:
loadStateImageView . setVisibility ( View . VISIBLE );
loadStateTextView . setText ( R . string . load_succeed );
loadStateImageView . setBackgroundResource ( R . drawable . load_succeed );
break ;
case FAIL:
default :
loadStateImageView . setVisibility ( View . VISIBLE );
loadStateTextView . setText ( R . string . load_fail );
loadStateImageView . setBackgroundResource ( R . drawable . load_failed );
break ;
}
if ( pullUpY < 0 )
{
new Handler ()
{
@Override
public void handleMessage ( Message msg )
{
changeState ( DONE );
hide ();
}
}. sendEmptyMessageDelayed ( 0 , 1000 );
} else
{
changeState ( DONE );
hide ();
}
}
private void changeState ( int to )
{
state = to ;
switch ( state )
{
case INIT:
refreshStateImageView . setVisibility ( View . GONE );
refreshStateTextView . setText ( R . string . pull_to_refresh );
pullView . clearAnimation ();
pullView . setVisibility ( View . VISIBLE );
loadStateImageView . setVisibility ( View . GONE );
loadStateTextView . setText ( R . string . pullup_to_load );
pullUpView . clearAnimation ();
pullUpView . setVisibility ( View . VISIBLE );
break ;
case RELEASE_TO_REFRESH:
refreshStateTextView . setText ( R . string . release_to_refresh );
pullView . startAnimation ( rotateAnimation );
break ;
case REFRESHING:
pullView . clearAnimation ();
refreshingView . setVisibility ( View . VISIBLE );
pullView . setVisibility ( View . INVISIBLE );
refreshingView . startAnimation ( refreshingAnimation );
refreshStateTextView . setText ( R . string . refreshing );
break ;
case RELEASE_TO_LOAD:
loadStateTextView . setText ( R . string . release_to_load );
pullUpView . startAnimation ( rotateAnimation );
break ;
case LOADING:
pullUpView . clearAnimation ();
loadingView . setVisibility ( View . VISIBLE );
pullUpView . setVisibility ( View . INVISIBLE );
loadingView . startAnimation ( refreshingAnimation );
loadStateTextView . setText ( R . string . loading );
break ;
case DONE:
break ;
}
}
private void releasePull ()
{
canPullDown = true ;
canPullUp = true ;
}
@Override
public boolean dispatchTouchEvent ( MotionEvent ev )
{
switch ( ev . getActionMasked ())
{
case MotionEvent . ACTION_DOWN :
downY = ev . getY ();
lastY = downY ;
timer . cancel ();
mEvents = 0 ;
releasePull ();
break ;
case MotionEvent . ACTION_POINTER_DOWN :
case MotionEvent . ACTION_POINTER_UP :
mEvents = - 1 ;
break ;
case MotionEvent . ACTION_MOVE :
if ( mEvents == 0 )
{
if ( pullDownY > 0
|| ((( Pullable ) pullableView ). canPullDown ()
&& canPullDown && state != LOADING ))
{
pullDownY = pullDownY + ( ev . getY () - lastY ) / radio ;
if ( pullDownY < 0 )
{
pullDownY = 0 ;
canPullDown = false ;
canPullUp = true ;
}
if ( pullDownY > getMeasuredHeight ())
pullDownY = getMeasuredHeight ();
if ( state == REFRESHING )
{
isTouch = true ;
}
} else if ( pullUpY < 0
|| ((( Pullable ) pullableView ). canPullUp () && canPullUp && state != REFRESHING ))
{
pullUpY = pullUpY + ( ev . getY () - lastY ) / radio ;
if ( pullUpY > 0 )
{
pullUpY = 0 ;
canPullDown = true ;
canPullUp = false ;
}
if ( pullUpY < - getMeasuredHeight ())
pullUpY = - getMeasuredHeight ();
if ( state == LOADING )
{
isTouch = true ;
}
} else
releasePull ();
} else
mEvents = 0 ;
lastY = ev . getY ();
radio = ( float ) ( 2 + 2 * Math . tan ( Math . PI / 2 / getMeasuredHeight ()
* ( pullDownY + Math . abs ( pullUpY ))));
if ( pullDownY > 0 || pullUpY < 0 )
requestLayout ();
if ( pullDownY > 0 )
{
if ( pullDownY <= refreshDist
&& ( state == RELEASE_TO_REFRESH || state == DONE ))
{
changeState ( INIT );
}
if ( pullDownY >= refreshDist && state == INIT )
{
changeState ( RELEASE_TO_REFRESH );
}
} else if ( pullUpY < 0 )
{
if (- pullUpY <= loadmoreDist
&& ( state == RELEASE_TO_LOAD || state == DONE ))
{
changeState ( INIT );
}
if (- pullUpY >= loadmoreDist && state == INIT )
{
changeState ( RELEASE_TO_LOAD );
}
}
if (( pullDownY + Math . abs ( pullUpY )) > 8 )
{
ev . setAction ( MotionEvent . ACTION_CANCEL );
}
break ;
case MotionEvent . ACTION_UP :
if ( pullDownY > refreshDist || - pullUpY > loadmoreDist )
{
isTouch = false ;
}
if ( state == RELEASE_TO_REFRESH )
{
changeState ( REFRESHING );
if ( mListener != null )
mListener . onRefresh ( this );
} else if ( state == RELEASE_TO_LOAD )
{
changeState ( LOADING );
if ( mListener != null )
mListener . onLoadMore ( this );
}
hide ();
default :
break ;
}
super . dispatchTouchEvent ( ev );
return true ;
}
private class AutoRefreshAndLoadTask extends
AsyncTask < Integer , Float , String >
{
@Override
protected String doInBackground ( Integer ... params )
{
while ( pullDownY < 4 / 3 * refreshDist )
{
pullDownY += MOVE_SPEED ;
publishProgress ( pullDownY );
try
{
Thread . sleep ( params [ 0 ]);
} catch ( InterruptedException e )
{
e . printStackTrace ();
}
}
return null ;
}
@Override
protected void onPostExecute ( String result )
{
changeState ( REFRESHING );
if ( mListener != null )
mListener . onRefresh ( PullToRefreshLayout . this );
hide ();
}
@Override
protected void onProgressUpdate ( Float ... values )
{
if ( pullDownY > refreshDist )
changeState ( RELEASE_TO_REFRESH );
requestLayout ();
}
}
public void autoRefresh ()
{
AutoRefreshAndLoadTask task = new AutoRefreshAndLoadTask ();
task . execute ( 20 );
}
public void autoLoad ()
{
pullUpY = - loadmoreDist ;
requestLayout ();
changeState ( LOADING );
if ( mListener != null )
mListener . onLoadMore ( this );
}
private void initView ()
{
pullView = refreshView . findViewById ( R . id . pull_icon );
refreshStateTextView = ( TextView ) refreshView
. findViewById ( R . id . state_tv );
refreshingView = refreshView . findViewById ( R . id . refreshing_icon );
refreshStateImageView = refreshView . findViewById ( R . id . state_iv );
pullUpView = loadmoreView . findViewById ( R . id . pullup_icon );
loadStateTextView = ( TextView ) loadmoreView
. findViewById ( R . id . loadstate_tv );
loadingView = loadmoreView . findViewById ( R . id . loading_icon );
loadStateImageView = loadmoreView . findViewById ( R . id . loadstate_iv );
}
@Override
protected void onLayout ( boolean changed , int l , int t , int r , int b )
{
Log . d ( "Test" , "Test" );
if (! isLayout )
{
refreshView = getChildAt ( 0 );
pullableView = getChildAt ( 1 );
loadmoreView = getChildAt ( 2 );
isLayout = true ;
initView ();
refreshDist = (( ViewGroup ) refreshView ). getChildAt ( 0 )
. getMeasuredHeight ();
loadmoreDist = (( ViewGroup ) loadmoreView ). getChildAt ( 0 )
. getMeasuredHeight ();
}
refreshView . layout ( 0 ,
( int ) ( pullDownY + pullUpY ) - refreshView . getMeasuredHeight (),
refreshView . getMeasuredWidth (), ( int ) ( pullDownY + pullUpY ));
pullableView . layout ( 0 , ( int ) ( pullDownY + pullUpY ),
pullableView . getMeasuredWidth (), ( int ) ( pullDownY + pullUpY )
+ pullableView . getMeasuredHeight ());
loadmoreView . layout ( 0 ,
( int ) ( pullDownY + pullUpY ) + pullableView . getMeasuredHeight (),
loadmoreView . getMeasuredWidth (),
( int ) ( pullDownY + pullUpY ) + pullableView . getMeasuredHeight ()
+ loadmoreView . getMeasuredHeight ());
}
class MyTimer
{
private Handler handler ;
private Timer timer ;
private MyTask mTask ;
public MyTimer ( Handler handler )
{
this . handler = handler ;
timer = new Timer ();
}
public void schedule ( long period )
{
if ( mTask != null )
{
mTask . cancel ();
mTask = null ;
}
mTask = new MyTask ( handler );
timer . schedule ( mTask , 0 , period );
}
public void cancel ()
{
if ( mTask != null )
{
mTask . cancel ();
mTask = null ;
}
}
class MyTask extends TimerTask
{
private Handler handler ;
public MyTask ( Handler handler )
{
this . handler = handler ;
}
@Override
public void run ()
{
handler . obtainMessage (). sendToTarget ();
}
}
}
public interface OnRefreshListener
{
void onRefresh ( PullToRefreshLayout pullToRefreshLayout );
void onLoadMore ( PullToRefreshLayout pullToRefreshLayout );
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先吐槽一下现在流行的刷新库,一个字大,包涵个人很多集成到项目中不需要的类,也很难找到很满意的效果,所以自己自己动手丰衣足食,撸一个。1.概述对所有基础控件(包括,嵌套滑动例如RecyclerView、NestedScrollView,普通的TextView、ListView、ScrollerView、LinearLayout等)提供下拉刷新上拉加载的支持,处理了横向滑动冲突(例如:顶部banner的情况) ,且实现无痕过度。gradle (改用bintray-release,2017-7-8 16:00上传,以下暂时不会生效)compile 'com.yan:pullrefreshlayout:1.1.2'2.说明支持所有基础控件 loading 出现效果默认(STATE_FOLLOW、STATE_PLACEHOLDER_FOLLOW、STATE_CENTER、STATE_PLACEHOLDER_CENTER、STATE_FOLLOW_CENTER、STATE_CENTER_FOLLOW)  //-控件设置-     refreshLayout.autoRefresh();// 自动刷新     refreshLayout.setOverScrollDampingRatio(0.2f);//  值越大overscroll越短 default 0.2     refreshLayout.setAdjustTwinkDuring(3);// 值越大overscroll越慢 default 3     refreshLayout.setScrollInterpolator(interpolator);// 设置scroller的插值器     refreshLayout.setLoadMoreEnable(true);// 上拉加载是否可用 default false     refreshLayout.setDuringAdjustValue(10f);// 动画执行时间调节,越大动画执行越慢 default 10f     // 刷新加载完成后回复动画执行时间,为-1时,根据setDuringAdjustValue()方法实现 default 300     refreshLayout.setRefreshBackTime(300);     refreshLayout.setDragDampingRatio(0.6f);// 阻尼系数 default 0.6     refreshLayout.setPullFlowHeight(400);// 拖拽最大范围,为-1时拖拽范围不受限制 default -1     refreshLayout.setRefreshEnable(false);// 下拉刷新是否可用 default false     refreshLayout.setPullTwinkEnable(true);// 回弹是否可用 default true      refreshLayout.setAutoLoadingEnable(true);// 自动加载是否可用 default false          // headerView和footerView需实现PullRefreshLayout.OnPullListener接口调整状态     refreshLayout.setHeaderView(headerView);// 设置headerView     refreshLayout.setFooterView(footerView);// 设置footerView          /**     * 设置header或者footer的的出现方式,默认7种方式     * STATE_FOLLOW, STATE_PLACEHOLDER_FOLLOW, STATE_PLACEHOLDER_CENTER     * , STATE_CENTER, STATE_CENTER_FOLLOW, STATE_FOLLOW_CENTER     * ,STATE_PLACEHOLDER     */     refreshLayout.setRefreshShowGravity(RefreshShowHelper.STATE_CENTER,RefreshShowHelper.STATE_CENTER);     refreshLayout.setHeaderShowGravity(RefreshShowHelper.STATE_CENTER)// header出现动画     refreshLayout.setFooterShowGravity(RefreshShowHelper.STATE_CENTER)// footer出现动画     // PullRefreshLayout.OnPullListener         public interface OnPullListener {             // 刷新加载过程中位置相刷新加载触发位置的百分比,时刻调用             void onPullChange(float percent);             void onPullReset();// 数据重置调用             void onPullHoldTrigger();// 拖拽超过触发位置调用             void onPullHoldUnTrigger();// 拖拽回到触发位置之前调用             void onPullHolding(); // 正在刷新             void onPullFinish();// 刷新完成         }3.demo用到的库loading 动画 AVLoadingIndicatorView(https://github.com/81813780/AVLoadingIndicatorView)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值