package com.lqr.wechat.widget;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import com.lqr.wechat.R;
/**
* 仿微信朋友圈列表页下拉刷新控件
* Created by aliouswang on 15/5/8.
*/
public class FriendRefreshView extends ViewGroup implements OnDetectScrollListener {
//圆形指示器
private ImageView mRainbowView;
private ListView mContentView;
//控件宽,高
private int sWidth;
private int sHeight;
private ViewDragHelper mDragHelper;
//contentView的当前top属性
private int currentTop;
//listView首个item
private int firstItem;
private boolean bScrollDown = false;
private boolean bDraging = false;
//圆形加载指示器最大top
private int rainbowMaxTop = 80;
//圆形加载指示器刷新时的top
private int rainbowStickyTop = 80;
//圆形加载指示器初始top
private int rainbowStartTop = -120;
//圆形加载指示器的半径
private int rainbowRadius = 100;
private int rainbowTop = -120;
//圆形加载指示器旋转的角度
private int rainbowRotateAngle = 0;
private boolean bViewHelperSettling = false;
//刷新接口listener
private OnRefreshListener mRefreshLisenter;
private AbsListView.OnScrollListener onScrollListener;
private OnDetectScrollListener onDetectScrollListener;
public enum State {
NORMAL,
REFRESHING,
DRAGING
}
//控件当前状态
private State mState = State.NORMAL;
public FriendRefreshView(Context context) {
this(context, null);
}
public FriendRefreshView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FriendRefreshView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initHandler();
initDragHelper();
initListView();
initRainbowView();
setBackgroundColor(Color.parseColor("#000000"));
onDetectScrollListener = this;
}
/**
* 初始化handler,当ViewDragHelper释放了mContentView时,
* 我们通过循环发送消息刷新mRainbowView的位置和角度
*/
private void initHandler() {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
if (rainbowTop > rainbowStartTop) {
rainbowTop -= 10;
requestLayout();
mHandler.sendEmptyMessageDelayed(0, 15);
}
break;
case 1:
if (rainbowTop <= rainbowStickyTop) {
if (rainbowTop < rainbowStickyTop) {
rainbowTop += 10;
if (rainbowTop > rainbowStickyTop) {
rainbowTop = rainbowStickyTop;
}
}
mRainbowView.setRotation(rainbowRotateAngle -= 10);
} else {
mRainbowView.setRotation(rainbowRotateAngle += 10);
}
requestLayout();
mHandler.sendEmptyMessageDelayed(1, 15);
break;
}
}
};
}
/**
* 初始化mDragHelper,我们处理拖动的核心类
*/
private void initDragHelper() {
mDragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View view, int i) {
return view == mContentView && !bViewHelperSettling;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return 0;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return top;
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
if (changedView == mContentView) {
int lastContentTop = currentTop;
if (top >= 0) {
currentTop = top;
} else {
top = 0;
}
int lastTop = rainbowTop;
int rTop = top + rainbowStartTop;
if (rTop >= rainbowMaxTop) {
if (!isRefreshing()) {
rainbowRotateAngle += (currentTop - lastContentTop) * 2;
rTop = rainbowMaxTop;
rainbowTop = rTop;
mRainbowView.setRotation(rainbowRotateAngle);
} else {
rTop = rainbowMaxTop;
rainbowTop = rTop;
}
} else {
if (isRefreshing()) {
rainbowTop = rainbowStickyTop;
} else {
rainbowTop = rTop;
rainbowRotateAngle += (rainbowTop - lastTop) * 3;
mRainbowView.setRotation(rainbowRotateAngle);
}
}
requestLayout();
}
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
mDragHelper.settleCapturedViewAt(0, 0);
ViewCompat.postInvalidateOnAnimation(FriendRefreshView.this);
//如果手势释放时,拖动的距离大于rainbowStickyTop,开始刷新
if (currentTop >= rainbowStickyTop) {
startRefresh();
}
}
});
}
@Override
public void computeScroll() {
super.computeScroll();
if (mDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
bViewHelperSettling = true;
} else {
bViewHelperSettling = false;
}
}
/**
* 我们invoke 方法shouldIntercept来判断是否需要拦截事件,
* 拦截事件是为了将事件传递给mDragHelper来处理,我们这里只有当mContentView滑动到顶部
* 且mContentView没有处于滑动状态时才触发拦截。
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mDragHelper.shouldInterceptTouchEvent(ev);
return shouldIntercept();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDragHelper.processTouchEvent(event);
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
mLastMotionY = 0;
bDraging = false;
bScrollDown = false;
rainbowRotateAngle = 0;
break;
case MotionEvent.ACTION_MOVE:
int index = MotionEventCompat.getActionIndex(event);
int pointerId = MotionEventCompat.getPointerId(event, index);
if (shouldIntercept()) {
mDragHelper.captureChildView(mContentView, pointerId);
}
break;
}
return true;
}
/**
* 判断是否需要拦截触摸事件
*
* @return
*/
private boolean shouldIntercept() {
if (bDraging) return true;
int childCount = mContentView.getChildCount();
if (childCount > 0) {
View firstChild = mContentView.getChildAt(0);
if (firstChild.getTop() >= 0
&& firstItem == 0 && currentTop == 0
&& bScrollDown) {
return true;
} else return false;
} else {
return true;
}
}
/**
* 判断mContentView是否处于顶部
*
* @return
*/
private boolean checkIsTop() {
int childCount = mContentView.getChildCount();
if (childCount > 0) {
View firstChild = mContentView.getChildAt(0);
if (firstChild.getTop() >= 0
&& firstItem == 0 && currentTop == 0) {
return true;
} else return false;
} else {
return false;
}
}
private void initRainbowView() {
mRainbowView = new ImageView(getContext());
mRainbowView.setImageResource(R.mipmap.rainbow_ic);
addView(mRainbowView);
}
/**
* 初始化listView,我们创建了istView for you,所有你要做的
* 就是调用setAdapter,绑定你自定义的adapter
*/
private void initListView() {
mContentView = new FriendRefreshListView(getContext());
View mHeadViw = LayoutInflater.from(getContext()).inflate(R.layout.list_head_layout, null);
mContentView.addHeaderView(mHeadViw);
this.addView(mContentView);
mContentView.setOnScrollListener(new AbsListView.OnScrollListener() {
private int oldTop;
private int oldFirstVisibleItem;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (onScrollListener != null) {
onScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
firstItem = firstVisibleItem;
if (onScrollListener != null) {
onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
if (onDetectScrollListener != null) {
onDetectedListScroll(view, firstVisibleItem);
}
}
private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
View view = absListView.getChildAt(0);
int top = (view == null) ? 0 : view.getTop();
if (firstVisibleItem == oldFirstVisibleItem) {
if (top > oldTop) {
onDetectScrollListener.onUpScrolling();
} else if (top < oldTop) {
onDetectScrollListener.onDownScrolling();
}
} else {
if (firstVisibleItem < oldFirstVisibleItem) {
onDetectScrollListener.onUpScrolling();
} else {
onDetectScrollListener.onDownScrolling();
}
}
oldTop = top;
oldFirstVisibleItem = firstVisibleItem;
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
sWidth = MeasureSpec.getSize(widthMeasureSpec);
sHeight = MeasureSpec.getSize(heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
LayoutParams contentParams = (LayoutParams) mContentView.getLayoutParams();
contentParams.left = 0;
contentParams.top = 0;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
LayoutParams contentParams = (LayoutParams) mContentView.getLayoutParams();
mContentView.layout(contentParams.left, currentTop,
contentParams.left + sWidth, currentTop + sHeight);
mRainbowView.layout(rainbowRadius, rainbowTop,
rainbowRadius * 2, rainbowTop + rainbowRadius);
}
@Override
public void onUpScrolling() {
bScrollDown = false;
}
@Override
public void onDownScrolling() {
bScrollDown = true;
}
public static class LayoutParams extends ViewGroup.LayoutParams {
public int left = 0;
public int top = 0;
public LayoutParams(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
}
public LayoutParams(int arg0, int arg1) {
super(arg0, arg1);
}
public LayoutParams(android.view.ViewGroup.LayoutParams arg0) {
super(arg0);
}
}
@Override
public android.view.ViewGroup.LayoutParams generateLayoutParams(
AttributeSet attrs) {
return new FriendRefreshView.LayoutParams(getContext(), attrs);
}
@Override
protected android.view.ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
}
@Override
protected android.view.ViewGroup.LayoutParams generateLayoutParams(
android.view.ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
@Override
protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
return p instanceof FriendRefreshView.LayoutParams;
}
private float mLastMotionX;
private float mLastMotionY;
/**
* 对ListView的触摸事件进行判断,是否处于滑动状态
*/
private class FriendRefreshListView extends ListView {
public FriendRefreshListView(Context context) {
this(context, null);
}
public FriendRefreshListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FriendRefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setBackgroundColor(Color.parseColor("#ffffff"));
}
/*当前活动的点Id,有效的点的Id*/
protected int mActivePointerId = INVALID_POINTER;
/*无效的点*/
private static final int INVALID_POINTER = -1;
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
int index = MotionEventCompat.getActionIndex(ev);
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
if (mActivePointerId == INVALID_POINTER)
break;
mLastMotionX = ev.getX();
mLastMotionY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
int indexMove = MotionEventCompat.getActionIndex(ev);
mActivePointerId = MotionEventCompat.getPointerId(ev, indexMove);
if (mActivePointerId == INVALID_POINTER) {
} else {
final float y = ev.getY();
float dy = y - mLastMotionY;
if (checkIsTop() && dy >= 1.0f) {
bScrollDown = true;
bDraging = true;
} else {
bScrollDown = false;
bDraging = false;
}
mLastMotionX = y;
}
break;
case MotionEvent.ACTION_UP:
mLastMotionY = 0;
break;
}
return super.onTouchEvent(ev);
}
}
public void setAdapter(BaseAdapter adapter) {
if (mContentView != null) {
mContentView.setAdapter(adapter);
}
}
public boolean isRefreshing() {
return mState == State.REFRESHING;
}
Handler mHandler;
public void startRefresh() {
if (!isRefreshing()) {
mHandler.removeMessages(0);
mHandler.removeMessages(1);
mHandler.sendEmptyMessage(1);
mState = State.REFRESHING;
invokeListner();
}
}
private void invokeListner() {
if (mRefreshLisenter != null) {
mRefreshLisenter.onRefresh();
}
}
public void stopRefresh() {
mHandler.removeMessages(1);
mHandler.sendEmptyMessage(0);
mState = State.NORMAL;
}
public void setOnRefreshListener(OnRefreshListener listener) {
this.mRefreshLisenter = listener;
}
public interface OnRefreshListener {
public void onRefresh();
}
}