package com.example.dragListView;
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.example.actionbar.R;
import com.pets.activity.NewDailyShareActivity;
import com.pets.util.CustomDataUtils;
/***
* 自定义拖拉ListView
*
* @author zhangjia
*
*/
public class FlushOnPullListView extends ListView implements OnScrollListener,
OnClickListener {
// 拖拉ListView枚举所有状态
private enum DListViewState {
LV_NORMAL, // 普通状态
LV_PULL_REFRESH, // 下拉状态(为超过mHeadViewHeight)
LV_RELEASE_REFRESH, // 松开可刷新状态(超过mHeadViewHeight)
LV_LOADING;// 加载状态
}
// 点击加载更多枚举所有状态
private enum DListViewLoadingMore {
LV_NORMAL, // 普通状态
LV_LOADING, // 加载状态
LV_OVER; // 结束状态
}
/**
* 常量接口,主要用于数据获取的key值定义
*
* @author Administrator
*
*/
private interface keys {
public static final String CURR_UPDATE_TIME = "currentUpdateTime";
}
// 回到顶部view
private PopupWindow backToTop;
private View mHeadView;// 头部headView
private TextView mRefreshTextview; // 刷新msg(mHeadView)
private TextView mLastUpdateTextView;// 更新事件(mHeadView)
private ImageView mArrowImageView;// 下拉图标(mHeadView)
private ProgressBar mHeadProgressBar;// 刷新进度体(mHeadView)
private int mHeadViewWidth; // headView的宽(mHeadView)
private int mHeadViewHeight;// headView的高(mHeadView)
private View mFootView;// 尾部mFootView
private View mLoadMoreView;// mFootView 的view(mFootView)
private TextView mLoadMoreTextView;// 加载更多.(mFootView)
private View mLoadingView;// 加载中...View(mFootView)
private View headTools;// listview顶上的登录与发表按钮
private Button login;// 登录按钮
private Button newArticle;// 发表新说说按钮
private Animation animation, reverseAnimation;// 旋转动画,旋转动画之后旋转动画.
private int mFirstItemIndex = -1;// 当前视图能看到的第一个项的索引
// 用于保证startY的值在一个完整的touch事件中只被记录一次
private boolean mIsRecord = false;
private int mStartY, mMoveY;// 按下是的y坐标,move时的y坐标
private DListViewState mlistViewState = DListViewState.LV_NORMAL;// 拖拉状态.(自定义枚举)
private DListViewLoadingMore loadingMoreState = DListViewLoadingMore.LV_NORMAL;// 加载更多默认状态.
private final static int RATIO = 2;// 手势下拉距离比.
private boolean mBack = false;// headView是否返回.
private OnRefreshLoadingMoreListener onRefreshLoadingMoreListener;// 下拉刷新接口(自定义)
private boolean isScroller = true;// 是否屏蔽ListView滑动。
public FlushOnPullListView(Context context) {
super(context, null);
initDragListView(context);
}
public FlushOnPullListView(Context context, AttributeSet attrs) {
super(context, attrs);
initDragListView(context);
}
// 注入下拉刷新接口
public void setOnRefreshListener(
OnRefreshLoadingMoreListener onRefreshLoadingMoreListener) {
this.onRefreshLoadingMoreListener = onRefreshLoadingMoreListener;
}
/***
* 初始化ListView
*/
public void initDragListView(Context context) {
String time = CustomDataUtils.lastUpdateTime(keys.CURR_UPDATE_TIME,
CustomDataUtils.DATE_LONG_FORMAT_YMDHMS);// 更新时间
initHeadView(context, time);// 初始化该head.
initLoadMoreView(context);// 初始化footer
setOnScrollListener(this);// ListView滚动监听
}
/***
* 初始话头部HeadView
*
* @param context
* 上下文
* @param time
* 上次更新时间
*/
public void initHeadView(Context context, String time) {
mHeadView = LayoutInflater.from(context).inflate(R.layout.head, null);
mArrowImageView = (ImageView) mHeadView
.findViewById(R.id.head_arrowImageView);
mArrowImageView.setMinimumWidth(60);
mHeadProgressBar = (ProgressBar) mHeadView
.findViewById(R.id.head_progressBar);
mRefreshTextview = (TextView) mHeadView
.findViewById(R.id.head_tipsTextView);
mLastUpdateTextView = (TextView) mHeadView
.findViewById(R.id.head_lastUpdatedTextView);
setLastUpdateTime(time);
measureView(mHeadView);
// 获取宽和高
mHeadViewWidth = mHeadView.getMeasuredWidth();
mHeadViewHeight = mHeadView.getMeasuredHeight();
addHeaderView(mHeadView, null, false);// 将初始好的ListView add进拖拽ListView
headTools = LayoutInflater.from(context).inflate(R.layout.head_tools,
null);
login = (Button) headTools.findViewById(R.id.list_head_login);
newArticle = (Button) headTools.findViewById(R.id.list_head_new);
login.setOnClickListener(this);
newArticle.setOnClickListener(this);
addHeaderView(headTools);
// 在这里我们要将此headView设置到顶部不显示位置.
mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
initAnimation();// 初始化动画
}
private void setLastUpdateTime(String time) {
// 显示更新事件
mLastUpdateTextView.setText("最近更新:" + time);
}
/**
* 移除顶部登录按钮
*/
public void removeLoginBtn() {
login.setVisibility(GONE);
}
/***
* 初始化底部加载更多控件
*/
private void initLoadMoreView(Context context) {
mFootView = LayoutInflater.from(context).inflate(R.layout.footer, null);
mLoadMoreView = mFootView.findViewById(R.id.load_more_view);
mLoadMoreTextView = (TextView) mFootView
.findViewById(R.id.load_more_tv);
mLoadingView = (LinearLayout) mFootView
.findViewById(R.id.loading_layout);
mLoadMoreView.setOnClickListener(this);
addFooterView(mFootView);
}
/***
* 初始化动画
*/
private void initAnimation() {
// 旋转动画
animation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());// 匀速
animation.setDuration(250);
animation.setFillAfter(true);// 停留在最后状态.
// 反向旋转动画
reverseAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator());
reverseAnimation.setDuration(250);
reverseAnimation.setFillAfter(true);
}
/***
* 作用:测量 headView的宽和高.
*
* @param child
*/
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
/***
* touch 事件监听
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
// 按下
case MotionEvent.ACTION_DOWN:
doActionDown(ev);
break;
// 移动
case MotionEvent.ACTION_MOVE:
doActionMove(ev);
break;
// 抬起
case MotionEvent.ACTION_UP:
doActionUp(ev);
break;
default:
break;
}
/***
* 如果是ListView本身的拉动,那么返回true,这样ListView不可以拖动.
* 如果不是ListView的拉动,那么调用父类方法,这样就可以上拉执行.
*/
if (isScroller) {
return super.onTouchEvent(ev);
} else {
return true;
}
}
/***
* 摁下操作
*
* 作用:获取摁下是的y坐标
*
* @param event
*/
void doActionDown(MotionEvent event) {
if (mIsRecord == false && mFirstItemIndex == 0) {
mStartY = (int) event.getY();
mIsRecord = true;
}
}
/***
* 拖拽移动操作
*
* @param event
*/
void doActionMove(MotionEvent event) {
mMoveY = (int) event.getY();// 获取实时滑动y坐标
// 检测是否是一次touch事件.
if (mIsRecord == false && mFirstItemIndex == 0) {
mStartY = (int) event.getY();
mIsRecord = true;
}
/***
* 如果touch关闭或者正处于Loading状态的话 return.
*/
if (mIsRecord == false || mlistViewState == DListViewState.LV_LOADING) {
return;
}
// 向下啦headview移动距离为y移动的一半.(比较友好)
int offset = (mMoveY - mStartY) / RATIO;
switch (mlistViewState) {
// 普通状态
case LV_NORMAL: {
// 如果<0,则意味着上滑动.
if (offset > 0) {
// 设置headView的padding属性.
mHeadView.setPadding(0, offset - mHeadViewHeight, 0, 0);
switchViewState(DListViewState.LV_PULL_REFRESH);// 下拉状态
}
}
break;
// 下拉状态
case LV_PULL_REFRESH: {
setSelection(0);// 选中第一项,可选.
// 设置headView的padding属性.
mHeadView.setPadding(0, offset - mHeadViewHeight, 0, 0);
if (offset < 0) {
/***
* 要明白为什么isScroller = false;
*/
isScroller = false;
switchViewState(DListViewState.LV_NORMAL);// 普通状态
Log.e("jj", "isScroller=" + isScroller);
} else if (offset > mHeadViewHeight) {// 如果下拉的offset超过headView的高度则要执行刷新.
switchViewState(DListViewState.LV_RELEASE_REFRESH);// 更新为可刷新的下拉状态.
}
}
break;
// 可刷新状态
case LV_RELEASE_REFRESH: {
setSelection(0);
// 设置headView的padding属性.
mHeadView.setPadding(0, offset - mHeadViewHeight, 0, 0);
// 下拉offset>0,但是没有超过headView的高度.那么要goback 原装.
if (offset >= 0 && offset <= mHeadViewHeight) {
mBack = true;
switchViewState(DListViewState.LV_PULL_REFRESH);
} else if (offset < 0) {
switchViewState(DListViewState.LV_NORMAL);
} else {
}
}
break;
default:
return;
}
;
}
/***
* 手势抬起操作
*
* @param event
*/
public void doActionUp(MotionEvent event) {
mIsRecord = false;// 此时的touch事件完毕,要关闭。
isScroller = true;// ListView可以Scrooler滑动.
mBack = false;
// 如果下拉状态处于loading状态.
if (mlistViewState == DListViewState.LV_LOADING) {
return;
}
// 处理相应状态.
switch (mlistViewState) {
// 普通状态
case LV_NORMAL:
break;
// 下拉状态
case LV_PULL_REFRESH:
mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
switchViewState(mlistViewState.LV_NORMAL);
break;
// 刷新状态
case LV_RELEASE_REFRESH:
mHeadView.setPadding(0, 0, 0, 0);
switchViewState(mlistViewState.LV_LOADING);
onRefresh();// 下拉刷新
break;
}
}
// 切换headview视图
private void switchViewState(DListViewState state) {
switch (state) {
// 普通状态
case LV_NORMAL: {
mArrowImageView.clearAnimation();// 清除动画
mArrowImageView.setImageResource(R.drawable.arrow);
}
break;
// 下拉状态
case LV_PULL_REFRESH: {
mHeadProgressBar.setVisibility(View.GONE);// 隐藏进度条
mArrowImageView.setVisibility(View.VISIBLE);// 下拉图标
mRefreshTextview.setText("下拉可以刷新");
mArrowImageView.clearAnimation();// 清除动画
// 开始设置时间上次刷新 时间
this.setLastUpdateTime(CustomDataUtils.lastUpdateTime(
keys.CURR_UPDATE_TIME,
CustomDataUtils.DATE_LONG_FORMAT_YMDHMS));
// 是有可刷新状态(LV_RELEASE_REFRESH)转为这个状态才执行,其实就是你下拉后在上拉会执行.
if (mBack) {
mBack = false;
mArrowImageView.clearAnimation();// 清除动画
mArrowImageView.startAnimation(reverseAnimation);// 启动反转动画
}
}
break;
// 松开刷新状态
case LV_RELEASE_REFRESH: {
mHeadProgressBar.setVisibility(View.GONE);// 隐藏进度条
mArrowImageView.setVisibility(View.VISIBLE);// 显示下拉图标
mRefreshTextview.setText("松开获取更多");
mArrowImageView.clearAnimation();// 清除动画
mArrowImageView.startAnimation(animation);// 启动动画
}
break;
// 加载状态
case LV_LOADING: {
mHeadProgressBar.setVisibility(View.VISIBLE);
mArrowImageView.clearAnimation();
mArrowImageView.setVisibility(View.GONE);
mRefreshTextview.setText("载入中...");
}
break;
default:
return;
}
// 切记不要忘记时时更新状态。
mlistViewState = state;
}
/***
* 下拉刷新
*/
private void onRefresh() {
if (onRefreshLoadingMoreListener != null) {
onRefreshLoadingMoreListener.onRefresh();
}
}
/***
* 下拉刷新完毕
*/
public void onRefreshComplete() {
mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);// 回归.
switchViewState(DListViewState.LV_NORMAL);//
}
/***
* 点击加载更多
*
* @param flag
* 数据是否已全部加载完毕
*/
public void onLoadMoreComplete(boolean flag) {
if (flag) {
updateLoadMoreViewState(DListViewLoadingMore.LV_OVER);
} else {
updateLoadMoreViewState(DListViewLoadingMore.LV_NORMAL);
}
}
// 更新Footview视图
private void updateLoadMoreViewState(DListViewLoadingMore state) {
switch (state) {
// 普通状态
case LV_NORMAL:
mLoadingView.setVisibility(View.GONE);
mLoadMoreTextView.setVisibility(View.VISIBLE);
mLoadMoreTextView.setText("查看更多");
break;
// 加载中状态
case LV_LOADING:
mLoadingView.setVisibility(View.VISIBLE);
mLoadMoreTextView.setVisibility(View.GONE);
break;
// 加载完毕状态
case LV_OVER:
mLoadingView.setVisibility(View.GONE);
mLoadMoreTextView.setVisibility(View.VISIBLE);
mLoadMoreTextView.setText("加载完毕");
break;
default:
break;
}
loadingMoreState = state;
}
/***
* ListView 滑动监听
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
private void backToTop(final AbsListView parent) {
if (null == backToTop) {
backToTop = new PopupWindow();
backToTop.setWidth(LayoutParams.WRAP_CONTENT);
backToTop.setHeight(LayoutParams.WRAP_CONTENT);
LinearLayout layout = new LinearLayout(getContext());
layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
Button backBtn = new Button(getContext());
backBtn.setText("TOP");
backBtn.setWidth(LayoutParams.MATCH_PARENT);
backBtn.setHeight(LayoutParams.MATCH_PARENT);
backBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (null != parent) {
if (parent.getCount() > 0)
parent.setSelection(0);
}
}
});
layout.addView(backBtn);
backToTop.setContentView(layout);
}
if (!backToTop.isShowing())
backToTop.showAtLocation(parent, Gravity.RIGHT | Gravity.BOTTOM,
20, 20);
}
private void dismissTip() {
if (null != backToTop && backToTop.isShowing()) {
backToTop.dismiss();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mFirstItemIndex = firstVisibleItem;
if (firstVisibleItem > 1) {
// 显示回到顶部
backToTop(view);
} else {
dismissTip();
}
}
/***
* 底部点击事件
*/
@Override
public void onClick(View v) {
if (v == newArticle) {
Intent intent = new Intent(getContext(),
NewDailyShareActivity.class);
getContext().startActivity(intent);
return;
}
// 防止重复点击
if (onRefreshLoadingMoreListener != null
&& loadingMoreState == DListViewLoadingMore.LV_NORMAL) {
updateLoadMoreViewState(DListViewLoadingMore.LV_LOADING);
onRefreshLoadingMoreListener.onLoadMore();// 对外提供方法加载更多.
}
}
/***
* 自定义接口
*/
public interface OnRefreshLoadingMoreListener {
/***
* // 下拉刷新执行
*/
void onRefresh();
/***
* 点击加载更多
*/
void onLoadMore();
}
}