zoukankan      html  css  js  c++  java
  • ListView装上拉电阻下拉刷新


    主要用到了这个几个文件。MainActivity是界面的Activity,MyAdapter是ListView的自己定义适配,MyListView是自己定义带头部LIistView,假设仅仅须要上拉载入就不须要;activity_main.xml是住界面。item.xml是ListView的子布局里面仅仅有一个TextView,listview_footer.xml是listview的载入很多其它的底部布局,listview_header.xml是listview的头部布局。


    MainActivity.java

    package com.example.listview;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.Toast;
    
    import com.example.listview.MyListView.OnRefreshListener;
    
    public class MainActivity extends Activity implements OnScrollListener{
    	/** ListView*/
    	private MyListView listView;
    	/** 自己定义的Adapter*/
    	private MyAdapter adapter;
    	/** 一共的数据*/
    	private List<String> list=new ArrayList<String>();
    	/** ListView的底部布局*/
    	private View footer;
    
    	private Handler handler;
    	 
    	private int count=0;
    	
    	
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		/** 配置好ListView*/
    		listView=(MyListView) findViewById(R.id.listView);
    
    		/** 加入底部布局,要在setAdapter前,否则没有效果*/
    		footer=LayoutInflater.from(this).inflate(R.layout.listview_footer, null);
    		listView.addFooterView(footer);
    	
    		/** 适配listView*/
    		adapter=new MyAdapter(this, list);
    		listView.setAdapter(adapter);
    		
    		/** 加入一个线程设置时间有等待的效果*/
    		handler=new Handler();
    
    		listView.setOnScrollListener(this);
    
    		listView.setonRefreshListener(new OnRefreshListener() {
    
    	            @Override
    	         public void onRefresh() {
    	                new AsyncTask<Void, Void, Void>() {
    	                    protected Void doInBackground(Void... params) {
    	                        try {
    	                            Thread.sleep(1000);
    	                        } catch (Exception e) {
    	                            e.printStackTrace();
    	                        }
    	                       // list.add("刷新后加入的内容");
    	                        return null;
    	                    }
    
    	                    @Override
    	                    protected void onPostExecute(Void result) {
    	                        adapter.notifyDataSetChanged();
    	                        listView.onRefreshComplete();
    	                    }
    	                }.execute(null, null, null);
    	                
    	            }
    	       });
    		 
    		setData();  
    		
    	}
    
    	/**
    	 * 底部滚动的监听 
    	 */
    	@Override
    	public void onScrollStateChanged(final AbsListView view, int scrollState) {
    		/** 当滚动停止同一时候在底部的时候*/
    	     if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && (view.getLastVisiblePosition() == view.getCount() - 1)) {
    	    		/** 为了有数据载入等待的时间。假设是网络数据请求,则此处不须要直接请求接口就ok*/
    	                handler.postDelayed(new Runnable() {
    
    	                    @Override
    	                    public void run() {
    	                    	setData();
    	                    	/** 让刷新出来的数据从屏幕開始显示,假设不设定位置,listView数据更新后会跑到第一条数据開始显示*/
    	                    	listView.setSelection(view.getCount()-1);
    	                    }
    
    	                }, 2000);
    	                
    	     }
    	     
    	}
    	@Override
    	public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
    	
    	}
    	/** 放数据,假设你的数据能够分页获取就不须要这样,此处是为了有分页的数据*/
    	@SuppressLint("ShowToast")
    	private void setData(){
    		
    		//当数据到达总量的时候移除底部布局
    		if(count>50){
    			
    			listView.removeFooterView(footer);
    			
    			Toast.makeText(this,"没有很多其它数据", 500).show();
    			
    			return;
    		}
    		
    		for(int i=count;i<count+10;i++){
    			
    			
    			list.add("数据"+i);
    			
    		}
    		
    		count=count+10;
    		/** 通知adapter数据改变*/
    		adapter.notifyDataSetChanged();
    	}
    }
    

    MyListView.java


    package com.example.listview;
    
    import java.util.Date;
    
    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.LinearInterpolator;
    import android.view.animation.RotateAnimation;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    /**
     * ListView加入刷新头部自己定义的ListView
     * 
     * @author 刘梓未
     * 
     *
     */
    public class MyListView extends ListView implements OnScrollListener {
    
        private final static int RELEASE_To_REFRESH = 0;// 下拉过程的状态值
        private final static int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值
        private final static int REFRESHING = 2;// 正在刷新的状态值
        private final static int DONE = 3;
        private final static int LOADING = 4;
    
        // 实际的padding的距离与界面上偏移距离的比例
        private final static int RATIO = 3;
        private LayoutInflater inflater;
    
        // ListView头部下拉刷新的布局
        private LinearLayout headerView;
        private TextView lvHeaderTipsTv;
        private TextView lvHeaderLastUpdatedTv;
        private ImageView lvHeaderArrowIv;
        private ProgressBar lvHeaderProgressBar;
    
        // 定义头部下拉刷新的布局的高度
        private int headerContentHeight;
    
        private RotateAnimation animation;
        private RotateAnimation reverseAnimation;
    
        private int startY;
        private int state;
        private boolean isBack;
    
        // 用于保证startY的值在一个完整的touch事件中仅仅被记录一次
        private boolean isRecored;
    
        private OnRefreshListener refreshListener;
    
        private boolean isRefreshable;
    
        public MyListView(Context context) {
            super(context);
            init(context);
        }
    
        public MyListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        private void init(Context context) {
            setCacheColorHint(context.getResources().getColor(android.R.color.transparent));
            inflater = LayoutInflater.from(context);
            headerView = (LinearLayout) inflater.inflate(R.layout.listview_header, null);
            lvHeaderTipsTv = (TextView) headerView
                    .findViewById(R.id.lvHeaderTipsTv);
            lvHeaderLastUpdatedTv = (TextView) headerView
                    .findViewById(R.id.lvHeaderLastUpdatedTv);
    
            lvHeaderArrowIv = (ImageView) headerView
                    .findViewById(R.id.lvHeaderArrowIv);
            // 设置下拉刷新图标的最小高度和宽度
            lvHeaderArrowIv.setMinimumWidth(70);
            lvHeaderArrowIv.setMinimumHeight(50);
    
            lvHeaderProgressBar = (ProgressBar) headerView
                    .findViewById(R.id.lvHeaderProgressBar);
            measureView(headerView);
            headerContentHeight = headerView.getMeasuredHeight();
            // 设置内边距,正好距离顶部为一个负的整个布局的高度,正好把头部隐藏
            headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
            // 重绘一下
            headerView.invalidate();
            // 将下拉刷新的布局加入ListView的顶部
            addHeaderView(headerView, null, false);
            // 设置滚动监听事件
            setOnScrollListener(this);
    
            // 设置旋转动画事件
            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(200);
            reverseAnimation.setFillAfter(true);
    
            // 一開始的状态就是下拉刷新完的状态。所以为DONE
            state = DONE;
            // 是否正在刷新
            isRefreshable = false;
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if (isRefreshable) {
                switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (!isRecored) {
                        isRecored = true;
                        startY = (int) ev.getY();// 手指按下时记录当前位置
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (state != REFRESHING && state != LOADING) {
                        if (state == PULL_To_REFRESH) {
                            state = DONE;
                            changeHeaderViewByState();
                        }
                        if (state == RELEASE_To_REFRESH) {
                            state = REFRESHING;
                            changeHeaderViewByState();
                            onLvRefresh();
                        }
                    }
                    isRecored = false;
                    isBack = false;
    
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    int tempY = (int) ev.getY();
                    if (!isRecored) {
                        isRecored = true;
                        startY = tempY;
                    }
                    if (state != REFRESHING && isRecored && state != LOADING) {
                        // 保证在设置padding的过程中,当前的位置一直是在head。否则假设当列表超出屏幕的话,当在上推的时候。列表会同一时候进行滚动
                        // 能够松手去刷新了
                        if (state == RELEASE_To_REFRESH) {
                            setSelection(0);
                            // 往上推了。推到了屏幕足够掩盖head的程度,可是还没有推到所有掩盖的地步
                            if (((tempY - startY) / RATIO < headerContentHeight)// 由松开刷新状态转变到下拉刷新状态
                                    && (tempY - startY) > 0) {
                                state = PULL_To_REFRESH;
                                changeHeaderViewByState();
                            }
                            // 一下子推到顶了
                            else if (tempY - startY <= 0) {// 由松开刷新状态转变到done状态
                                state = DONE;
                                changeHeaderViewByState();
                            }
                        }
                        // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
                        if (state == PULL_To_REFRESH) {
                            setSelection(0);
                            // 下拉到能够进入RELEASE_TO_REFRESH的状态
                            if ((tempY - startY) / RATIO >= headerContentHeight) {// 由done或者下拉刷新状态转变到松开刷新
                                state = RELEASE_To_REFRESH;
                                isBack = true;
                                changeHeaderViewByState();
                            }
                            // 上推到顶了
                            else if (tempY - startY <= 0) {// 由DOne或者下拉刷新状态转变到done状态
                                state = DONE;
                                changeHeaderViewByState();
                            }
                        }
                        // done状态下
                        if (state == DONE) {
                            if (tempY - startY > 0) {
                                state = PULL_To_REFRESH;
                                changeHeaderViewByState();
                            }
                        }
                        // 更新headView的size
                        if (state == PULL_To_REFRESH) {
                            headerView.setPadding(0, -1 * headerContentHeight
                                    + (tempY - startY) / RATIO, 0, 0);
    
                        }
                        // 更新headView的paddingTop
                        if (state == RELEASE_To_REFRESH) {
                            headerView.setPadding(0, (tempY - startY) / RATIO
                                    - headerContentHeight, 0, 0);
                        }
    
                    }
                    break;
    
                default:
                    break;
                }
            }
            return super.onTouchEvent(ev);
        }
    
        // 当状态改变时候。调用该方法。以更新界面
        private void changeHeaderViewByState() {
            switch (state) {
            case RELEASE_To_REFRESH:
                lvHeaderArrowIv.setVisibility(View.VISIBLE);
                lvHeaderProgressBar.setVisibility(View.GONE);
                lvHeaderTipsTv.setVisibility(View.VISIBLE);
                lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
    
                lvHeaderArrowIv.clearAnimation();// 清除动画
                lvHeaderArrowIv.startAnimation(animation);// 開始动画效果
    
                lvHeaderTipsTv.setText("松开刷新");
                break;
            case PULL_To_REFRESH:
                lvHeaderProgressBar.setVisibility(View.GONE);
                lvHeaderTipsTv.setVisibility(View.VISIBLE);
                lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
                lvHeaderArrowIv.clearAnimation();
                lvHeaderArrowIv.setVisibility(View.VISIBLE);
                // 是由RELEASE_To_REFRESH状态转变来的
                if (isBack) {
                    isBack = false;
                    lvHeaderArrowIv.clearAnimation();
                    lvHeaderArrowIv.startAnimation(reverseAnimation);
    
                    lvHeaderTipsTv.setText("下拉刷新");
                } else {
                    lvHeaderTipsTv.setText("下拉刷新");
                }
                break;
    
            case REFRESHING:
    
                headerView.setPadding(0, 0, 0, 0);
    
                lvHeaderProgressBar.setVisibility(View.VISIBLE);
                lvHeaderArrowIv.clearAnimation();
                lvHeaderArrowIv.setVisibility(View.GONE);
                lvHeaderTipsTv.setText("正在刷新...");
                lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
                break;
            case DONE:
                headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
    
                lvHeaderProgressBar.setVisibility(View.GONE);
                lvHeaderArrowIv.clearAnimation();
                lvHeaderArrowIv.setImageResource(R.drawable.head_arrow);
                lvHeaderTipsTv.setText("下拉刷新");
                lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
                break;
            }
        }
    
        // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“预计”headView的width以及height
        private void measureView(View child) {
            ViewGroup.LayoutParams params = child.getLayoutParams();
            if (params == null) {
                params = new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
            }
            int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0,
                    params.width);
            int lpHeight = params.height;
            int childHeightSpec;
            if (lpHeight > 0) {
                childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
                        MeasureSpec.EXACTLY);
            } else {
                childHeightSpec = MeasureSpec.makeMeasureSpec(0,
                        MeasureSpec.UNSPECIFIED);
            }
            child.measure(childWidthSpec, childHeightSpec);
        }
    
        public void setonRefreshListener(OnRefreshListener refreshListener) {
            this.refreshListener = refreshListener;
            isRefreshable = true;
        }
    
        public interface OnRefreshListener {
            public void onRefresh();
        }
    
        @SuppressWarnings("deprecation")
    	public void onRefreshComplete() {
            state = DONE;
            lvHeaderLastUpdatedTv.setText("近期更新:" + new Date().toLocaleString());
            changeHeaderViewByState();
        }
    
        private void onLvRefresh() {
            if (refreshListener != null) {
                refreshListener.onRefresh();
            }
        }
    
    
    
    }

    listview_footer.xml

    <?

    xml version="1.0" encoding="utf-8"?

    > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:layout_marginTop="10dp" android:orientation="horizontal" > <ProgressBar android:id="@+id/footer_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>


    listview_header.xml



    <?xml version="1.0" encoding="utf-8"?>
    <!-- ListView的头部 -->
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    
        <!-- 内容 -->
    
        <RelativeLayout
            android:id="@+id/head_contentLayout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/list_header_bg"
            android:paddingLeft="30dp">
    
            <!-- 箭头图像、进度条 -->
    
            <FrameLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true" >
    
                <!-- 箭头 -->
    
                <ImageView
                    android:id="@+id/lvHeaderArrowIv"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:src="@drawable/head_arrow" />
    
                <!-- 进度条 -->
    
                <ProgressBar
                    android:id="@+id/lvHeaderProgressBar"
                    style="?android:attr/progressBarStyleSmall"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:visibility="gone" />
            </FrameLayout>
    
            <!-- 提示、近期更新 -->
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:gravity="center_horizontal"
                android:orientation="vertical" >
    
                <!-- 提示 -->
    
                <TextView
                    android:id="@+id/lvHeaderTipsTv"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="下拉刷新"
                    android:textSize="13sp" />
    
                <!-- 近期更新 -->
    
                <TextView
                    android:id="@+id/lvHeaderLastUpdatedTv"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="最新更新"
                    android:textSize="10sp" />
            </LinearLayout>
        </RelativeLayout>
    
    </LinearLayout>

    下载链接


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    MVC是什么?
    Slice Header中的field_pic_flag的含义?
    Slice header 中的frame_num的含义?
    上下文管理器 contextlib
    mixin模式特点
    Flask中路由原理
    使用Docker搭建Django,Nginx,R,Python部署环境
    使用Docker+Jenkins自动构建部署
    Jenkins 关闭和重启
    使用pipenv管理python项目
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4837804.html
Copyright © 2011-2022 走看看