ListView下拉刷新的一些常见错误

来源:互联网 发布:js控制浏览器最小化 编辑:程序博客网 时间:2024/04/25 08:51

                                                 第一篇博客

                   (ListView下拉刷新常见错误)

           开篇之前还是感谢我今次的这个冲动(写博客),不然我现在也不会有这篇文章,以后也不会有这种写博客的习惯。对于博客,个人还是比较支持,因为你可以在前辈的博客里面学到很多有用的知识,人是不断求进的,不要拘于小节才是王道。好了,入正文了。

            android是一个开源项目,各种效果经过几年的时间已经有了很多现成的框架,直接上网下载cp过来就ok了。但个人认为,懂其如何套用之外,还要真正懂其原理,这才是以后遇到什么问题就知道如何解决问题,而且扩展性的空间也很大,对吧。首先说明一下,在你开始新建项目的时候,你要明白几个方法/属性/常量的值是代表什么的。(方法不只一种,这里是用到重写ListView控件的方法,仅供参考)

  方法:

(1)public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) 这个是ListView控件滑动的时候所触发的一个方法(可以理解为随时监控ListView滑动的情况),其中只、主要有三个重要参数:

firstVisibleItem:为你在手机屏幕看到当前ListView的第一个子项索引;

visibleItemCount:为你在手机屏幕看到当前ListView最后一个子项索引(半个也算一个);

totalItemCount:为你ListView子项的总数目(adapter的size),要注意的是,当你设置了头部(head)view与底部(foot)view 的时候,则totalItemCount 则变成totalItemCount+2;

         情景想像:当你的ListView有大量子集时(出现滚动条),此刻你处于一个中间状态,那么你的手指不断向下滑,那么当滚动到顶部的时候(碰到顶部),这时候的firstVisibleItem就等于0。(不知道你明白这三个参数的关系没有,在不出现头底部的时候。firstVisibleItem+visibleItemCount=totalItemCount)。

(2)public void onScrollStateChanged(AbsListView view, int scrollState) 这是在ListView控件里面一个监控手势的方法,其中有一个重要的参数----scrollState

scrollState为判断你做出的动作,常用作与下面三个常量作判断(if (scrollState == XXX))

<1>SCROLL_STATE_IDLE   你滚动屏幕的时候,强行停止滚动所触发的一个事件

<2>SCROLL_STATE_FLING  你拖动控件之后(手指离开屏幕),然后控件随着惯性的作用下自动滚动期间所触发的事件

<3>SCROLL_STATE_TOUCH_SCROLL  你拖动控件(手指一直不离开屏幕)的时候所触发的一个事件

(3)重写控件的onTouchEvent

这个方法是作用于刷新状态的控制,这个可由你们自由控制,当手指滑到什么程度的时候就达到刷新的状态。

通常控制在三个行为上:MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_UP

 

好了,到现在为止已经部署好最关键的三个步骤,接下来就是添加 头部view 与 底部 view。

这里要注意一个问题,也是害我很惨的地方。例如 :this.addHeaderView(linHead); 一定要放在 setAdapter(new adapter(this.getContext())); 的前面。再强调一次,是前面。不然会抛出异常,这个追究下去,可以查看setAdapter的源码。

 

当然还要添加一些数据测试了,这里就不多说了。

 

下面贴出一个demo,仅供参考:

文件清单:com/example/listview_rewrite/MainActivity.java

import android.os.Bundle;
import android.app.Activity;

public class MainActivity extends Activity {

 private MyListView mListView;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  mListView = new MyListView(this);
   setContentView(mListView);
 }

}

文件清单:com/example/listview_rewrite/MyListView.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

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.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.TextView;

public class MyListView extends ListView implements OnScrollListener{

 private int flag = -1;
 private boolean b = false;
 private int sy,dy;
 private boolean bb = false;
 private LayoutInflater mlayoutInflater;
 private LinearLayout linHead_container;
 private LinearLayout linFoot_container;
 private LinearLayout linHead;
 private LinearLayout linFoot;

 public final class ViewHolder{
  public TextView tv;
 }

 //初始化数据
 private void init(){
  setAdapter(new adapter(this.getContext()));
 }
 
 public class adapter extends BaseAdapter {   
   private LayoutInflater mLayoutInflater ;
   public adapter(Context context){
    //构造方法,获得布局引用
    this.mLayoutInflater = LayoutInflater.from(context);
   }
   
   @Override
   public View getView(int arg0, View convertView, ViewGroup arg2) {
    //ViewHolder的作用就是避免重复创建,节省资源,提高效率为主要目的
    ViewHolder holder = null;
    if (convertView == null) {
     holder=new ViewHolder();   
     //获得ListView的子项布局
     convertView = mLayoutInflater.inflate(R.layout.textview, null);
     holder.tv = (TextView)convertView.findViewById(R.id.tv);
     convertView.setTag(holder);
    }else { 
     holder = (ViewHolder)convertView.getTag();
    }
    holder.tv.setText(getData().get(arg0).get("title").toString());
    return convertView;
   }
   
   @Override
   public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return 0;
   }
   
   @Override
   public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return null;
   }
   
   @Override
   public int getCount() {
    // TODO Auto-generated method stub
    return getData().size();
   }
  };
  
 //添加头部view与底部view一定要在初始化数据前面
 public MyListView(Context context) {
  super(context);
  mlayoutInflater = LayoutInflater.from(context);
  View v = mlayoutInflater.inflate(R.layout.foot, null);
  linFoot = (LinearLayout)v.findViewById(R.id.foot);
  linFoot_container = (LinearLayout)v.findViewById(R.id.foot_container);
  this.addFooterView(linFoot);
  v = mlayoutInflater.inflate(R.layout.head, null);
  linHead = (LinearLayout)v.findViewById(R.id.head);
  linHead_container = (LinearLayout)v.findViewById(R.id.head_container);
  this.addHeaderView(linHead);
  linHead_container.setVisibility(View.GONE);
  linFoot_container.setVisibility(View.GONE);
  init();
  //设置监听
  this.setOnScrollListener(this);
 }
 
 public MyListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
  this.setOnScrollListener(this);
  mlayoutInflater = LayoutInflater.from(context);
  // TODO Auto-generated constructor stub
 }
 
 public MyListView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  init();
  this.setOnScrollListener(this);
  mlayoutInflater = LayoutInflater.from(context);
  // TODO Auto-generated constructor stub
 }
 
 //设置数据
 private ArrayList<Map<String, Object>> getData() {
  ArrayList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
  Map<String, Object>map = new HashMap<String, Object>();
  for (int i = 0; i < 60; i++) {
   map.put("title", "title"+(i+1));
   list.add(map);
  }
  return list;
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   sy = (int) event.getRawY();
   break;

  case MotionEvent.ACTION_MOVE:
   dy = (int) (event.getRawY() - sy);
//   if(Math.abs(dy)>=480/3 ){
//    if(flag == 1){
//     Log.i("AAAAA", "底部刷新到了临界点1/3");
//     bb = true;
//    }else if(flag ==2){
//     Log.i("AAAAA", "顶部刷新到了临界点1/3");
//     bb = true;
//    }else{
//     bb = false;
//    }
//   }
   //等于1就代表滑到底部了
   if(flag == 1 ){
    //小于0就代表向上滑动
    if(dy<0){
     //设置底部view为可见
     linFoot_container.setVisibility(View.VISIBLE);
     //笔者手机的分辨率是320*480
     if(Math.abs(dy)>=480/3 ){
       Log.i("AAAAA", "底部刷新到了临界点1/3");
       bb = true;
      }
    }
   }
   //等于2就代表到达顶部了
   else if(flag ==2){
    //大于0就代表向下滑动
    if(dy>0){ 
     //设置顶部view为可见
     linHead_container.setVisibility(View.VISIBLE);
     //笔者手机的分辨率是320*480
     if(Math.abs(dy)>=480/3 ){
       Log.i("AAAAA", "顶部刷新到了临界点1/3");
       bb = true;
      }
    }
   }
   
   break;
   
  //松开手的时候,底部与顶部的view就隐藏了
  case MotionEvent.ACTION_UP:
   if(bb){
    Log.i("AAAAA", "松手开始加载信息。。。。。");
    if(flag == 1){
     linFoot_container.setVisibility(View.GONE);
    }else if(flag ==2){
     linHead_container.setVisibility(View.GONE);
    }else{
     linFoot_container.setVisibility(View.GONE);
     linHead_container.setVisibility(View.GONE);
    }
   }
   else{
    linFoot_container.setVisibility(View.GONE);
    linHead_container.setVisibility(View.GONE);
   }
   break;
  }
  return super.onTouchEvent(event);
 }
 
 @Override
 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
  Log.i("AAAA", "一共有f"+firstVisibleItem+"项。。。。");
  Log.i("AAAA", "一共有v"+visibleItemCount+"项。。。。");
  Log.i("AAAA", "一共有t"+totalItemCount+"项。。。。");
  if(firstVisibleItem + visibleItemCount == totalItemCount
    && totalItemCount >0 ){
   Log.i("AAAA", "到底部了。。。。");
   b = true;
   flag = 1;
  }else if(firstVisibleItem ==0 && totalItemCount>0){
   Log.i("AAAA", "到最顶了。。。。");
   b = true;
   flag = 2;
  }else{
   b = false;
   flag = -1;
  }
  
 }

 @Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  
  if(scrollState == SCROLL_STATE_FLING || scrollState==SCROLL_STATE_TOUCH_SCROLL
    && b && flag ==1){
   Log.i("AAAA", "在这个时候加载底部信息。。。。");
  }else if((scrollState == SCROLL_STATE_FLING || scrollState==SCROLL_STATE_TOUCH_SCROLL
    && b && flag ==2)){
   Log.i("AAAA", "在这个时候加载头部信息。。。。");
  }
  
 }

}

 

文件清单:ListView_reWrite\res\layout\foot.xml

<?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:id="@+id/foot"
    android:orientation="vertical" >
   
    <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/foot_container"
     android:orientation="vertical" >
     <Button
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:id="@+id/btn"
         android:text="查看更多"/>
    </LinearLayout>

</LinearLayout>

文件清单:ListView_reWrite\res\layout\head.xml

<?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:id="@+id/head"
    android:orientation="vertical" >
   
    <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/head_container"
     android:orientation="vertical" >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAlignment="center"
        android:text="正在加载中。。。"/>
    </LinearLayout>

</LinearLayout>

 

文件清单:ListView_reWrite\res\layout\textview.xml

<?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" >
   
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tv"/>

</LinearLayout>

好了,这篇文章将要结束了,还有一点没有讲的,是否会有朋友问,为什么在布局文件里面一定要嵌套多一个 LinearLayout呢? 正是这个原因,因为你要做到隐藏头部或底部view的时候

经测试是不作用根LinearLayout的,所以要做一个容器装载里面的view,然后调用就可以成功收放自如view了。

 

研究了一个下午,总算有点成果,对ListView 的理解也有初步认识,当然上面只是简单布局,还有使用,ListView的例子还有各式各样等等,这只是一个开始而已,不自满,求向上。

第一篇文章,写得不怎么清晰简洁,以后力求不冗余,讲重点,谢谢大家了,有疑问可以提出,能看到的都会尽量回答,大家交流学习。

 

 

 

 

 

 

 

 

 

 

 

原创粉丝点击