zoukankan      html  css  js  c++  java
  • Android--简单的自定义ListView下拉刷新

    ListView下拉刷新一般要注意以下几点:

    1. listview的头布局

    2. 注意标志的应用,即刷新的几个状态,分别是下拉刷新,松开刷新和正在刷新

    3. 注意几个动画效果,即箭头旋转,刷新图标旋转等

    先上效果图:

                                 

                                                                                                                                   下面,我们来分别介绍。

    先来说说这个demo里用到的几个方法。

    (1)public boolean onTouchEvent(MotionEvent ev):这个方法是手势触摸事件。这里主要用到了MotionEvent.ACTION_DOWN(手势按下)、MotionEvent.ACTION_MOVE(手势滑动)和MotionEvent.ACTION_UP(手指抬起手势)。

     

    下拉刷新,是先将listview的头部隐藏,然后用手势拖动屏幕刷新。那么,listview的头部如何隐藏呢?这里用的是header.setPadding(0,-headerViewHeight,0,0)来隐藏头部,这里不细说,等下介绍。如图1所示,要让listview的头部跟着手势一起向下滑动,则需要记录手指移动的距离。所以,当MotionEvent.ACTION_DOWN(手势按下)触发时,需要一个downY记录手势按下时y的偏移值,然后随着手势的滑动即MotionEvent.ACTION_MOVE(手势滑动)触发时,又需要一个moveY记录移动的偏移值,然后paddingTop=moveY-downY得到的就是手指滑动的距离。然后用paddingTop-headerViewHeight(相减的值设为x)得到头部的顶部到屏幕的顶部距离。如果想x>0则说明头部完全显示,如果x<0则头部没有完全显示。

     

    这里要设置几个标志位

    PULL_DOWN_REFRESH(下拉刷新):当头部未完全显示时为下拉刷新状态。

    RELEASE_REFRESH(释放刷新):当头部完全显示时为释放刷新状态。

    REFRESHING(正在刷新):当手势抬起,并头部完全显示时为正在刷新。

     

    其他的都比较简单,在程序里都有注释,这里就不再赘述了。上代码:

    RefreshListView.java

    package com.example.yds.pulldowntest;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.RotateAnimation;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.AbsListView;
    import android.widget.TextView;
    
    import org.w3c.dom.Text;
    
    /**
     * Created by yds on 2017/1/10.
     */
    
    public class RefreshListView extends ListView implements AbsListView.OnScrollListener {
        //头布局视图
        private View header;
        //头布局高度
        private int headerViewHeight;
        //按下时y的偏移量
        private int downY;
        //移动时y的偏移量
        private int moveY;
        //距离顶部的距离
        private int paddingTop;
        //listview第一个可见的item项
        private int firstVisibleItemPosition;
        //下拉刷新
        private final int PULL_DOWN_REFRESH = 0;
        //释放刷新
        private  final int RELEASE_REFRESH = 1;
        //正在刷新
        private final int REFRESHING = 2;
        //当前状态,默认为下拉刷新
        private int currentState = PULL_DOWN_REFRESH;
        //刷新列表构造函数
        private Context context;
        //刷新监听
        private OnRefreshListener mOnRefreshListener;
        private ImageView refresh;
        private RotateAnimation animation;
        //图片向上旋转
        private Animation upAnimation;
        //图片向下旋转
        private Animation downAnimation;
        //箭头
        private ImageView row;
        //提示文本
        private TextView header_tv;
        public RefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            //初始化头布局
            initHeaderView();
            //滑动监听
            this.setOnScrollListener(this);
            this.context = context;
        }
    
        /**滚动状态改变时调用,一般用于列表视图和网格视图
         *
         * @param view
         * @param scrollState 有三种值,分别是SCROLL_STATE_IDLE,SCROLL_STATE_TOUCH_SCROLL,SCROLL_STATE_FLING
         *                    SCROLL_STATE_IDLE:当屏幕停止滚动时
         *                    SCROLL_STATE_TOUCH_SCROLL:当屏幕以触屏方式滚动并且手指还在屏幕上时
         *                    SCROLL_STATE_FLING:当用户之前滑动屏幕并抬起手指,屏幕以惯性滚动
         */
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (scrollState==SCROLL_STATE_IDLE||scrollState == SCROLL_STATE_FLING){
    
            }
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            firstVisibleItemPosition = firstVisibleItem;
        }
    //    public void setOnRefreshListener(OnRefreshListener listener){
    //
    //    }
    
        public void setOnRefreshListener(OnRefreshListener listener){
            mOnRefreshListener = listener;
        }
    
        private void initHeaderView(){
            //头布局文件
            header = LayoutInflater.from(getContext()).inflate(R.layout.header,null);
            //测量头布局,绘制一个视图一般经过measure,layout,draw
            header.measure(0,0);
            //头布局高度
            headerViewHeight = header.getMeasuredHeight();
            //设置间隔
            header.setPadding(0,-headerViewHeight,0,0);
            //加载头布局
            this.addHeaderView(header);
            refresh = (ImageView) header.findViewById(R.id.refresh);
            row = (ImageView) header.findViewById(R.id.row);
            header_tv = (TextView) header.findViewById(R.id.header_tv);
            initAnimation();
    
        }
        private void initAnimation(){
            animation = new RotateAnimation(0f,360f, Animation.RELATIVE_TO_SELF,0.48f,Animation.RELATIVE_TO_SELF,0.47f);
            animation.setDuration(500);
            animation.setRepeatCount(5);
    
            upAnimation = new RotateAnimation(0f,180f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
            upAnimation.setDuration(300);
            upAnimation.setFillAfter(true);
    
            downAnimation = new RotateAnimation(180f,360f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
            downAnimation.setDuration(300);
            downAnimation.setFillAfter(true);
    //        refresh.setAnimation(animation);
    
        }
    
        /**
         * 触摸事件
         * @param ev
         * @return
         */
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()){
                //手指按下
                case MotionEvent.ACTION_DOWN:
                    //记录按下时y的偏移量
                    downY = (int) ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE://手指滑动
                    //记录移动时的y值偏移
                    moveY = (int) ev.getY();
                    //可以看成头布局距离屏幕顶部的距离,这里除以2是控制手指滑动
                    paddingTop = (moveY - downY)/2-headerViewHeight;
                    if(firstVisibleItemPosition==0&&-headerViewHeight<paddingTop){//必须的条件
                        //如果paddingTop>0就说明完全显示了,但还要判断当前状态是否是下拉刷新状态,因为正在刷新状态也是完全显示
                        if(paddingTop>0&&currentState == PULL_DOWN_REFRESH){//完全显示
                            header_tv.setText("松开刷新");
                            //将当前状态置为释放刷新
                            currentState = RELEASE_REFRESH;
                            changeHeaderByViewState();
                        }else if(paddingTop<0&&currentState == RELEASE_REFRESH){//没有完全显示,currentState=RELEASE_REFRESH原因是可以先滑到完全显示后再往上滑到不完全显示
                            currentState = PULL_DOWN_REFRESH;
                            header_tv.setText("下拉刷新");
                            changeHeaderByViewState();
                        }
                        header.setPadding(0,paddingTop,0,0);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if(currentState == RELEASE_REFRESH){//完全显示
                        header.setPadding(0,0,0,0);
                        currentState = REFRESHING;
                        changeHeaderByViewState();
                        if (mOnRefreshListener!=null){
                            mOnRefreshListener.downPullRefresh();
                        }
                    }else if(currentState == PULL_DOWN_REFRESH){//未完全显示
                        //当手指松开时,若头部未完全显示则隐藏头部
                        header.setPadding(0,-headerViewHeight,0,0);
                    }
                    break;
            }
            return super.onTouchEvent(ev);
        }
    
        private void changeHeaderByViewState(){
            switch (currentState){
                case PULL_DOWN_REFRESH:
                    row.startAnimation(downAnimation);
                    break;
                case RELEASE_REFRESH:
                    row.startAnimation(upAnimation);
                    break;
                case REFRESHING:
                    row.clearAnimation();
                    row.setVisibility(View.GONE);
                    header_tv.setText("正在刷新");
                    refresh.clearAnimation();
                    refresh.setVisibility(View.VISIBLE);
                    refresh.startAnimation(animation);
                    break;
            }
        }
        public void hideHeaderView(){
            header.setPadding(0,-headerViewHeight,0,0);
            refresh.setVisibility(View.GONE);
            currentState = PULL_DOWN_REFRESH;
            header_tv.setText("下拉刷新");
            row.setVisibility(View.VISIBLE);
    
        }
    }

    MainActivity.java

    package com.example.yds.pulldowntest;
    
    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.widget.TextView;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class MainActivity extends Activity implements OnRefreshListener{
        private TextView log_tv;
    
        private RefreshListView listView;
        private PullDownAdapter adapter;
        private Map<String,Object>map;
        List<Map<String,Object>>list = new ArrayList<>();
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            log_tv = (TextView) findViewById(R.id.log_tv);
            listView = (RefreshListView) findViewById(R.id.listview);
    
            for (int i = 0 ;i < 5 ; i++){
                map = new HashMap<>();
                map.put("name","this "+i);
                list.add(map);
            }
    
            adapter = new PullDownAdapter(this,list);
    
            listView.setOnRefreshListener(this);
            listView.setAdapter(adapter);
    
            log_tv.setText(list.get(0).get("name").toString()+"this is null?"+list.get(1).get("name").toString());
        }
    
        @Override
        public void downPullRefresh() {
            new AsyncTask<Void,Void,Void>(){
    
                @Override
                protected Void doInBackground(Void... params) {
                    SystemClock.sleep(2800);
                    map = list.get(0);
                    map.put("name","这是刷新后的数据");
                    list.add(map);
                    return null;
                }
    
                @Override
                protected void onPostExecute(Void result) {
                    super.onPostExecute(result);
                    adapter.notifyDataSetChanged();
                    listView.hideHeaderView();
                }
            }.execute(new Void[]{});
        }
    }

    源码下载地址:

     http://download.csdn.net/detail/u013293125/9734831

  • 相关阅读:
    STM32F407移植contiki2.6后使用LWIP库实现tcp client
    C#简单的tcpserver
    linux下python导出sybase 数据库 表记录的方式
    python BeautifulSoup find 方法
    SAP Java Connector(JCo)
    Windows和Linux系统如何退出python命令行
    python怎么安装requests、beautifulsoup4等第三方库
    windows下对python的pip更新到最新版本
    如何在windows下安装Python(Python入门教程)
    3.10-通过requests、BeautifulSoup、webbrowser模块的相关方法,爬取网页数据示例程序(一)
  • 原文地址:https://www.cnblogs.com/ityizhainan/p/6273919.html
Copyright © 2011-2022 走看看