Hoist the Colours! Our world is wide!

上拉加载之前跟大家分享过,就是通过监听listview的滚动事件,确定最后一个可视条目为listview的最后一个条目,这时候用户继续下拉,就去加载更多,然后需要注意的是需要本次加载完成之后才能去加载更多,所以需要有一个flag去标志是否完成加载。用户执行下拉刷新或者是上拉加载的操作是不同时的,就是下拉刷新的时候不能上拉加载,反之亦然。这样下拉就可以完成这个功能。

下拉刷新,首先,我们下拉得到的数据需要添加在原有数据的前面。然后下拉刷新的时候我们需要注意的地方一个是header的显示,他的提示文字随着用户的滑动不停的改变。然后当用户滑动到一定程度的时候,释放可以刷新数据。

所以,我们首先需要定义上拉刷新的四种状态,没有动作,开始下拉,释放可以刷新,正在刷新。然后,我们首次需要隐藏掉header,就利用到header的padding Top,不断改变该属性可以实现header随用户手滑动而改变。大概的效果如下图

下面是详细的代码实现:自定义ListView,继承ListView,然后实现OnScrollListener,主要的功能:下拉刷新header的显示处理,下拉加载footer的显示处理,定义两个接口对应下拉刷新和上拉加载,用于接口回调,与Activity通行。没有什么,需要注意一点的就是下拉刷新过程中的header可以转变的,可以有NONE 到RELEASE 反之也可以,需要作出处理,每一次处理之后都要及时调用refreshHeaderViewByState这个方法去重新显示header。当用户拖动的距离大于headerHeigh+30之后就可以松开刷新了,这个是可以自定义的。import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;import android.annotation.SuppressLint;import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;import com.guanggong.operatestdemo01.R;/** * @author Administrator liweijie * @since 5.19 * @version 2.0 * 是一个自定义的listview,可作用于上拉刷新下拉加载 * */@SuppressLint("ClickableViewAccessibility")public class OperaSumListView extends ListView implements OnScrollListener{// 区分是下拉刷新还是上拉加载public static final int LOAD = 0;public static final int REFRESH = 1;// 这是上拉加载的一些view+需要的变量private View footer;private TextView loadFull;private TextView noData;private TextView loading;private ProgressBar loadProgressbar;private int lastVisiableitem;private int totleItem;private boolean isLoading = false; // 每一次都需要先把上次加载的完成之后才可以去加载下一次//用于保证下拉刷新的时候不可以上拉加载,反之一样private boolean isRefresh = false;private boolean isLoad = false;private View header;private int heighHeader;private int SPACE = 30; // 控制下拉到什么程度的时候开始改变state的值为RELEASE,松开可以刷新private int scrollState; // 滚动状态,只有是手指摁在屏幕导致的下拉刷新事件有效,假如是由于惯性的则无销,个人设定private int firstVisiableItem; // 第一个可见的item,用于判断当前情况是否可以下拉刷新private boolean isRemark = false;// 标记是否正在下拉刷新状态private int startY;// 手指摁下的时候后的y值private ImageView arrow;private TextView tip;private TextView lastUpdate;private ProgressBar refreshBar;// 下拉刷新的四种状态,一开始没有显示出来为NONE// 下拉显示出header的时候提示信息有所改变,下拉可刷新// 下拉一定程度的时候文字变为松开可刷新// 最后为正在刷新private static final int NONE = 0;private static final int PULL = 1;private static final int RELEASE = 2;private static final int REFRESHING = 3;private int state;// 箭头动画private RotateAnimation anim;private RotateAnimation anim1;public OperaSumListView(Context context){super(context);initView(context);}public OperaSumListView(Context context, AttributeSet attrs){super(context, attrs);initView(context);}public OperaSumListView(Context context, AttributeSet attrs, int defStyleAttr){super(context, attrs, defStyleAttr);initView(context);}/** * 每一次header的状态改变的时候都需要对他的布局进行相关的处理 */@SuppressLint("InflateParams") private void initView(Context context){anim = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, (float) 0.5,RotateAnimation.RELATIVE_TO_SELF, 0.5f);anim.setDuration(400);anim.setFillAfter(true);anim1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, (float) 0.5,RotateAnimation.RELATIVE_TO_SELF, 0.5f);anim1.setDuration(400);anim1.setFillAfter(true);LayoutInflater inflater = LayoutInflater.from(context);footer = inflater.inflate(R.layout.opera_sumfragment_listview_footer, null);loadFull = (TextView) footer.findViewById(R.id.id_sum_listview_footer_lv_textview01);noData = (TextView) footer.findViewById(R.id.id_sum_listview_footer_lv_textview02);loading = (TextView) footer.findViewById(R.id.id_sum_listview_footer_lv_textview03);loadProgressbar = (ProgressBar) footer.findViewById(R.id.id_sum_listview_footer_lv_progress);this.addFooterView(footer);footer.setVisibility(View.GONE);header = inflater.inflate(R.layout.opera_sumfragment_listview_header, null);arrow = (ImageView) header.findViewById(R.id.id_sum_listview_header_lv_rv_imageview);tip = (TextView) header.findViewById(R.id.id_sum_listview_header_lv_rv_lv_textview);lastUpdate = (TextView) header.findViewById(R.id.id_sum_listview_header_lv_rv_lv_textview02);lastUpdate.setText(new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒", Locale.getDefault()).format(new Date()));refreshBar = (ProgressBar) header.findViewById(R.id.id_sum_listview_header_lv_rv_progress);measureHeader(header);heighHeader = header.getMeasuredHeight();toPadding(-heighHeader);this.addHeaderView(header);this.setOnScrollListener(this);}private void measureHeader(View child){ViewGroup.LayoutParams lp = child.getLayoutParams();if (lp == null){lp = new android.view.ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);}int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);int temp = lp.height;int heighSpec;if (temp > 0){heighSpec = MeasureSpec.makeMeasureSpec(temp, MeasureSpec.EXACTLY);} else{heighSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);}child.measure(widthSpec, heighSpec);}/** * 设置header的padding top的值 * * @param i */private void toPadding(int i){header.setPadding(header.getPaddingLeft(), i, header.getPaddingRight(),header.getPaddingBottom());header.invalidate();}@Overridepublic boolean onTouchEvent(MotionEvent ev){switch (ev.getAction()){case MotionEvent.ACTION_DOWN: // 首次手指摁下if (firstVisiableItem == 0){isRemark = true;startY = (int) ev.getY();}break;case MotionEvent.ACTION_MOVE:// 手指移动whenMove(ev);break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:// 手指抬起System.out.println("state=" + state);if (state == PULL || state == NONE){state = NONE;refreshHeaderViewByState();} else if (state == RELEASE){System.out.println("有执行到");state = REFRESHING;refreshHeaderViewByState();if (onRefreshListener != null && !isLoad){isRefresh = true;onRefreshListener.onRefresh();}}isRemark = false;break;}return super.onTouchEvent(ev);}/** * 用于控制移动时候的状态改变和切换 计算padding top的值 * * @param ev */private void whenMove(MotionEvent ev){if (!isRemark){return;}int tmpY = (int) ev.getY();int space = tmpY – startY;int topPadding = space – heighHeader;switch (state){case NONE:if (space > 0){state = PULL;refreshHeaderViewByState();}break;case PULL:toPadding(topPadding);if (space > heighHeader + SPACE && scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){state = RELEASE;refreshHeaderViewByState();} else if (space < 0){state = NONE;refreshHeaderViewByState();}break;case RELEASE:toPadding(topPadding);if (space < heighHeader + SPACE && space > 0){state = PULL;refreshHeaderViewByState();} else if (space <= 0){state = NONE;refreshHeaderViewByState();}break;}}/** * 每一次header的状态改变的时候都需要对他的布局进行相关的处理 */private void refreshHeaderViewByState(){switch (state){case NONE:toPadding(-heighHeader);break;case PULL:tip.setText("下拉可以刷新");arrow.clearAnimation();arrow.setAnimation(anim1);arrow.startAnimation(anim1);refreshBar.setVisibility(View.GONE);arrow.setVisibility(View.VISIBLE);break;case RELEASE:tip.setText("松开可以刷新");arrow.clearAnimation();arrow.setAnimation(anim);arrow.startAnimation(anim);arrow.setVisibility(View.VISIBLE);refreshBar.setVisibility(View.GONE);break;case REFRESHING:System.out.println("123有执行力过");toPadding(30);arrow.clearAnimation();arrow.setVisibility(View.GONE);refreshBar.setVisibility(View.VISIBLE);tip.setText("正在刷新");}}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState){this.scrollState = scrollState;if (lastVisiableitem == totleItem && scrollState == OnScrollListener.SCROLL_STATE_IDLE &&!isRefresh){if (!isLoading){isLoading = true;isLoad = true;footer.setVisibility(View.VISIBLE);if (onLoadListener != null){onLoadListener.onLoad();}}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,int totalItemCount){this.firstVisiableItem = firstVisibleItem;this.lastVisiableitem = firstVisibleItem + visibleItemCount;this.totleItem = totalItemCount;}/** * 上拉加载监听 * * @author Administrator * */public interface OnLoadListener{void onLoad();}private OnLoadListener onLoadListener;public void setOnLoadListener(OnLoadListener onLoadListener){this.onLoadListener = onLoadListener;}/** * 下拉刷新监听 * * @author Administrator * */public interface OnRefreshListener{void onRefresh();}private OnRefreshListener onRefreshListener;public void setOnRefreshListener(OnRefreshListener onRefreshListener){this.onRefreshListener = onRefreshListener;}/** * 对于下拉加载的各种情况进行处理 1,数据还有很多,没有加载完成,下拉可以继续加载 2,数据本次加载完成,下次下拉不会再加载 * 3,数据已经之前巧合加载完成,不会再去加载 * * @param result */public void setFooterResult(int result){isLoad = false;System.out.println(result + "result");if (result == 10)// 还有剩余数据{isLoading = false;loading.setVisibility(View.VISIBLE);loadProgressbar.setVisibility(View.VISIBLE);noData.setVisibility(View.GONE);loadFull.setVisibility(View.GONE);footer.setVisibility(View.GONE);} else if (result < 10 && result > 0)// 已经完全没有数据可以加载,这是最后一次加载数据{isLoading = true;loading.setVisibility(View.GONE);loadProgressbar.setVisibility(View.GONE);noData.setVisibility(View.GONE);loadFull.setVisibility(View.VISIBLE);footer.setVisibility(View.VISIBLE);} else{isLoading = true;// 已经完全没有数据可以加载loading.setVisibility(View.GONE);loadProgressbar.setVisibility(View.GONE);noData.setVisibility(View.VISIBLE);loadFull.setVisibility(View.GONE);footer.setVisibility(View.VISIBLE);}}/** * 刷新完成之后需要做一些后续工作 */public void refreshCompleted(boolean flag){isRefresh = false;state = NONE;isRemark = false;if(flag){lastUpdate.setText(new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒", Locale.getDefault()).format(new Date()));}refreshHeaderViewByState();}}

由于这一篇blog是接着之前的,需要在OperaSumFragment之中去实现MyListView的接口,包括之前的一些处理,如下,代码

人生最大的错误是不断担心会犯错

Hoist the Colours! Our world is wide!

相关文章:

你感兴趣的文章:

标签云: