android自定义下拉刷新使用ViewDraghelper处理
主要是使用ViewDragHelper处理的滑动侦听
privateViewDragHelperdragHelper;
privateViewmContentView;
privateViewGroupmTopView;
privateListViewlistView;
privateRecyclerViewrecyclerView;
privateScrollViewscrollView;
privateImageViewiv_circel;
privateRelativeLayoutrl_content;
private intmWidth,mHeight;
private intmaxRange=0;//最大下拉的高度
private intrefreshHeight;//下拉出发刷新的高度
private inttext_bottom;//中间文字的底部
private intdownY;
private intchildViewTop;
private booleanisMoveChildView,isLayout;//是否包含可滑动的view true包含
private booleanisStop,isStartAnim;//是否停止刷新,是否开启动画
//下拉刷新的状态
private final intSTATE_DOWN=0;//下拉中
private final intSTATE_REFRESHING=1;//刷新中
private final intSTATE_REFRESH=2;//可刷新
private intcurrent_state=STATE_DOWN;
//属性值
private intrefresh_gravity=1;//1 top 2 center 3 bottom
privateOnRefreshListenerlistener;
private booleanisRefresh=true;//是否可以刷新
privateTextViewtv_text;
publicRefreshView(Context context) {
this(context, null);
}
publicRefreshView(Context context,AttributeSet attrs) {
this(context,attrs,0);
}
publicRefreshView(Context context,AttributeSet attrs, intdefStyleAttr) {
super(context,attrs,defStyleAttr);
init();
//获取自定义属性
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.refreshView);
refresh_gravity= ta.getInt(R.styleable.refreshView_refresh_gravity,1);
ta.recycle();
}
public interfaceOnRefreshListener {
voidonRefresh();
}
public voidsetOnRefreshListener(OnRefreshListener listener) {
this.listener= listener;
}
public voidsetIsRefresh(booleanisRefresh) {
this.isRefresh= isRefresh;
}
private voidinit() {
dragHelper= ViewDragHelper.create(this, newMyCallBack());
}
@Override
protected voidonSizeChanged(intw, inth, intoldw, intoldh) {
super.onSizeChanged(w,h,oldw,oldh);
mWidth= w;
mHeight= h;
}
@Override
protected voidonFinishInflate() {
super.onFinishInflate();
//健壮性检查
if(getChildCount() >1) {
throw newRuntimeException("只能包含一个子view或viewgroup");
}
if(getChildCount() ==0) {
throw newRuntimeException("not childview,childview would not be null!");
}
isLayout=false;
//因为在onFinishInflate中添加一个viewgroup在0的位置
mContentView= getChildAt(0);//获取布局中的view
isMoveChildView= childType(mContentView);//查看是否有可滑动的view
//添加下拉刷新头布局
mTopView= (ViewGroup) View.inflate(getContext(),R.layout.layout_refresh, null);
addView(mTopView,0);
rl_content= (RelativeLayout)mTopView.findViewById(R.id.fl_header);
rl_content.measure(0,0);
refreshHeight=rl_content.getMeasuredHeight();
tv_text= (TextView)mTopView.findViewById(R.id.tv_text);
iv_circel= (ImageView)mTopView.findViewById(R.id.iv_circel);
iv_circel.setAlpha(0.0f);
//根据设置的属性设置头布局的位置
if(refresh_gravity==1) {
rl_content.setGravity(Gravity.TOP);
}else if(refresh_gravity==2) {
rl_content.setGravity(Gravity.CENTER);
}else{
rl_content.setGravity(Gravity.BOTTOM);
}
}
/**
*判断此view是否是可滑动的view,或此view中是否包含可滑动的view(listview,scrollview,recyclerview)
*
*@paramview
*@returntrue则表示包含可滑动的view
*/
private booleanchildType(View view) {
booleanconform =false;
conform = isTypeConform(view,conform);
if(!conform) {
if(viewinstanceofViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
intchildCount = viewGroup.getChildCount();
for(inti =0;i < childCount;i++) {
View childView = viewGroup.getChildAt(i);
if(childViewinstanceofViewGroup) {
booleantypeConform = isTypeConform(childView,conform);
if(typeConform) {
childViewTop= childView.getTop();//可滑动view的初始top值
returntypeConform;
}
childType(childView);
}
}
}
}
returnconform;
}
/**
*是否是可滑动的view
*/
private booleanisTypeConform(View view, booleantype) {
if(viewinstanceofListView) {
type =true;
listView= (ListView) view;
}else if(viewinstanceofRecyclerView) {
recyclerView= (RecyclerView) view;
type =true;
}else if(viewinstanceofScrollView) {
scrollView= (ScrollView) view;
type =true;
}
returntype;
}
@Override
protected voidonLayout(booleanchanged, intleft, inttop, intright, intbottom) {
if(!isLayout) {
if(iv_circel!=null&&isStartAnim) {
iv_circel.clearAnimation();
isStartAnim=false;
iv_circel.setAlpha(0.0f);
}
super.onLayout(changed,left,top,right,bottom);
}
maxRange=mHeight-refreshHeight;//最大下拉距离
text_bottom=refreshHeight-refreshHeight/2;
mTopView.layout(0,-(mHeight-refreshHeight),mWidth,refreshHeight);
isLayout=false;
//重新摆放刷新布局
if(refresh_gravity==1&&mContentView.getTop() >=refreshHeight) {
mTopView.setTranslationY(mContentView.getTop() -refreshHeight);
}
}
@Override
public booleanonInterceptTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
downY= (int) ev.getY();
}
returndragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public booleanonTouchEvent(MotionEvent event) {
dragHelper.processTouchEvent(event);
return true;
}
private classMyCallBackextendsViewDragHelper.Callback {
/**
*返回可拖拽的范围
*/
@Override
public intgetViewVerticalDragRange(View child) {
//如果包含可滑动的view
if(isMoveChildView&&downY>childViewTop) {
if(listView!=null&&listView.getAdapter() !=null) {
View childView =listView.getChildAt(0);
if(listView.getAdapter().getCount() >0&& childView !=null&& childView.getTop() <0)
return super.getViewVerticalDragRange(child);
}else if(scrollView!=null&&scrollView.getScrollY() >0) {
return super.getViewVerticalDragRange(child);
}else if(recyclerView!=null&&recyclerView.getAdapter() !=null&&recyclerView.getChildAt(0).getTop() <0) {
return super.getViewVerticalDragRange(child);
}
}
returnmaxRange;
}
/**
*返回true表示可以拖拽
*/
@Override
public booleantryCaptureView(View child, intpointerId) {
//如果触摸的是刷新的头部view或者是设置为不可刷新则返回false
if(child ==mTopView|| !isRefresh) {
return false;
}
return true;
}
/**
*当被拖拽的view移动位置后,会调用此方法。可以用于处理View之间的联动
*/
@Override
public voidonViewPositionChanged(View changedView, intleft, inttop, intdx, intdy) {
super.onViewPositionChanged(changedView,left,top,dx,dy);
//处理上面view的移动
floatmoveTop = top;
if(moveTop >=text_bottom) {
floatalpha = (moveTop -text_bottom) /text_bottom;
if(alpha >1) {
alpha =1.0f;
}else if(alpha <0.0) {
alpha =0.0f;
}
iv_circel.setAlpha(alpha);
}else{
iv_circel.setAlpha(0.0f);
}
if(tv_text!=null) {
isLayout=true;
tv_text.setText("下拉刷新");
}
if(moveTop >=refreshHeight) {
if(iv_circel!=null&&isStartAnim) {
isStartAnim=false;
iv_circel.clearAnimation();
}
if(refresh_gravity==1) {
isLayout=true;
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)rl_content.getLayoutParams();
params.height= (int) moveTop;
rl_content.setLayoutParams(params);
rl_content.requestLayout();
}else if(refresh_gravity==2||refresh_gravity==3) {
floattranslationY = moveTop -refreshHeight;
mTopView.setTranslationY(translationY);
}
}
}
/**
*拖拽松开时调用
*/
@Override
public voidonViewReleased(View releasedChild, floatxvel, floatyvel) {
super.onViewReleased(releasedChild,xvel,yvel);
intmContentViewTop =mContentView.getTop();
if(mContentViewTop >refreshHeight) {
current_state=STATE_REFRESH;
refreshOpen();
}else{
close();
}
}
/**
*返回top值
*/
@Override
public intclampViewPositionVertical(View child, inttop, intdy) {
floatnewTop = top/** 0.93f*/;
if(newTop >=maxRange) {
newTop =maxRange;
}else if(top <0) {
newTop =0;
}
return(int) newTop;
}
}
/**
*开始刷新 并且滚动至相应的位置
*/
private voidrefreshOpen() {
inttop =refreshHeight;
if(dragHelper.smoothSlideViewTo(mContentView,0,top)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
/**
*关闭面板 此时下拉的高度没有达到刷新的高度,滚动至0的位置
*/
private voidclose() {
inttop =0;
if(dragHelper.smoothSlideViewTo(mContentView,0,top)) {
ViewCompat.postInvalidateOnAnimation(this);
}
isLayout=false;
current_state=STATE_DOWN;
iv_circel.clearAnimation();
}
@Override
public voidcomputeScroll() {
// super.computeScroll();
if(dragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}else if(mContentView.getTop() >=refreshHeight&¤t_state==STATE_REFRESH) {
startAnim();
current_state=STATE_REFRESHING;//改变状态
if(listener!=null) {
listener.onRefresh();
}
if(tv_text!=null) {
tv_text.setText("刷新中");
isLayout=true;
}
}
}
private longduration=500L;
private voidstartAnim() {
isStop=false;
duration=500L;
isStartAnim=true;
RotateAnimation anim =newRotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5F,Animation.RELATIVE_TO_SELF,0.5F);
anim.setDuration(duration);
anim.setRepeatCount(Animation.INFINITE);
anim.setInterpolator(newLinearInterpolator());
iv_circel.startAnimation(anim);
anim.setAnimationListener(newAnimation.AnimationListener() {
@Override
public voidonAnimationStart(Animation animation) {
}
@Override
public voidonAnimationEnd(Animation animation) {
current_state=STATE_DOWN;//清楚动画的同时并改变是否刷新的状态
if(tv_text!=null) {
isLayout=true;
tv_text.setText("刷新完毕");
}
postDelayed(newRunnable() {
@Override
public voidrun() {
close();//回滚至顶部
}
},300);
}
@Override
public voidonAnimationRepeat(Animation animation) {
if(!isStop) {
duration-=100;
if(duration<=230) {
duration=230;
}
}else{
duration+=100;
if(duration>=500) {
duration=500;
anim.setRepeatCount(1);
}
}
anim.setDuration(duration);
}
});
}
/**
*刷新完毕
*/
public voidrefreshFinish() {
isStop=true;
}
}
自定义属性
< declare-styleable name="refreshView">
<enum name="refresh_top" value="1"/>
<enum name="refresh_center" value="2"/>
<enum name="refresh_bottom" value="3"/>
<declare-styleable/>
头部布局
<LinearLayout
android:id="@+id/ll_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_green_light"
android:gravity="bottom"
android:orientation="vertical">
android:id="@+id/fl_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="bottom"
android:paddingBottom="20dp"
android:paddingTop="20dp">
<FramLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="下拉刷新"
android:textColor="@android:color/black"
android:textSize="12sp"/>
android:id="@+id/iv_circel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@mipmap/circle"/>
</Framlayout>