/** * Created by on 2016/12/2. * 自定义listview: * 一、下拉刷新: * 1. 添加头部布局,并设置位置隐藏 * 2. 监听滑动事件,判断当前显示在最顶端的item是否是第一个item * 3. 监听onTouch事件,根据下拉的距离来判断下来状态的变化 * 二、加载更多: * 1. 添加底部布局,并隐藏 * 2. 监听滑动事件,判断最后显示的item是不是最后一个item来决定是否加载更多 * 这里通过传递参数的方式来传递handler来延迟刷新 * (推荐)通过接口回调的方式可以实现加载数据 */ public class ReFlashListView extends ListView implements AbsListView.OnScrollListener{ private Handler handler;//这个handler用来做一个延时处理刷新 private View header;//头布局 private int headerHeight;//header的高度 int firstVisibleItem;//listview中可见的第一个item的位置 int visibleItemCount;//可见的item的数量 int totalItemCounts;//已经显示出来的总数量 int scrollState;//滑动状态 int state;//滑动的状态 final int NONE = 0; //正常状态 final int PULL = 1; //提示下拉状态 final int RELSE = 2; //提示释放状态 final int RELSING = 3; //正在刷新状态 private boolean isTop = false; //判断按下的时候当前显示在最上面一个item是listview的第一个item private int stateY;//按下的时候Y轴的位置 private ImageView iv_header; private TextView tv_header; private ProgressBar pg_header; private View footer;//底部布局 private boolean isLoading = false; public ReFlashListView(Context context) { super(context); initView(context); } public ReFlashListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public ReFlashListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } /** * 实例化handler */ public void setListViewHandler(Handler handler){ this.handler = handler; } /** * 给ListView添加头布局 * @param context */ private void initView(Context context){ header = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_header, null); iv_header = (ImageView) header.findViewById(R.id.iv_header); tv_header = (TextView) header.findViewById(R.id.tv_header); pg_header = (ProgressBar) header.findViewById(R.id.pg_header); measureHeight(header); headerHeight = header.getMeasuredHeight(); initHeaderTopPadding(); this.addHeaderView(header); loadFooter(context); this.setOnScrollListener(this); } /** * 加载底部布局 */ private void loadFooter(Context context){ footer = LayoutInflater.from(context).inflate(R.layout.activity_view_listview_footer, null); footer.findViewById(R.id.ll_load_more).setVisibility(View.GONE); this.addFooterView(footer); } /** * 初始化header的位置 */ public void initHeaderTopPadding(){ setTopPadding(-headerHeight); } /** * 设置header的高度:隐藏header */ private void setTopPadding(int topPadding) { header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom()); } /** * 高度父布局当前view的宽高 * 如果没有这一步,header.getMeasuredHeight() == 0 */ private void measureHeight(View view){ ViewGroup.LayoutParams p = view.getLayoutParams(); if(p == null){ p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.WRAP_CONTENT); } int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height; int temHeight = p.height; if(temHeight > 0){ height = MeasureSpec.makeMeasureSpec(temHeight , MeasureSpec.EXACTLY); }else { height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } view.measure(width, height); } /** * @param view * @param scrollState:即滑动的状态。分为三种 0,1,2 0 表示停止滑动的状态 SCROLL_STATE_IDLE 1表示正在滚动,用户手指在屏幕上 SCROLL_STATE_TOUCH_SCROLL 2表示正在滑动。用户手指已经离开屏幕 SCROLL_STATE_FLING */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { this.scrollState = scrollState; if((firstVisibleItem + visibleItemCount) == totalItemCounts && scrollState == SCROLL_STATE_IDLE){ if(!isLoading){ //显示出footer,并在这里加载数据 footer.findViewById(R.id.ll_load_more).setVisibility(View.VISIBLE); /** * TODO:加载数据 */ } } } /** * @param view * @param firstVisibleItem : 第一个可见的item的位置 * @param visibleItemCount : 可见的item的数量 * @param totalItemCount : 总的数量 */ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; this.visibleItemCount = visibleItemCount; this.totalItemCounts = totalItemCount; } /** * 监听滑动状态的改变 * @param ev * @return */ @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: if(firstVisibleItem == 0){//当前显示在最上面一个item是listview的第一个item state = NONE;//设置状态,表示继续下拉可以触发刷新 isTop = true; stateY = (int) ev.getY(); } break; case MotionEvent.ACTION_MOVE: reFlashing(ev); break; case MotionEvent.ACTION_UP: if(state == RELSE){ state = RELSING; reFlasTip(); //加载数据/** * TODO:刷新数据 */}else if(state == PULL){ state = NONE; isTop = false; reFlasTip(); } break; } return super.onTouchEvent(ev); } /** * 判断移动过程中的操作 */ private void reFlashing(MotionEvent ev){ if(!isTop){ return; } int evY = (int) ev.getY(); int spaceY = evY - stateY; int topPadding = spaceY - headerHeight; if(topPadding >= headerHeight * 3){ topPadding = headerHeight * 2; } switch (state){ case NONE: if(spaceY >= 0){ //表示往下拉动 state = PULL; reFlasTip(); } break; case PULL: setTopPadding(topPadding); if(spaceY >= headerHeight+20 && scrollState == SCROLL_STATE_TOUCH_SCROLL){ //表示往下拉动,并且正在滚动 state = RELSE; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; case RELSE: setTopPadding(topPadding); if(spaceY < headerHeight){ state = PULL; reFlasTip(); }else if(spaceY <= 0){ state = NONE; isTop = false; reFlasTip(); } break; } } /** * 根据下拉状态的变化改变header的提示 */ private void reFlasTip(){ switch (state){ case NONE: setTopPadding(-headerHeight); break; case PULL: tv_header.setText("下拉可以刷新"); break; case RELSE: tv_header.setText("松开可以刷新"); break; case RELSING: setTopPadding(headerHeight); tv_header.setText("正在刷新"); break; } }}
自定义ListView下拉刷新,上拉加载
最新推荐文章于 2024-06-19 18:08:01 发布