欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中ListView下拉刷新的实现方法

程序员文章站 2024-02-23 22:18:22
listview中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考。那我就不解释,直接上代码了。 这里需要自己重写一下lis...

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

Android中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; 
 } 
 
} 

如果想针对android listview进行深入研究的同学,可以参考专题《android listview使用方法汇总》

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