Android中ListView下拉刷新的实现代码

Android中ListView下拉刷新

实现效果图:

ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考。那我就不解释,直接上代码了。

这里需要自己重写一下ListView,重写代码如下:

package net.loonggg.listview; 

import java.util.Date; 

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView; 

public class MyListView extends ListView implements OnScrollListener { 

  private final static int RELEASE_To_REFRESH = 0;// 下拉过程的状态值
  private final static int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值
  private final static int REFRESHING = 2;// 正在刷新的状态值
  private final static int DONE = 3;
  private final static int LOADING = 4; 

  // 实际的padding的距离与界面上偏移距离的比例
  private final static int RATIO = 3;
  private LayoutInflater inflater; 

  // ListView头部下拉刷新的布局
  private LinearLayout headerView;
  private TextView lvHeaderTipsTv;
  private TextView lvHeaderLastUpdatedTv;
  private ImageView lvHeaderArrowIv;
  private ProgressBar lvHeaderProgressBar; 

  // 定义头部下拉刷新的布局的高度
  private int headerContentHeight; 

  private RotateAnimation animation;
  private RotateAnimation reverseAnimation; 

  private int startY;
  private int state;
  private boolean isBack; 

  // 用于保证startY的值在一个完整的touch事件中只被记录一次
  private boolean isRecored; 

  private OnRefreshListener refreshListener; 

  private boolean isRefreshable; 

  public MyListView(Context context) {
    super(context);
    init(context);
  } 

  public MyListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  } 

  private void init(Context context) {
    setCacheColorHint(context.getResources().getColor(R.color.transparent));
    inflater = LayoutInflater.from(context);
    headerView = (LinearLayout) inflater.inflate(R.layout.lv_header, null);
    lvHeaderTipsTv = (TextView) headerView
        .findViewById(R.id.lvHeaderTipsTv);
    lvHeaderLastUpdatedTv = (TextView) headerView
        .findViewById(R.id.lvHeaderLastUpdatedTv); 

    lvHeaderArrowIv = (ImageView) headerView
        .findViewById(R.id.lvHeaderArrowIv);
    // 设置下拉刷新图标的最小高度和宽度
    lvHeaderArrowIv.setMinimumWidth(70);
    lvHeaderArrowIv.setMinimumHeight(50); 

    lvHeaderProgressBar = (ProgressBar) headerView
        .findViewById(R.id.lvHeaderProgressBar);
    measureView(headerView);
    headerContentHeight = headerView.getMeasuredHeight();
    // 设置内边距,正好距离顶部为一个负的整个布局的高度,正好把头部隐藏
    headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
    // 重绘一下
    headerView.invalidate();
    // 将下拉刷新的布局加入ListView的顶部
    addHeaderView(headerView, null, false);
    // 设置滚动监听事件
    setOnScrollListener(this); 

    // 设置旋转动画事件
    animation = new RotateAnimation(0, -180,
        RotateAnimation.RELATIVE_TO_SELF, 0.5f,
        RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    animation.setInterpolator(new LinearInterpolator());
    animation.setDuration(250);
    animation.setFillAfter(true); 

    reverseAnimation = new RotateAnimation(-180, 0,
        RotateAnimation.RELATIVE_TO_SELF, 0.5f,
        RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    reverseAnimation.setInterpolator(new LinearInterpolator());
    reverseAnimation.setDuration(200);
    reverseAnimation.setFillAfter(true); 

    // 一开始的状态就是下拉刷新完的状态,所以为DONE
    state = DONE;
    // 是否正在刷新
    isRefreshable = false;
  } 

  @Override
  public void onScrollStateChanged(AbsListView view, int scrollState) { 

  } 

  @Override
  public void onScroll(AbsListView view, int firstVisibleItem,
      int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == 0) {
          isRefreshable = true;
         } else {
          isRefreshable = false;
         }
    } 

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (isRefreshable) {
      switch (ev.getAction()) {
      case MotionEvent.ACTION_DOWN:
        if (!isRecored) {
          isRecored = true;
          startY = (int) ev.getY();// 手指按下时记录当前位置
        }
        break;
      case MotionEvent.ACTION_UP:
        if (state != REFRESHING && state != LOADING) {
          if (state == PULL_To_REFRESH) {
            state = DONE;
            changeHeaderViewByState();
          }
          if (state == RELEASE_To_REFRESH) {
            state = REFRESHING;
            changeHeaderViewByState();
            onLvRefresh();
          }
        }
        isRecored = false;
        isBack = false; 

        break; 

      case MotionEvent.ACTION_MOVE:
        int tempY = (int) ev.getY();
        if (!isRecored) {
          isRecored = true;
          startY = tempY;
        }
        if (state != REFRESHING && isRecored && state != LOADING) {
          // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
          // 可以松手去刷新了
          if (state == RELEASE_To_REFRESH) {
            setSelection(0);
            // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
            if (((tempY - startY) / RATIO < headerContentHeight)// 由松开刷新状态转变到下拉刷新状态
                && (tempY - startY) > 0) {
              state = PULL_To_REFRESH;
              changeHeaderViewByState();
            }
            // 一下子推到顶了
            else if (tempY - startY <= 0) {// 由松开刷新状态转变到done状态
              state = DONE;
              changeHeaderViewByState();
            }
          }
          // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
          if (state == PULL_To_REFRESH) {
            setSelection(0);
            // 下拉到可以进入RELEASE_TO_REFRESH的状态
            if ((tempY - startY) / RATIO >= headerContentHeight) {// 由done或者下拉刷新状态转变到松开刷新
              state = RELEASE_To_REFRESH;
              isBack = true;
              changeHeaderViewByState();
            }
            // 上推到顶了
            else if (tempY - startY <= 0) {// 由DOne或者下拉刷新状态转变到done状态
              state = DONE;
              changeHeaderViewByState();
            }
          }
          // done状态下
          if (state == DONE) {
            if (tempY - startY > 0) {
              state = PULL_To_REFRESH;
              changeHeaderViewByState();
            }
          }
          // 更新headView的size
          if (state == PULL_To_REFRESH) {
            headerView.setPadding(0, -1 * headerContentHeight
                + (tempY - startY) / RATIO, 0, 0); 

          }
          // 更新headView的paddingTop
          if (state == RELEASE_To_REFRESH) {
            headerView.setPadding(0, (tempY - startY) / RATIO
                - headerContentHeight, 0, 0);
          } 

        }
        break; 

      default:
        break;
      }
    }
    return super.onTouchEvent(ev);
  } 

  // 当状态改变时候,调用该方法,以更新界面
  private void changeHeaderViewByState() {
    switch (state) {
    case RELEASE_To_REFRESH:
      lvHeaderArrowIv.setVisibility(View.VISIBLE);
      lvHeaderProgressBar.setVisibility(View.GONE);
      lvHeaderTipsTv.setVisibility(View.VISIBLE);
      lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE); 

      lvHeaderArrowIv.clearAnimation();// 清除动画
      lvHeaderArrowIv.startAnimation(animation);// 开始动画效果 

      lvHeaderTipsTv.setText("松开刷新");
      break;
    case PULL_To_REFRESH:
      lvHeaderProgressBar.setVisibility(View.GONE);
      lvHeaderTipsTv.setVisibility(View.VISIBLE);
      lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
      lvHeaderArrowIv.clearAnimation();
      lvHeaderArrowIv.setVisibility(View.VISIBLE);
      // 是由RELEASE_To_REFRESH状态转变来的
      if (isBack) {
        isBack = false;
        lvHeaderArrowIv.clearAnimation();
        lvHeaderArrowIv.startAnimation(reverseAnimation); 

        lvHeaderTipsTv.setText("下拉刷新");
      } else {
        lvHeaderTipsTv.setText("下拉刷新");
      }
      break; 

    case REFRESHING: 

      headerView.setPadding(0, 0, 0, 0); 

      lvHeaderProgressBar.setVisibility(View.VISIBLE);
      lvHeaderArrowIv.clearAnimation();
      lvHeaderArrowIv.setVisibility(View.GONE);
      lvHeaderTipsTv.setText("正在刷新...");
      lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
      break;
    case DONE:
      headerView.setPadding(0, -1 * headerContentHeight, 0, 0); 

      lvHeaderProgressBar.setVisibility(View.GONE);
      lvHeaderArrowIv.clearAnimation();
      lvHeaderArrowIv.setImageResource(R.drawable.arrow);
      lvHeaderTipsTv.setText("下拉刷新");
      lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
      break;
    }
  } 

  // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
  private void measureView(View child) {
    ViewGroup.LayoutParams params = child.getLayoutParams();
    if (params == null) {
      params = new ViewGroup.LayoutParams(
          ViewGroup.LayoutParams.FILL_PARENT,
          ViewGroup.LayoutParams.WRAP_CONTENT);
    }
    int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0,
        params.width);
    int lpHeight = params.height;
    int childHeightSpec;
    if (lpHeight > 0) {
      childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
          MeasureSpec.EXACTLY);
    } else {
      childHeightSpec = MeasureSpec.makeMeasureSpec(0,
          MeasureSpec.UNSPECIFIED);
    }
    child.measure(childWidthSpec, childHeightSpec);
  } 

  public void setonRefreshListener(OnRefreshListener refreshListener) {
    this.refreshListener = refreshListener;
    isRefreshable = true;
  } 

  public interface OnRefreshListener {
    public void onRefresh();
  } 

  public void onRefreshComplete() {
    state = DONE;
    lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString());
    changeHeaderViewByState();
  } 

  private void onLvRefresh() {
    if (refreshListener != null) {
      refreshListener.onRefresh();
    }
  } 

  public void setAdapter(LvAdapter adapter) {
    lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString());
    super.setAdapter(adapter);
  } 

}

重写完ListView之后,在布局文件中是这么使用的,头部下拉刷新的布局文件lv_header.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- ListView的头部 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="#000000" > 

  <!-- 内容 --> 

  <RelativeLayout
    android:id="@+id/head_contentLayout"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="30dp" > 

    <!-- 箭头图像、进度条 --> 

    <FrameLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:layout_centerVertical="true" > 

      <!-- 箭头 --> 

      <ImageView
        android:id="@+id/lvHeaderArrowIv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/arrow" /> 

      <!-- 进度条 --> 

      <ProgressBar
        android:id="@+id/lvHeaderProgressBar"
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="gone" />
    </FrameLayout> 

    <!-- 提示、最近更新 --> 

    <LinearLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:gravity="center_horizontal"
      android:orientation="vertical" > 

      <!-- 提示 --> 

      <TextView
        android:id="@+id/lvHeaderTipsTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下拉刷新"
        android:textColor="@color/white"
        android:textSize="20sp" /> 

      <!-- 最近更新 --> 

      <TextView
        android:id="@+id/lvHeaderLastUpdatedTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="上次更新"
        android:textColor="@color/gold"
        android:textSize="10sp" />
    </LinearLayout>
  </RelativeLayout> 

</LinearLayout>

在Main.xml中进行设置,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="#000000"
  android:orientation="vertical" > 

  <net.loonggg.listview.MyListView
    android:id="@+id/lv"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" /> 

</LinearLayout>

然后就是在MainActivity中实现,代码如下:

package net.loonggg.listview; 

import java.util.ArrayList;
import java.util.List; 

import net.loonggg.listview.MyListView.OnRefreshListener;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View; 

public class MainActivity extends Activity {
  private List<String> list;
  private MyListView lv;
  private LvAdapter adapter; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    lv = (MyListView) findViewById(R.id.lv);
    list = new ArrayList<String>();
    list.add("loonggg");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    list.add("我们都是开发者");
    adapter = new LvAdapter(list, this);
    lv.setAdapter(adapter); 

    lv.setonRefreshListener(new OnRefreshListener() { 

      @Override
      public void onRefresh() {
        new AsyncTask<Void, Void, Void>() {
          protected Void doInBackground(Void... params) {
            try {
              Thread.sleep(1000);
            } catch (Exception e) {
              e.printStackTrace();
            }
            list.add("刷新后添加的内容");
            return null;
          } 

          @Override
          protected void onPostExecute(Void result) {
            adapter.notifyDataSetChanged();
            lv.onRefreshComplete();
          }
        }.execute(null, null, null);
      }
    });
  }
}

这里还需要为ListView设置一下Adapter,自定义的Adapter如下:

package net.loonggg.listview; 

import java.util.List; 

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView; 

public class LvAdapter extends BaseAdapter {
  private List<String> list;
  private Context context; 

  public LvAdapter(List<String> list, Context context) {
    this.list = list;
    this.context = context;
  } 

  @Override
  public int getCount() {
    return list.size();
  } 

  @Override
  public Object getItem(int position) {
    return list.get(position);
  } 

  @Override
  public long getItemId(int position) {
    return position;
  } 

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    TextView tv = new TextView(context.getApplicationContext());
    tv.setText(list.get(position));
    return tv;
  } 

}

到这里就完了,代码中的解释非常详细,具体的我就不多说了,也不解释了,自己看看并研究吧!

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Android编程实现带有图标的ListView并带有长按菜单效果示例

    本文实例讲述了Android编程实现带有图标的ListView并带有长按菜单效果.分享给大家供大家参考,具体如下: MainActivity.Java package com.zxl; import java.util.ArrayList; import java.util.List; import org.w3c.dom.ls.LSException; import android.app.Activity; import android.os.Bundle; import android.v

  • Android UI设计系列之自定义ListView仿QQ空间阻尼下拉刷新和渐变菜单栏效果(8)

    好久没有写有关UI的博客了,刚刚翻了一下之前的博客,最近一篇有关UI的博客:Android UI设计系列之自定义Dialog实现各种风格的对话框效果(7) ,实现各种风格效果的对话框,在那篇博客写完后由于公司封闭开发封网以及其它原因致使博客中断至今,中断这么久很是惭愧,后续我会尽量把该写的都补充出来.近来项目有个需求,要做个和QQ空间类似的菜单栏透明度渐变和下拉刷新带有阻尼回弹的效果.于是花点时间动手试了试,基本上达到了QQ空间的效果,截图如下: 通过观察QQ空间的运行效果,发现当往上滚动时菜单

  • Android编程实现ListView内容无限循环显示的方法

    本文实例讲述了Android编程实现ListView内容无限循环显示的方法.分享给大家供大家参考,具体如下: 其实要达到无限循环显示,主要就是实现继承Adapter的类. 我这里用到的是BaseAdapter private class MyAdapter extends BaseAdapter{ private Context context; private String[] strs = null; LayoutInflater inflater = null; public MyAdap

  • Android listview数据显示及提示信息的实例

    Android  listview数据显示及提示信息的实例 最近我们测试人员说,我们的所有的列表都要做一个没有数据就提示没有数据,当时我的表情是这样的 =_=!!! 我的天呐--这么多列表真的要一个一个做嘛!!!然后我想了一下,那就直接改造Listview吧--说干就干. 没有数据的效果: 有数据的效果: 代码: NoDataListView.java package com.tianjs.tianjinsuop2p.widgets; import android.content.Context

  • Android ListView列表控件的介绍和性能优化

    ListView列表控件 一.ListView显示数据的原理:mvc模式 m:mode 数据(用javabean规范封装) v:view ListView c:adapter 适配器,负责把数据展示到ListView上 二.ListView最常用适配器 BaseAdapter.SimpleAdapter.ArrayAdapter 三.ListView显示数据的步骤 1.创建ListView 2.自定义ListView的适配器继承BaseAdapter,重写baseAdapter的getCount

  • android开发教程之listview使用方法

    首先是布局文件,这里需要两个布局文件,一个是放置列表控件的Activity对应的布局文件 main.xml,另一个是ListView中每一行信息显示所对应的布局  list_item.xml    这一步需要注意的问题是ListView 控件的id要使用Android系统内置的 android:id="@android:id/list"   [注意形式] main.xml 复制代码 代码如下: <?xml version="1.0" encoding=&quo

  • Android编程实现为ListView创建上下文菜单(ContextMenu)的方法

    本文实例讲述了Android编程实现为ListView创建上下文菜单(ContextMenu)的方法.分享给大家供大家参考,具体如下: ContextMenu称为上下文菜单,一般在控件上长按时弹出.今天我们学习ContextMenu的用法,这里与listview相结合,先在ListView显示几个Item,然后在Item上长按,弹出一个菜单(就是ContextMenu),点击菜单上的项目,提示刚才长按的Item的Position. main.xml文件 <?xml version="1.0

  • Android实现读取SD卡下所有TXT文件名并用listView显示出来的方法

    本文实例讲述了Android实现读取SD卡下所有TXT文件名并用listView显示出来的方法.分享给大家供大家参考,具体如下: MainActivity.Java package com.zxl; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.os.Bundle; import android.os.En

  • Android ListView分页简单实现

    Android ListView分页简单实现 分页,开发应用中必不可少.那么,现在就来实现分页功能. 首先来想想实现它要有哪些步骤, 1, 实现的组件, 2.初始化第一页数据, 3,底部布局 , 4,加载数据的条件 5.获取下一页的数据. 有了思路,我们一步步来实现就行了.先来想想我们用什么组件实现,我们知道列表UI我们常用ListView或者RecyclerView,初始化数据,我们就在通过一个for循环来准备数据,底部布局我们直接使ProgressBar控件和一个TextView来显示就可以

  • Android ListView 条目多样式展示实例详解

    ListView的多种样式条目展示 这里给大家介绍一下简单的ListView的多种样式展示 在布局文件中和往常一样写一个ListViwe的布局 <ListView android:id="@+id/main_listview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> 其他的这里就不多说了,直接介绍适配器里的操作 packag

  • Android TV listview及焦点处理

    Android TV listview及焦点处理 Android TV上的listview ,因为没有touch事件,只能通过按键处理,因此,用到listview时需要特殊处理: 1.复杂的view需要获取焦点,需要设置: setItemsCanFocus(true) 同时需要设置下能获取焦点view的属性: android:focusable="true 这样子级view就可以获取获取焦点. 2.view中需要获取焦点需要高亮框效果,可以在view画外框: package com.cn21.e

  • Android ListView长按弹出菜单二种实现方式示例

    复制代码 代码如下: /** * 知识点1:ListView item:两种长按弹出菜单方式* 知识点2:ListView SimpleAdapter的使用* 知识点 3:在java代码中创建一个ListView*/ public class ListOnLongClickActivity extends Activity {         private LinearLayout myListViewlayout;         private ListView mListView;   

随机推荐