天天看點

android-----ListView上拉加載更多實作

        前幾篇部落格,我們從緩存的角度優化了ListView,如果你對此還不太熟悉的話可以到android-----帶你一步一步優化ListView(一),android-----帶你一步一步優化ListView(二),android-----帶你一步一步優化ListView(三),檢視,其實,對于ListView的優化來說,還有一種方式我們沒有涉及,那就是分頁加載了,你在微信加載朋友圈的時候會發現每次顯示到最下面會出現加載更多的提示資訊,這就是分頁加載的使用啦,我們沒有必要每次加載ListView的資料時把所有資料全部都查找到,因為ListView本身能夠顯示在一個界面的條目數是有限的,我們完全可以隻去查找一螢幕的資料并且顯示他,當使用者滑動到最下面的時候再去加載下一螢幕的資料,這對于ListView上面有圖檔顯示的應用來說優化效果特别明顯,那麼這篇部落格,我們将會實作類似于朋友圈上拉加載更多的功能;

        先來看看效果圖:

android-----ListView上拉加載更多實作

        好了,接下來我們從代碼層面來講解該怎麼實作:

        首先定義一個主界面布局listview.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" >
    <ListView 
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>
</LinearLayout>
           

        定義每個item的顯示布局item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        />
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_toRightOf="@id/imageView"
        android:layout_marginTop="20dp"
        android:layout_marginRight="70dp"
        />
</RelativeLayout>
           

        很簡單,就是一個ImageView和一個TextView

        接下來就是一個用于顯示加載更多的布局了load_more.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/loadmore"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"  
    android:orientation="horizontal" >
    
    <ProgressBar  
        android:id="@+id/progress"  
        style="?android:attr/progressBarStyleSmall"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_marginBottom="30dp"  
        android:layout_marginTop="30dp" />  
  
    <TextView  
        android:id="@+id/tv"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_marginLeft="20dp"  
        android:text="正在加載..."  
        android:textColor="#FF0000" />
</LinearLayout>
           

        這個界面中會顯示一個進度條和正在加載的TextView

        之後便是為我們的ListView設定擴充卡ListViewAdapter了

public class ListViewAdapter extends BaseAdapter{
	
	public List<String> list;
	public LayoutInflater inflater;
	
	
	public ListViewAdapter() {
	}
	
	public ListViewAdapter(Context context,List<String> list) {
		this.list = list;
		this.inflater = LayoutInflater.from(context);
	}
	
	@Override
	public int getCount() {
		return list.size();
	}

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

	@Override
	public long getItemId(int position) {
		return 0;
	}
	
	public void updateView(List<String> nowList)
	{
		this.list = nowList;
		this.notifyDataSetChanged();//強制動态重新整理資料進而調用getView方法
	}
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View view = null;
		ViewHolder holder = null;
		if(convertView == null)
		{
			view = inflater.inflate(R.layout.item, null);
			holder = new ViewHolder();
			holder.imageView = (ImageView)view.findViewById(R.id.imageView);
			holder.textView = (TextView)view.findViewById(R.id.textView);
			view.setTag(holder);//為了複用holder
		}else
		{
			view = convertView;
			holder = (ViewHolder) view.getTag();
		}
		holder.imageView.setImageResource(R.drawable.image);
		holder.textView.setText(list.get(position));
		return view;
	}	
	static class ViewHolder
	{
		ImageView imageView;
		TextView textView;
	}
}
           

        這段代碼中的getView方法就是我們平常使用ListView為其設定擴充卡所要重寫的方法,重點在于第30行的updateView方法了,這個方法用于修改需要顯示在ListView上面的資料資訊,并且随後調用notifyDataSetChanged方法來通知擴充卡告訴他ListView上面需要顯示的内容已經發生了改變,這時候就會調用getView方法來重新加載資料了;

        接下來就是我們的主Activity

public class MainActivity extends Activity implements OnScrollListener{

	public View loadmoreView;
	public LayoutInflater inflater;
	public ListView listView;
	public int last_index;
	public int total_index;
	public List<String> firstList = new ArrayList<String>();//表示首次加載的list
	public List<String> nextList = new ArrayList<String>();//表示出現重新整理之後需要顯示的list
	public boolean isLoading = false;//表示是否正處于加載狀态
	public ListViewAdapter adapter;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.listview);
		inflater = LayoutInflater.from(this);
		loadmoreView = inflater.inflate(R.layout.load_more, null);//獲得重新整理視圖
		loadmoreView.setVisibility(View.VISIBLE);//設定重新整理視圖預設情況下是不可見的
		listView = (ListView) findViewById(R.id.listView);
		initList(10, 10);
		adapter = new ListViewAdapter(this, firstList);
		listView.setOnScrollListener(this);
		listView.addFooterView(loadmoreView,null,false);
		listView.setAdapter(adapter);
	}
	/**
	 * 初始化我們需要加載的資料
	 * @param firstCount
	 * @param nextCount
	 */
	public void initList(int firstCount,int nextCount)
	{
		for(int i = 0;i < firstCount;i++)
		{
			firstList.add("第"+(i+1)+"個開始加載");
		}
		for(int i = 0;i < firstCount;i++)
		{
			nextList.add("第"+(i+1)+"個開始加載");
		}
		for(int i = 0;i < nextCount;i++)
		{
			nextList.add("重新整理之後第"+(i+1)+"個開始加載");
		}
	}
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
		last_index = firstVisibleItem+visibleItemCount;
		total_index = totalItemCount;
		System.out.println("last:  "+last_index);
		System.out.println("total:  "+total_index);
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		if(last_index == total_index && (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE))
		{
			//表示此時需要顯示重新整理視圖界面進行新資料的加載(要等滑動停止)
			if(!isLoading)
			{
				//不處于加載狀态的話對其進行加載
				isLoading = true;
				//設定重新整理界面可見
				loadmoreView.setVisibility(View.VISIBLE);
				onLoad();
			}
		}
	}
	
	/**
	 * 重新整理加載
	 */
	public void onLoad()
	{
		try {
			//模拟耗時操作
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		if(adapter == null)
		{
			adapter = new ListViewAdapter(this, firstList);
			listView.setAdapter(adapter);
		}else
		{
			adapter.updateView(nextList);
		}
		loadComplete();//重新整理結束
	}
	
	/**
	 * 加載完成
	 */
	public void loadComplete()
	{
		loadmoreView.setVisibility(View.GONE);//設定重新整理界面不可見
		isLoading = false;//設定正在重新整理标志位false
		MainActivity.this.invalidateOptionsMenu();
		listView.removeFooterView(loadmoreView);//如果是最後一頁的話,則将其從ListView中移出
	}
}
           

        在第19行獲得了加載更多的重新整理視圖并且第20行設定該視圖是可見的,因為我們模拟的是要加載兩頁的資料,這樣的話第一頁加載結束之後需要顯示加載更多的視圖,在第24行将該視圖添加到了ListView的最下面,随後為Listview添加滑動事件,這裡面最重要的兩個方法就是第48行的onScroll和第56行的onScrollStateChanged,通過onScroll中的last_index用于獲得目前頁面表示在現時螢幕可以見到的最大Item的位置,total_index用于表示ListView可以加載的ListItem總數;第57行判斷目前頁面表示在現時螢幕可以見到的最大Item的位置如果等于ListView可以加載的ListItem總數并且滑動停止的話,則判斷isLoading是否處于加載狀态,如果不處于加載狀态的話,則調用onLoad方法去加載,這個方法裡面的Thread.sleep(2000)用于模拟耗時操作,随後利用ListAdapter的updateView方法更新ListView需要顯示的資料,最後調用loadComplete來結束重新整理操作,第98行設定重新整理視圖不可見,修改isLoading加載标志,最後将加載更多視圖從目前ListView中移除;

        至此,上拉加載更多講解結束,下一篇我們将講解一下下拉重新整理的實作,謝謝大家!

點選下載下傳源碼!!!!!