Android之listview下拉刷新

本文介绍如何在Android应用中实现ListView的下拉刷新功能。通过自定义View,学习自定义属性和方法,了解下拉刷新的实现原理。尽管已有现成的库如PullToRefresh可供使用,但作者分享了自己的实现过程,包括XML布局文件和自定义View的Java代码。文章适合想要深入理解下拉刷新机制的开发者阅读。

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

       很久没有更新了,老是忘记,哈哈。。。。。

      那么今天就说一说listview的下拉刷新,通过这个我们可以学习到自定义view的一些属性,还有需要重写的一些方法,以及这些方法的作用。

虽然现在已经有下拉刷新的一些成熟的库了,例如PullToRefresh,有空你们可以去试一下,这个就比较简单了,只需调用里面的方法就可以实现下拉刷新的功能。

有兴趣的朋友可以学习一下。

个人觉得我这个其实有一点点的麻烦,但毕竟是自己刚开始的时候第一次写的一个自定义view,所以拿出来跟你们分享分享。下面就先贴出我的xml文件中的代码吧,必要的地方我会一些注释的。


这个是主页面的xml文件,是自定义listview的包名,

<com.example.reflashlistview.FlashListView
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        
        />



这个是listview的item的布局

<?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="horizontal" >
    
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher"
        />
    
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:textColor="#66ff0000"
        android:text="文本一"
        />
    

</LinearLayout>

这个是头布局的文件

<?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="wrap_content"
        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/linear"
            >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉可以刷新"
               android:id="@+id/update"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/updatetime"
                />
        </LinearLayout>
        <ImageView
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:src="@drawable/xia"
            android:id="@+id/image"
            android:layout_toLeftOf="@id/linear"
            android:layout_marginRight="20dp"
            />
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/progress"
            style="?android:attr/progressBarStyleSmall"
            android:visibility="gone"
            android:layout_toLeftOf="@id/linear"
            android:layout_marginRight="20dp"
            />
        
        
    </RelativeLayout>
    

</LinearLayout>


好了,就到正文了,先贴出自定义view的代码

public class FlashListView extends ListView implements OnScrollListener{
    View header;
    int headerHeight;
    int firstVisibleItem;//当前第一个可见的Item的位置
    boolean isRemark;//标记,当前是在listview的最低端嗯下的
    int startY;//摁下时的y值
    int scrollState;//listview当前滚动的状态
    int state;//当前的状态
    final int NONE=0;//当前状态
    final int PULL=1;//提示下拉状态
    final int RELESE=2;//提示释放状态
    final int REFLASHING=3;//刷新状态
    IReflashListener listener;//刷新数据的接口
    private TextView text;
    private ProgressBar bar;
    private ImageView image;
    private Handler handler=new Handler(){
        public void handleMessage(android.os.Message msg) {
            finish();
        };
    };
    
//这是要重写的构造方法
    public FlashListView(Context context) {
        super(context);
        initView(context);
    }
    public FlashListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public FlashListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }
    //刷新完成后让头布局继续隐藏,并恢复到原来的状态
    public void finish(){
        if(state==REFLASHING){
            state=PULL;
            text.setText("下拉刷新");
            bar.setVisibility(View.INVISIBLE);
            image.setVisibility(View.VISIBLE);
            header.setPadding(0, -headerHeight, 0, 0);
        }
    }
    //初始化界面,添加顶部文件到listview中
    private void initView(Context context){
        LayoutInflater inflater = LayoutInflater.from(context);
        header=inflater.inflate(R.layout.header, null);
        text = (TextView) findViewById(R.id.update);
        bar = (ProgressBar) findViewById(R.id.progress);
        image = (ImageView) findViewById(R.id.image);
        measureView(header);
        headerHeight=header.getMeasuredHeight();
        topPadding(-headerHeight);//高度是0
        this.addHeaderView(header);
        this.setOnScrollListener(this);
    }
    //通知父布局占用的宽和高
    private void measureView(View view){
        ViewGroup.LayoutParams p = view.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);
        }else{
            height=MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(width, height);
                
    }
    //设置header布局的上边距
    private void topPadding(int topPadding){
        header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());
        header.invalidate();
    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        this.firstVisibleItem=firstVisibleItem;
        
        
    }
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        this.scrollState=scrollState;
        
    }

//

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if(firstVisibleItem==0){
                isRemark=true;
                startY=(int) ev.getY();
                reflashViewByState();
            }
            break;
        case MotionEvent.ACTION_MOVE:
            onMove(ev);
            reflashViewByState();
            break;
        case MotionEvent.ACTION_UP:
            if(state==RELESE){
                state=REFLASHING;
                reflashViewByState();
                //加载最新数据
                
            }else if(state==PULL){
                state=NONE;
                isRemark=false;
                reflashViewByState();
                listener.onReflash();
            }
            break;
            
        }
        return super.onTouchEvent(ev);
    }
    //根据提示当前状态,改变界面显示
    private void reflashViewByState(){
        TextView textview = (TextView) header.findViewById(R.id.update);
        ImageView image = (ImageView) header.findViewById(R.id.image);
        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:
            image.clearAnimation();
            topPadding(-headerHeight);
            

            break;
        case PULL:
            image.setVisibility(View.VISIBLE);
            progress.setVisibility(View.GONE);
            textview.setText("下拉可以刷新");
            image.clearAnimation();
            image.setAnimation(anim1);
            

            break;
        case RELESE:
            image.setVisibility(View.VISIBLE);
            progress.setVisibility(View.GONE);
            textview.setText("松开可以刷新");
            image.clearAnimation();    
            image.setAnimation(anim);
            
            break;
        case REFLASHING:
            topPadding(50);
            image.setVisibility(View.GONE);
            progress.setVisibility(View.VISIBLE);
            textview.setText("正在刷新...");
            image.clearAnimation();
            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:
            topPadding(topPadding);
            if(space<headerHeight+30){
                state=PULL;
                reflashViewByState();
            }else if(space<=0){
                state=NONE;
                isRemark=false;
                reflashViewByState();
            }

            break;

        }
    }
    //获取完数据
    
    public void reflashComplete(){
        state=NONE;
        isRemark=false;
        reflashViewByState();
        TextView updateTime = (TextView) header.findViewById(R.id.updatetime);
        SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日hh:mm:ss");
        Date date = new Date(System.currentTimeMillis());
        String time = format.format(date);
        updateTime.setText(time);
    }
    
    public void setInterface(IReflashListener listener){
        this.listener=listener;
    }
    //刷新数据接口
    public interface IReflashListener{
        public void onReflash();
            
        
    }
   
}


然后是在主activity的操作,这里就比较简单了

public class MainActivity extends Activity implements IReflashListener{

    

    private FlashListView ll;
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ll = (FlashListView) findViewById(R.id.ll);
        ll.setInterface(this);
        ll.setAdapter(new MyAdapter());
    }
    class MyAdapter extends BaseAdapter{

        

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return 100;
        }

        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view;
            if(convertView==null){
                view=View.inflate(getApplicationContext(), R.layout.item, null);
            }else{
                view=convertView;
            }
            ImageView image = (ImageView) view.findViewById(R.id.image);
            text = (TextView) view.findViewById(R.id.text);
            text.setText("文本"+position);
            image.setBackgroundResource(R.drawable.ic_launcher);
            return view;
        }
        
    }

    
    @Override
    public void onReflash() {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            
            @Override
            public void run() {
                
                ll.reflashComplete();
                
            }
        }, 2000);
        //获取最新数据
        //通知界面显示
        //通知listview刷新数据完毕
    ll.finish();
    }  
}

好了,到这里下拉刷新的操作就是完成了,我把全部的代码都贴在上面了,其中会有注释,希望你们能看明白。

因为曾经的我也为这个问题难为过,找了好多但都是一点,有的需要自己去尝试怎么跟自己写的融合,很麻烦。所以我明白自己找到的代码如果不能运行,还报一大堆的错误是多么的坑人,我会尽量的把所有的代码都给你们展示出来,希望你们看的高兴。

就到这里了。^-^         ^-^            ^-^



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值