ListView上下拉刷新

本文介绍如何在Android应用中自定义ListView类,实现上下拉刷新和上拉加载的功能,包括顶部布局、底部加载提示、滚动监听、状态切换等关键组件的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

listview的上下拉刷新在大部分的app中都有用到,可以使用第三方的PullToRefresh框架也可以自定义listview控件。下面是自定义的listview类:

public class LoadListView extends ListView  implements OnScrollListener{
    View footer;//底部布局
    int totalItemCount;//总数量
    int lastVisibleItem;//最后一个可见的item
    boolean isLoading =false;//正在加载
    ILoadListener iLoadListener;
    View header;
    int headerHeight;//顶部布局文件的高度
    int firstVisibleItem;
    boolean isRemark;//標記,當前實在listview 最頂端按下的。
    int startY;//按下時的Y值

    int state;//當前的狀態
    final int NONE = 0 ;//正常狀態
    final int PULL = 1;//提示下拉狀態
    final int RELESE = 2;//提示釋放狀態
    final int REFLASHING = 3;//刷新狀態
    int scrollState;//當前滾動狀態
    IReflashListener iReflashListener;//刷新數據的接口
    public LoadListView(Context context) {
        super(context);
        initView(context);
    }

    public LoadListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    public LoadListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    /**
     * 添加底部加载提示到ListView
     * 添加顶部加载提示到ListView
     * @param context
     */
    private void initView(Context context){
        //上拉加载
        LayoutInflater inflater = LayoutInflater.from(context);
        footer=inflater.inflate(R.layout.footer_layout,null);
        footer.findViewById(R.id.txt).setVisibility(View.INVISIBLE);
        this.setOnScrollListener(this);//设置滚动监听
        this.addFooterView(footer);


        //下拉刷新
        header=inflater.inflate(R.layout.header_layout,null);
        measureView(header);
        headerHeight = header.getMeasuredHeight();
        topPadding(-headerHeight);
        this.addHeaderView(header);


    }
    //计算顶部占多大
    private void measureView(View v){
        ViewGroup.LayoutParams p = v.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 tempheight=p.height;

        if(tempheight>0){
            height = MeasureSpec.makeMeasureSpec(tempheight,MeasureSpec.EXACTLY);//得到的是tempheight
        }else{
            height = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);//得到的是字布局的实际大小
        }
        v.measure(width, height);

    }

    public void topPadding(int topPadding){
        header.setPadding(header.getPaddingLeft(),topPadding,header.getPaddingRight(),header.getPaddingBottom());
        header.invalidate();
    }
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        //DOTO 下拉中
        this.lastVisibleItem=firstVisibleItem+visibleItemCount;
        this.totalItemCount=totalItemCount;

        this.firstVisibleItem=firstVisibleItem;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if(firstVisibleItem==0){
                isRemark=true;
                startY=(int) ev.getY();
            }
            break;
        case MotionEvent.ACTION_MOVE:
            onMove(ev);
            break;
        case MotionEvent.ACTION_UP:
            if(state==RELESE){
                state=REFLASHING;
                reflashViewByState();
                //加載最新數據
                iReflashListener.onReflash();
            }else if(state==PULL){
                state=NONE;
                isRemark=false;
                reflashViewByState();
            }
            break;


        default:
            break;
        }



        return super.onTouchEvent(ev);

    }

    private void reflashViewByState(){

        TextView tip = (TextView) header.findViewById(R.id.tip); 
        ImageView arrow = (ImageView) header.findViewById(R.id.imag);
        ProgressBar progress=(ProgressBar) header.findViewById(R.id.progress);
        RotateAnimation anim = new RotateAnimation(0,180,
                RotateAnimation.RELATIVE_TO_SELF,0.5f,
                RotateAnimation.RELATIVE_TO_SELF,0.5f);

        anim.setDuration(500);
        anim.setFillAfter(true);

        RotateAnimation anim1 = new RotateAnimation(180,0,
                RotateAnimation.RELATIVE_TO_SELF,0.5f,
                RotateAnimation.RELATIVE_TO_SELF,0.5f);
        anim1.setDuration(500);
        anim1.setFillAfter(true);
        switch (state) {
        case NONE:
            topPadding(-headerHeight);
            break;
        case PULL:
            arrow.setVisibility(View.VISIBLE);
            progress.setVisibility(View.INVISIBLE);
            tip.setText(getResources().getString(R.string.xialashuxin));
            arrow.clearAnimation();
            arrow.setAnimation(anim1);

            break;
        case RELESE:
            arrow.setVisibility(View.VISIBLE);
            progress.setVisibility(View.INVISIBLE);
            tip.setText(getResources().getString(R.string.songkaishuxin));
            arrow.clearAnimation();
            arrow.setAnimation(anim);
            break;
        case REFLASHING:
            topPadding(50);
            arrow.setVisibility(View.INVISIBLE);
            progress.setVisibility(View.VISIBLE);
            tip.setText(getResources().getString(R.string.zenzaishuxin));
            arrow.clearAnimation();
    break;
        default:
            break;
        }
    }

    private void onMove(MotionEvent ev) {
            if(!isRemark){
                return;
            }

            int tempY=(int) ev.getY();
            int space = tempY-startY;
            int topPadding = space-headerHeight;
            switch (state) {
            case NONE:
                if(space>0){
                    state=PULL;
                    reflashViewByState();
                }
                break;
            case PULL:
                topPadding(topPadding);
                if(space>headerHeight+30 && scrollState==SCROLL_STATE_TOUCH_SCROLL){
                    state=RELESE;
                    reflashViewByState();
                }
                break;
            case RELESE:
                topPadding(topPadding);
                if(space<headerHeight+30){
                    state=PULL;
                    reflashViewByState();
                }else if(space<0){
                    state=NONE;
                    isRemark=false;
                    reflashViewByState();
                }
                break;
            case REFLASHING:

                break;
            default:
                break;
            }
    }

    /**
     * 下拉刷新完成
     */
     public void reflashComplete(){
         state = NONE;
         isRemark = false;
         reflashViewByState();

         TextView lastupdatetime = (TextView) header.findViewById(R.id.lasttime); 
         SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
         Date date = new Date(System.currentTimeMillis());
         String time = format.format(date);
         lastupdatetime.setText(time);

     }

     public void setReflashInterface(IReflashListener iListener){
         this.iReflashListener=iListener;
     }

     public interface IReflashListener{
         public void onReflash();
     }


    public void onScrollStateChanged(AbsListView view, int scrollState) {
        //DOTO 滑动状态改变
        if(totalItemCount==lastVisibleItem && scrollState==SCROLL_STATE_IDLE){
            footer.findViewById(R.id.txt).setVisibility(View.VISIBLE);
            if(!isLoading){
                isLoading=true;
            //footer.findViewById(R.id.txt).setVisibility(View.VISIBLE);
            //加载更多
            iLoadListener.onLoad();
            }
        }

        this.scrollState=scrollState;


    }
    public void setInterface(ILoadListener iLoadListener){
        this.iLoadListener=iLoadListener;
    }

    public interface ILoadListener{
        public void onLoad();
    }

    /**
      * 上拉加載完成
      */
    public void loadComplete(){
        isLoading=false;
        footer.findViewById(R.id.txt).setVisibility(View.INVISIBLE);
    }
}

activity中的调用方法:

//activity实现上拉、下拉监听
    public class Main extends Activity implements ILoadListener,IReflashListener {
    private LoadListView list;
    boolean isloading=false;
    boolean isReflashing=false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        list = (LoadListView) findViewById(R.id.list);
        //隐藏listview头布局
        list.setHeaderDividersEnabled(false);
        //隐藏listview底部布局
        list.setFooterDividersEnabled(false);    
        //设置listview的上拉加载监听
        list.setInterface(this);
        //设置listview的下拉刷新监听
        list.setReflashInterface(this);  
    }

    public void onReflash() {
         //更新listview数据
        }
    }
    public void onLoad() {
         //更新listview数据
    }
    }
}

顶部布局文件如下:

<?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="match_parent"
    android:orientation="vertical" >
    <RelativeLayout 
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:paddingTop="10dp"  
       android:paddingBottom="10dp"
        >
        <LinearLayout 
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:orientation="vertical"
          android:layout_centerInParent="true" 
          android:id="@+id/layout"
          android:gravity="center"
            >
            <TextView 
              android:id="@+id/tip"
              android:text="@string/xialashuxin"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
                />
             <TextView 
              android:id="@+id/lasttime"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
                />
        </LinearLayout>
            <ImageView 
               android:id="@+id/imag"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_toLeftOf="@id/layout"
               android:layout_marginRight="20dp"
                android:src="@drawable/pull_to_refresh_arrow"
                />

            <ProgressBar 
               android:id="@+id/progress"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_toLeftOf="@id/layout"
               android:layout_marginRight="20dp"
               style="?android:attr/progressBarStyleSmall"
               android:visibility="gone"
                />

    </RelativeLayout>
    </LinearLayout>

底部布局文件如下:

<LinearLayout 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"
    android:orientation="vertical"
     >
    <LinearLayout
        android:id="@+id/txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingTop="10dp"  
        android:paddingBottom="10dp"
        android:gravity="center"
          >
        <ProgressBar 
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          style="?android:attr/progressBarStyleSmall"
            />
       <!--  <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="正在加载..."
            /> -->

     </LinearLayout>
    </LinearLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值