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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM