• android118 上拉下拉刷新列表listView实现


    MainActivity。java

    package com.heima52.pullrefresh;
    
    import java.util.ArrayList;
    
    import com.heima52.pullrefresh.view.RefreshListView;
    import com.heima52.pullrefresh.view.RefreshListView.OnRefreshListener;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.SystemClock;
    import android.app.Activity;
    import android.util.Log;
    import android.view.Menu;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.ViewTreeObserver.OnGlobalLayoutListener;
    import android.view.Window;
    import android.widget.BaseAdapter;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
        private RefreshListView refreshListView;
        
        private ArrayList<String> list = new ArrayList<String>();
    
        private MyAdapter adapter;
        
        private Handler handler = new Handler(){
            public void handleMessage(android.os.Message msg) {
                //更新UI,改变集合
                adapter.notifyDataSetChanged();
                refreshListView.completeRefresh();
            };
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            initView();
            initData();//要在initView()方法之后
        }
        
        private void initView() {
            requestWindowFeature(Window.FEATURE_NO_TITLE);//修改当前Activity的主题:没有TITLE
            setContentView(R.layout.activity_main);
            refreshListView = (RefreshListView) findViewById(R.id.refreshListView);
        }
        
        private void initData() {
            for (int i = 0; i < 15; i++) {
                list.add("listview原来的数据 - "+i);
            }
            
            //第一种方法
            final View headerView = View.inflate(this, R.layout.layout_header, null);//这个操作是异步的,控件还没有加载完成,所以下面获取控件高度为0,
            headerView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {//在headerView控件加载完成后执行,此时就可以获得控件的高度了。
                    headerView.getViewTreeObserver().removeGlobalOnLayoutListener(this);//这个监听器要即使移除,因为他的子view重绘时也会调用这个方法,所以要移除。
                    int headerViewHeight = headerView.getHeight();//获得控件的高度
                    Log.e("MainActivity", "headerViewHeight: "+headerViewHeight);
                    headerView.setPadding(0, -headerViewHeight, 0, 0);
                    refreshListView.addHeaderView(headerView);//
                }
            });
            //第二种方法
            headerView.measure(0, 0);//主动通知系统去测量然后就会去主动加载该控件。
            int headerViewHeight = headerView.getMeasuredHeight();//获得控件的高度
            Log.e("MainActivity", "headerViewHeight: "+headerViewHeight);//这个值是0,
            headerView.setPadding(0, -headerViewHeight, 0, 0);//设置负高度把headerView隐藏
            refreshListView.addHeaderView(headerView);//ListView添加一个Header,Header是一个view.addHeaderView必须在setAdapter之前调用
            
            
            //第三种
            adapter = new MyAdapter();
            refreshListView.setAdapter(adapter);
            
            refreshListView.setOnRefreshListener(new OnRefreshListener() {
                @Override
                public void onPullRefresh() {
                    //需要联网请求服务器的数据,然后更新UI
                    requestDataFromServer(false);
                }
    
                @Override
                public void onLoadingMore() {
                    requestDataFromServer(true);
                }
            });
            
        }
        /**
         * 模拟向服务器请求数据
         */
        private void requestDataFromServer(final boolean isLoadingMore){
            new Thread(){
                public void run() {
                    SystemClock.sleep(3000);//模拟请求服务器的一个时间长度
                    
                    if(isLoadingMore){
                        list.add("加载更多的数据-1");
                        list.add("加载更多的数据-2");
                        list.add("加载更多的数据-3");
                    }else {
                        list.add(0, "下拉刷新的数据");
                    }
                    
                    //在UI线程更新UI
                    handler.sendEmptyMessage(0);
                };
            }.start();
        }
        
        class MyAdapter extends BaseAdapter{
            @Override
            public int getCount() {
                return list.size();
            }
            @Override
            public Object getItem(int position) {
                return null;
            }
            @Override
            public long getItemId(int position) {
                return 0;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                TextView textView = new TextView(MainActivity.this);//不需要使用布局文件,动态创建一个TextView
                textView.setPadding(20, 20, 20, 20);
                textView.setTextSize(18);
                
                textView.setText(list.get(position));
                
                return textView;
            }
            
        }
    
    }

    activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
    
        <!-- 自定义的view:ListView-->
        <com.heima52.pullrefresh.view.RefreshListView
            android:id="@+id/refreshListView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </com.heima52.pullrefresh.view.RefreshListView>
    
    </RelativeLayout>

    RefreshListView。java

    package com.heima52.pullrefresh.view;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import com.heima52.pullrefresh.R;
    
    import android.widget.AbsListView.OnScrollListener;
    import android.R.integer;
    import android.content.Context;
    import android.os.Handler;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.RotateAnimation;
    import android.widget.AbsListView;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    public class RefreshListView extends ListView implements OnScrollListener{
    
        private View headerView;//headerView
        private ImageView iv_arrow;
        private ProgressBar pb_rotate;
        private TextView tv_state,tv_time;
        private View footerView;
        private int footerViewHeight;
        
        private int headerViewHeight;//headerView高
        
        private int downY;//按下时y坐标
        
        private final int PULL_REFRESH = 0;//下拉刷新的状态
        private final int RELEASE_REFRESH = 1;//松开刷新的状态
        private final int REFRESHING = 2;//正在刷新的状态
        private int currentState = PULL_REFRESH;
        
        private RotateAnimation upAnimation,downAnimation;
        
        private boolean isLoadingMore = false;//当前是否正在处于加载更多
    
        public RefreshListView(Context context) {
            super(context);
            init();
        }
    
        public RefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
        
        private void init(){
            setOnScrollListener(this);
            initHeaderView();
            initRotateAnimation();
            initFooterView();
        }
    
    
        /**
         * 初始化headerView,刷新头。
         */
        private void initHeaderView() {
            headerView = View.inflate(getContext(), R.layout.layout_header, null);
            iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
            pb_rotate = (ProgressBar) headerView.findViewById(R.id.pb_rotate);
            tv_state = (TextView) headerView.findViewById(R.id.tv_state);
            tv_time = (TextView) headerView.findViewById(R.id.tv_time);
            
            headerView.measure(0, 0);//主动通知系统去测量该view,然后就可以获取控件的高度;
            headerViewHeight = headerView.getMeasuredHeight();
            headerView.setPadding(0, -headerViewHeight, 0, 0);
            
            addHeaderView(headerView);//listView的方法,加载view到头部。
        }
        
        /**
         * 初始化旋转动画
         */
        private void initRotateAnimation() {
            upAnimation = new RotateAnimation(0, -180, //旋转动画,从0到-180度,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f,//中心点是自身的一半处
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            upAnimation.setDuration(300);
            upAnimation.setFillAfter(true);
            downAnimation = new RotateAnimation(-180, -360, 
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            downAnimation.setDuration(300);
            downAnimation.setFillAfter(true);
        }
        
        //初始化底部的刷新
        private void initFooterView() {
            footerView = View.inflate(getContext(), R.layout.layout_footer, null);
            footerView.measure(0, 0);//主动通知系统去测量该view;
            footerViewHeight = footerView.getMeasuredHeight();
            footerView.setPadding(0, -footerViewHeight, 0, 0);//把底部隐藏起来
            addFooterView(footerView);//listView的方法,加载view放在底部。
        }
        
        @Override
        public boolean onTouchEvent(MotionEvent ev) {//手向下滑动的时候,上面隐藏的慢慢出现。
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN://手指按下就获取手指远离顶部的距离。
                downY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                
                if(currentState==REFRESHING){//如果是正在刷新状态则不能滑动。
                    break;
                }
                
                int deltaY = (int) (ev.getY() - downY);//手指滑动就或获取手指滑动的距离
                
                int paddingTop = -headerViewHeight + deltaY;//paddingTop是刷新头的上边距离,
                //paddingTop=0则刷新头全部显示,paddingTop<0则刷新头进入顶部,paddingTop = -headerViewHeight表示刷新头全部进入顶部,paddingTop>0则刷新头刷离顶部
                if(paddingTop>-headerViewHeight && getFirstVisiblePosition()==0){//getFirstVisiblePsition表示当前listView第一个显示的是第0个,
                    headerView.setPadding(0, paddingTop, 0, 0);
                    Log.e("RefreshListView", "paddingTop: "+paddingTop);
                    
                    if(paddingTop>=0 && currentState==PULL_REFRESH){
                        //从下拉刷新进入松开刷新状态
                        currentState = RELEASE_REFRESH;
                        refreshHeaderView();
                    }else if (paddingTop<0 && currentState==RELEASE_REFRESH) {
                        //进入下拉刷新状态
                        currentState = PULL_REFRESH;
                        refreshHeaderView();
                    }
                    
                    
                    return true;//拦截TouchMove,不让listview处理该次move事件则造成listview无法滑动
                }
                
                
                break;
            case MotionEvent.ACTION_UP:
                if(currentState==PULL_REFRESH){//刷新头还未全部出来则回去隐藏headerView
                    //隐藏headerView
                    headerView.setPadding(0, -headerViewHeight, 0, 0);
                }else if (currentState==RELEASE_REFRESH) {//刷新头全部滑动出来了则回去但不隐藏headerView
                    headerView.setPadding(0, 0, 0, 0);
                    currentState = REFRESHING;
                    refreshHeaderView();
                    
                    if(listener!=null){
                        listener.onPullRefresh();
                    }
                }
                break;
            }
            return super.onTouchEvent(ev);
        }
        
        /**
         * 根据currentState来更新headerView
         */
        private void refreshHeaderView(){
            switch (currentState) {
            case PULL_REFRESH:
                tv_state.setText("下拉刷新");
                iv_arrow.startAnimation(downAnimation);//给箭头设置向下的箭头旋转动画,则箭头会旋转。
                break;
            case RELEASE_REFRESH:
                tv_state.setText("松开刷新");
                iv_arrow.startAnimation(upAnimation);//给箭头设置向上的箭头旋转动画,则箭头会旋转。
                break;
            case REFRESHING:
                iv_arrow.clearAnimation();//因为向上的旋转动画有可能没有执行完
                iv_arrow.setVisibility(View.INVISIBLE);//垂直箭头隐藏
                pb_rotate.setVisibility(View.VISIBLE);//环形旋转箭头动画显示
                tv_state.setText("正在刷新...");
                break;
            }
        }
        
        /**
         * 数据完成刷新操作,重置为初始未滑动的状态,
         * 在你获取完数据并更新完adater之后,去在UI线程中调用该方法
         */
        public void completeRefresh(){
            if(isLoadingMore){
                //重置footerView状态
                footerView.setPadding(0, -footerViewHeight, 0, 0);
                isLoadingMore = false;
            }else {
                //重置headerView状态
                headerView.setPadding(0, -headerViewHeight, 0, 0);
                currentState = PULL_REFRESH;
                pb_rotate.setVisibility(View.INVISIBLE);
                iv_arrow.setVisibility(View.VISIBLE);
                tv_state.setText("下拉刷新");
                tv_time.setText("最后刷新:"+getCurrentTime());
            }
        }
        
        /**
         * 获取当前系统时间,并格式化
         * @return
         */
        private String getCurrentTime(){
            SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
            return format.format(new Date());
        }
        
        private OnRefreshListener listener;
        public void setOnRefreshListener(OnRefreshListener listener){
            this.listener = listener;
        }
        public interface OnRefreshListener{
            void onPullRefresh();
            void onLoadingMore();
        }
        
        /**OnScrollListener监听器的方法
         * 
         * SCROLL_STATE_IDLE:闲置状态,就是手指松开
         * SCROLL_STATE_TOUCH_SCROLL:手指触摸滑动,就是按着来滑动
         * SCROLL_STATE_FLING:快速滑动后松开
         */
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if(scrollState==OnScrollListener.SCROLL_STATE_IDLE 
                    && getLastVisiblePosition()==(getCount()-1) &&!isLoadingMore){
                isLoadingMore = true;//滑倒了底部就不会在进来了
                //滑到底部的时候才显示footerView
                footerView.setPadding(0, 0, 0, 0);
                setSelection(getCount());//setSelection是listView的方法,将对应位置的item放置到屏幕顶端,让listview最后一条显示出来。
                
                if(listener!=null){
                    listener.onLoadingMore();
                }
            }
        }
        
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
        }
    
    }

    layout_footer.xml

    底部的刷新。
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal" >
    
        <ProgressBar
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:indeterminate="true"
            android:indeterminateDrawable="@drawable/indeterminate_drawable"   底部的旋转动画
            android:indeterminateDuration="1000" />
    
        <TextView android:layout_width="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:layout_height="wrap_content"
            android:textColor="#aa000000"
            android:layout_marginLeft="15dp"
            android:textSize="20sp"
            android:text="加载更多..."/>
    </LinearLayout>

    layout_header.xml

    下拉出去后 ,顶部垂直箭头和刷新转圈。
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"   水平居中
        android:orientation="horizontal" >
            
        <!-- 垂直箭头和环形箭头是叠加在一起的,因此用相对布局 -->
        <RelativeLayout android:layout_width="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:layout_height="wrap_content">
            
            <ImageView android:layout_width="wrap_content"    垂直箭头图片
                android:layout_centerInParent="true"          父窗体居中
                android:id="@+id/iv_arrow"
                android:background="@drawable/indicator_arrow"   
                android:layout_height="wrap_content"/>
            
            <ProgressBar android:layout_width="30dp"     环形箭头转圈图片
                android:layout_centerInParent="true"     父窗体居中
                android:layout_height="30dp"
                android:visibility="invisible"            
                android:id="@+id/pb_rotate"
                android:indeterminateDuration="1000"     一秒钟转一圈
                   android:indeterminateDrawable="@drawable/indeterminate_drawable"  环形箭头旋转动画indeterminate_drawable.xml
                />
            
        </RelativeLayout>
        
        <LinearLayout android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:gravity="center"                   垂直水平居中
            android:layout_marginLeft="15dp"
            android:orientation="vertical">   
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:id="@+id/tv_state"
                android:textColor="#aa000000"
                android:text="下拉刷新"/>
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="14sp"
                android:id="@+id/tv_time"
                android:textColor="@android:color/darker_gray"
                android:text="最后刷新:"/>
            
        </LinearLayout>
    
    </LinearLayout>

    indeterminate_drawable.xml

    环形箭头旋转动画
    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android" 
        android:fromDegrees="0"  旋转从0到360度
        android:toDegrees="360" 
        android:pivotX="50%"  旋转基于的中心点
        android:pivotY="50%"
        android:drawable="@drawable/indicate_rotate"   要旋转的动画
        >
        
    
    </rotate>
    下拉刷新-------
        1.addHeaderView必须在setAdapter之前调用
        2.将paddingTop设置一个headerView高度的负值去隐藏它
        
        加载布局控件:加载文件——解析标签——测量控件——布局控件——绘制控件
        
        getHeight()和getMeasuredHeight()的区别:
        getMeasuredHeight():获取测量完的高度,只要在onMeasure测量方法执行完,就可以用
                            它获取到宽高,在自定义控件内部多使用这个
                            使用view.measure(0,0)方法可以主动通知系统去测量,然后就
                            可以直接使用它获取宽高
        getHeight():必须在onLayout方法执行完后,才能获得宽高
                    view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                        @Override
                        public void onGlobalLayout() {
                        headerView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        int headerViewHeight = headerView.getHeight();
                        //直接可以获取宽高
                }
            });
        3.setSelection(position);将对应位置的item放置到屏幕顶端
  • 相关阅读:
    JS判断字符串是否为空或是否全为空格
    分页-jquery.page.js插件在使用时重复触发“上一页”和“下一页”操作
    JS IE 打开本地exe程序
    bootstrap中的模态框(modal,弹出层)
    attr()、prop()、css() 的区别
    java-ActiveMQ
    java-webSocket
    java-普通类文件@Autowired自动注入为null
    HTML5<canvas>标签:使用canvas元素在网页上绘制四分之一圆(3)
    HTML5<canvas>标签:使用canvas元素在网页上绘制渐变和图像(2)
  • 原文地址:https://www.cnblogs.com/yaowen/p/5011232.html
Copyright © 2020-2023  润新知