Android的ListView分頁功能(上滑加載更多)

  今天主要工做是將以前實現的各類ListView顯示所有信息,優化成了每次加載幾條數據,而後上滑的時候加載更多,底部顯示一個進度條和一個文字提示,而後加載完畢後,將提示信息隱藏。java

  一邊看教學視頻一遍敲代碼,邊學習邊實踐,感受學到了不少東西。android

  課程鏈接:http://www.imooc.com/learn/136web

  

  好了,說說是怎麼作的吧,供之後學習參考。json

  首先要定義一個footer.xml做爲進度條和提示加載中的底部佈局,代碼以下:服務器

    <LinearLayout
        android:id="@+id/load_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal"
        android:paddingBottom="10dip"
        android:paddingTop="10dip"
        tools:ignore="UselessParent" >

        <ProgressBar
            style="?android:attr/progressBarStyleLargeInverse"
            android:layout_width="30dp"
            android:layout_height="30dp" />
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="正在加載......"
            android:textSize="16sp"
            tools:ignore="HardcodedText" />

    </LinearLayout>

  這樣的顯示效果就是這樣的:網絡

  

  而後自定義一個LoadListView,繼承自ListView,實現其三個構造方法:app

    public LoadListView(Context context) {
        super(context);        
        initView(context);
    }
    public LoadListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }
    public LoadListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

  其中initView()是經過inflater初始化佈局的,代碼:less

    private void initView(Context context){
        LayoutInflater inflater = LayoutInflater.from(context);
        footer = inflater.inflate(R.layout.footer, null);
        footer.findViewById(R.id.load_layout).setVisibility(GONE);
        this.addFooterView(footer);
        this.setOnScrollListener(this);
    }

  而後,實現實現它的滑動事件接口,(詳見代碼,這裏只說過程),目的是爲了監聽ListView上滑到底部的時候,顯示那個【加載更多...】提示信息,而後實現加載更多的函數運行,達到加載出更多數據。異步

  那麼問題來了,加在了更多數據是從新設置數據適配器嗎?答案固然是不能夠從新設置,這裏咱們首先判斷adapter是否爲空,若是是空的,就setAdaper(),若是不是,其實就是加載更多之後,咱們不去從新設置,而是調用this.notifyDataSetChanged();  //當有數據變化的時候,ListView會自動刷新界面。這樣很好的保證了數據不會從新設置,效果還不錯。ide

            if(adapter == null){
                adapter = new FenleiAdapter(FenleiActivity.this, newsBeans);
                mListView.setAdapter(adapter);
            }else {
                adapter.onDateChange(newsBeans);
            }
    public void onDateChange(List<FenleiBean> mList) {
        // TODO Auto-generated method stub
        this.mList = mList;
        this.notifyDataSetChanged();  //當有數據變化的時候,自動刷新界面
        
    }

  繼續,這個時候咱們會遇到一個問題,就是在自定義類LoadListView中,怎麼去調用MainActivity中的方法,答案是接口回調,大概的意思就是在LoadListView中定義一個接口,而後去MainActivity具體實現這個接口,調用的時候,經過ListView變量來調用,具體我也只是大體明白這個意思,若是不明白能夠再百度一下。

  當ListView經過findViewById()找到控件id的時候,不要忘了將這個接口設置給ListView,代碼是mListView.setInterface(this);

  最後的最後要在加載完數據以後,去把提示消息設置爲隱藏,這樣,整個就大功告成了!!!

  最後的效果如圖:

   

        [上滑效果]                [加載更多之後的效果]

LoadListView.java源碼(具體還要根據你的項目去寫)

package com.tdyl.consult.fenlei;

import com.tdyl.consult.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

public class LoadListView extends ListView implements OnScrollListener {

    View footer; 
    int totalItemCount;
    int lastVisibleItem;
    boolean isLoading;
    ILoadListener2 iListener2;
    public LoadListView(Context context) {
        super(context);        
        initView(context);
    }
    public LoadListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }
    public LoadListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }
    
    private void initView(Context context){
        LayoutInflater inflater = LayoutInflater.from(context);
        footer = inflater.inflate(R.layout.footer, null);
        footer.findViewById(R.id.load_layout).setVisibility(GONE);
        this.addFooterView(footer);
        this.setOnScrollListener(this);
    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        this.lastVisibleItem = firstVisibleItem + visibleItemCount;
        this.totalItemCount = totalItemCount;
    }
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollStatus) {
        if(totalItemCount == lastVisibleItem
                && scrollStatus == SCROLL_STATE_IDLE){
            if(!isLoading){
                isLoading = true;
                footer.findViewById(R.id.load_layout).setVisibility(VISIBLE);
                //加載更多數據
                iListener2.onLoad();
            }
        }
    }
    
    public void loadComplete(){
        isLoading = false;
        footer.findViewById(R.id.load_layout).setVisibility(GONE);
    }
    
    public void setInterface(ILoadListener2 iListener2){
        this.iListener2 = iListener2;
    }
    
    public interface ILoadListener2{
        public void onLoad();
    }

}
View Code

MainActivity.java源碼(我這裏叫FenleiActivity.java,道理是同樣的)

package com.tdyl.consult.fenlei;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;

import com.tdyl.consult.R;
import com.tdyl.consult.fenlei.LoadListView.ILoadListener2;
import com.tdyl.consult.otochat.ChatOtoActivity;

public class FenleiActivity extends Activity implements ILoadListener2 {

    private LoadListView mListView;
    private String user_fenlei = "";
    private TextView title_name;
    int number = 10;
    FenleiAdapter adapter = null;

    ArrayList <HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>();  //用來存放用戶信息
    HashMap<String, Object> map = new HashMap<String, Object>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_fenlei);
        title_name = (TextView) findViewById(R.id.id_top_fenlei);
        mListView = (LoadListView) findViewById(R.id.lv_main);
        mListView.setInterface(this);
        Intent intent = getIntent();
        user_fenlei = intent.getStringExtra("user_fenlei");
        //-----------------------------------------------------------------------------
        title_name.setText(user_fenlei+"專家");
        new NewsAsynkTask().execute(number);
    }

    /**
     * 將url對應的json格式數據轉化爲咱們縮封裝的NewsBean對象
     * @param url
     * @return
     */
    private List<FenleiBean> getJsonData(int number){
        List<FenleiBean> newsBeanList = new ArrayList<FenleiBean>();
        //-----------------------------------------------------------------------------
        searchTop10(number);
        FenleiBean newsBean;
        if(list.size() == 0)
        {
            new AlertDialog.Builder(this)
            .setIcon(R.drawable.icon_menu)
            .setTitle("舒適小提示")
            .setMessage("沒有要搜尋的專家分類")
            .setPositiveButton("馬上返回搜索界面...", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    finish();
                }
            }).show();
        }
        for(int i=0;i<list.size();i++)
        {
            newsBean = new FenleiBean();
            HashMap<String, Object> map1 = new HashMap<String, Object>();
            map1 = list.get(i);
            newsBean.newsIconUrl = map1.get("user_touxiangURL").toString();
            newsBean.newTitle = map1.get("username").toString();
            newsBean.newsContent = map1.get("user_qianming").toString();
            newsBean.newsJifen = map1.get("user_jifen").toString();
            newsBeanList.add(newsBean);
        }
        return newsBeanList;    
    }

    /**
     * 實現網絡的異步訪問
     * @author Lenovo
     *
     */
    class NewsAsynkTask extends AsyncTask<Integer,Void, List<FenleiBean>>{

        @Override
        protected List<FenleiBean> doInBackground(Integer... params) {
            return getJsonData(params[0]);
        }

        @Override
        protected void onPostExecute(List<FenleiBean> newsBeans) {
            // TODO Auto-generated method stub
            super.onPostExecute(newsBeans);
            if(adapter == null){
                adapter = new FenleiAdapter(FenleiActivity.this, newsBeans);
                mListView.setAdapter(adapter);
            }else {
                adapter.onDateChange(newsBeans);
            }

            mListView.setOnItemClickListener(new OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
                    // TODO Auto-generated method stub
                    HashMap<String, Object> map1 = list.get(position);
                    Intent intent=new Intent();
                    intent.setClass(FenleiActivity.this,ChatOtoActivity.class);
                    intent.putExtra("username", map1.get("username").toString());     //用戶名傳到另外一個界面
                    System.out.println("username"+map1.get("username").toString());
                    intent.putExtra("touxiang", map1.get("user_touxiangURL").toString());    //頭像地址
                    //啓動
                    startActivity(intent);

                    //Toast.makeText(FenleiActivity.this, "點擊了"+newsBean.get("username"),Toast.LENGTH_SHORT).show();
                }
            });
        }


    }

    /**
     * 查詢用戶分類信息函數,放入list中,經過關鍵字key來取出
     * */

    public void searchTop10(int number)
    {
        //命名空間
        String nameSpace = "http://wsServer.gnuhpc.org/";
        //方法名字
        String methodName = "SearchTeacherTop10";
        // endPoint
        String endPoint =  "http://10.0.2.2:8080/wsServerHello";
        //soapAction
        String soapAction = "http://wsServer.gnuhpc.org/SearchTeacherTop10";
        //指定調用方法命名空間和方法名字
        SoapObject rpc = new SoapObject(nameSpace, methodName); 
        //調用方法時須要傳入一個參數
        //爲了與web service保持一致,須要設置爲arg0,由於web service會自動將其轉化爲arg0 arg1
        rpc.addProperty("arg0",user_fenlei);
        rpc.addProperty("arg1",number);
        try {
            //wsdl地址
            HttpTransportSE transport = new HttpTransportSE(endPoint);
            transport.debug= true;
            //生成調用WebService方法的SOAP請求信息,並指定SOAP的版本 
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);    
            envelope.bodyOut = rpc;    
            //設置是否調用的是dotNet開發的WebService,服務器是.net的須要設置爲true,java不用
            envelope.dotNet = false;                 
            envelope.setOutputSoapObject(rpc);                 

            System.out.println("rpc:"+rpc); 
            System.out.println("enevlope:"+envelope); 
            System.out.println("---基本服務設置完畢,下面開始調用服務");

            Log.v("---調用消息:", "開始call函數");
            transport.call(soapAction, envelope);
            Log.v("---函數結果:", ""+envelope.getResponse());
            if(envelope.getResponse()!=null)  
            {
                // 獲取返回的數據  
                SoapObject object = (SoapObject) envelope.bodyIn; 
                System.out.println("---object:"+object);
                System.out.println("---獲取數據成功!");
                System.out.println("object.toString():"+object.toString()); 

                // 獲取返回的結果 ,將結果存入到一個Map中
                System.out.println(object.getProperty(0)); 
                int count = object.getPropertyCount();
                System.out.println("#######################"+count);

                for(int index = 0; index < count; index = index + 5)  //表中有五個關鍵字,循環條件+5
                {
                    map = new HashMap<String, Object>();
                    map.put("username", object.getProperty(index).toString());  //用戶名
                    map.put("user_fenlei", object.getProperty(index+1).toString());  //分類
                    map.put("user_qianming", object.getProperty(index+2).toString());  //簽名
                    map.put("user_touxiangURL", object.getProperty(index+3).toString());  //在線狀態
                    map.put("user_jifen", object.getProperty(index+4).toString());  //積分
                    list.add(map);
                }
                System.out.println("list的值爲:"+list);
            }
            else{
                Log.v("----鏈接消息:", "鏈接失敗");
            }
        } catch (SoapFault e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onLoad() {
        //獲取更多數據
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {

            @Override
            public void run() {
                number=number+2;  //每次多顯示兩條數據
                new NewsAsynkTask().execute(number);
                //通知listView顯示更新,加載完畢 
                
                /**
                 * 設置默認顯示爲Listview最後一行
                 */
                mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
                mListView.setStackFromBottom(true);
                //通知listView加載完畢,底部佈局消失
                mListView.loadComplete();

            }
        }, 1000);
    }

}
View Code

  感謝這門視頻課程,汲取養分,繼續努力......

相關文章
相關標籤/搜索