国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

Android ListView 實(shí)現(xiàn)上拉加載的示例代碼

2019-12-12 00:42:52
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

本文介紹了Android ListView 實(shí)現(xiàn)上拉加載的示例代碼,分享給大家,具體如下:

我們先分析一下如何實(shí)現(xiàn) ListView 上拉加載。

  • 當(dāng)我們上拉的時(shí)候,會(huì)出現(xiàn)一個(gè)提示界面,即 ListView 的 Footer 布局。
  • ListView 要實(shí)現(xiàn)滾動(dòng),所以要監(jiān)聽(tīng) ListView 滾動(dòng)事件,即 OnScrollListener() 事件。
  • 當(dāng)我們開(kāi)始滾動(dòng)時(shí),F(xiàn)ooter 布局才慢慢顯示出來(lái),所以需要監(jiān)聽(tīng) ListView 的 onTouch() 事件。

實(shí)現(xiàn)思路

  1. 首先判斷 ListView 加載時(shí)機(jī),當(dāng) ListView 的 lastVisibleItem == totalItemCount 時(shí)表示當(dāng)前處于 ListView 最底端,此時(shí)允許下拉。
  2. 自定義一個(gè) FooterView,將 FooterView 添加到 ListView 底部,在上拉時(shí)候的顯示和完成時(shí)候的隱藏。
  3. 定義一個(gè)加載接口,當(dāng)上拉動(dòng)作完成時(shí)候回調(diào),用于標(biāo)記狀態(tài)并加載最新數(shù)據(jù)進(jìn)行展示。

1、定義 Footer

Footer 要實(shí)現(xiàn)的效果:

第一次上拉時(shí),F(xiàn)ooter 逐漸顯示,文字顯示為下拉可以加載,箭頭向上,進(jìn)度條隱藏。

當(dāng)松開(kāi)加載的時(shí)候,箭頭隱藏,進(jìn)度條展示,文字改為正在加載。

1、Footer 加載時(shí)狀態(tài)變化

定義一個(gè)如上圖所示的 Footer 的 XML 文件 footer_layout.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:paddingBottom="10dp"  android:paddingTop="10dp">  <LinearLayout    android:id="@+id/layout"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_centerHorizontal="true"    android:layout_marginTop="10dp"    android:gravity="center"    android:orientation="vertical">    <TextView      android:id="@+id/tv_tip"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:text="下拉可以刷新"      android:textSize="12sp" />  </LinearLayout>  <ImageView    android:id="@+id/img_arrow"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginRight="10dp"    android:layout_toLeftOf="@+id/layout"    android:src="@drawable/pull_to_refresh_arrow" />  <ProgressBar    android:id="@+id/progress"    style="@style/progressBar_custom_drawable"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_centerVertical="true"    android:layout_marginRight="10dp"    android:layout_toLeftOf="@+id/img_arrow"    android:visibility="gone"    tools:visibility="visible" /></RelativeLayout>

2、初始化布局

定義一個(gè) RefreshListView 類繼承 ListView,重寫(xiě)構(gòu)造函數(shù),并將 Footer 添加到 ListView 中。

public class RefreshListView extends ListView {  private View header;  private int headerHeight;//頂部布局高度  private int firstVisibleItem;//當(dāng)前第一個(gè) Item 可見(jiàn)位置  private float startY;//按下時(shí)開(kāi)始的Y值  private int scrollState;//當(dāng)前滾動(dòng)狀態(tài)    private View footer;  private int footerHeight;//底部布局高度  private float lastY;  private boolean canLoadMoreEnabled;//是否允許加載更多    public RefreshListView(Context context) {    super(context);    initView(context);  }  public RefreshListView(Context context, AttributeSet attrs) {    super(context, attrs);    initView(context);  }  public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    initView(context);  }  private void initView(Context context) {    header = LayoutInflater.from(context).inflate(R.layout.header_layout, null);    footer = LayoutInflater.from(context).inflate(R.layout.footer_layout, null);    measureView(header);    measureView(footer);    //這里獲取高度的時(shí)候需要先通知父布局header占用的空間    headerHeight = header.getMeasuredHeight();    footerHeight = footer.getMeasuredHeight();    topPadding(-headerHeight);    bottomPadding(-footerHeight);//用于隱藏 Footer    this.addHeaderView(header);    this.addFooterView(footer);    this.setOnScrollListener(this);  }    /**   * 設(shè)置 Footer 布局的下邊距   * 以隱藏 Footer   * @param topPadding   */  private void bottomPadding(int bottomPadding) {    footer.setPadding(footer.getPaddingLeft(), footer.getPaddingTop(),        footer.getPaddingRight(),        bottomPadding);    footer.invalidate();  }}

3、實(shí)現(xiàn)上拉加載

給 ListView 設(shè)置監(jiān)聽(tīng)

public class RefreshListView extends ListView implements AbsListView.OnScrollListener {  private int firstVisibleItem;//當(dāng)前第一個(gè) Item 可見(jiàn)位置  private int scrollState;//當(dāng)前滾動(dòng)狀態(tài)    private void initView(Context context) {    header = LayoutInflater.from(context).inflate(R.layout.header_layout, null);    footer = LayoutInflater.from(context).inflate(R.layout.footer_layout, null);    measureView(header);    measureView(footer);    //這里獲取高度的時(shí)候需要先通知父布局header占用的空間    headerHeight = header.getMeasuredHeight();    footerHeight = footer.getMeasuredHeight();    topPadding(-headerHeight);    bottomPadding(-footerHeight);    this.addHeaderView(header);    this.addFooterView(footer);    this.setOnScrollListener(this);  }    @Override  public void onScrollStateChanged(AbsListView view, int scrollState) {    this.scrollState = scrollState;  }  @Override  public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    this.firstVisibleItem = firstVisibleItem;    this.lastVisibleItem = firstVisibleItem + visibleItemCount;    this.totalItemCount = totalItemCount;  }}

加載的時(shí)機(jī)是判斷l(xiāng)astVisibleItem == totalItemCount,而上拉事件我們需要重寫(xiě) onTouchEvent() 事件,首先定義幾個(gè)狀態(tài)。

private float lastY;private static int state;//當(dāng)前狀態(tài)private final static int NONE = 0;//正常狀態(tài)private final static int PULL = 1;//下拉狀態(tài)private final static int RELEASE = 2;//釋放狀態(tài)private final static int REFRESHING = 3;//正在刷新?tīng)顟B(tài)

在 onTouchEvent 中,在 ACTION_DOWN 時(shí),記錄最開(kāi)始的 Y 值,然后在 ACTION_MOVE 事件中實(shí)時(shí)記錄移動(dòng)距離 space,不斷刷新 FooterView 的 bootomPadding,讓它跟隨滑動(dòng)距離進(jìn)行顯示,繼續(xù)滑動(dòng),當(dāng) space 大于了 FooterHeight 時(shí),狀態(tài)給為 RELEASE,表示可以釋放進(jìn)行刷新操作。

@Override  public boolean onTouchEvent(MotionEvent ev) {    switch (ev.getAction()) {      case MotionEvent.ACTION_DOWN:        //最頂部        if (firstVisibleItem == 0) {//刷新          canRefreshEnabled = true;          startY = ev.getY();        } else if (lastVisibleItem == totalItemCount) {//加載更多          canLoadMoreEnabled = true;          lastY = ev.getY();        }        break;      case MotionEvent.ACTION_MOVE:        onMove(ev);        break;      case MotionEvent.ACTION_UP:        if (state == RELEASE) {//如果已經(jīng)釋放,則可以提示刷新數(shù)據(jù)          state = REFRESHING;          if (iRefreshListener != null) {            iRefreshListener.onRefresh();          }          if (iLoadMoreListener != null) {            iLoadMoreListener.onLoadMore();          }        } else if (state == PULL) {//如果是在下拉狀態(tài),不刷新數(shù)據(jù)          state = NONE;        }        if (canRefreshEnabled) {          refreshViewByState();        }        if (canLoadMoreEnabled) {          loadViewByState();        }        canLoadMoreEnabled = false;        canRefreshEnabled = false;        break;    }    return super.onTouchEvent(ev);  }  /**   * 判斷移動(dòng)過(guò)程中的操作   *   * @param ev   */  private void onMove(MotionEvent ev) {    int tempY = (int) ev.getY();    int refreshSpace = (int) (tempY - startY);//向下移動(dòng)的距離    int topPadding = refreshSpace - headerHeight;//在移動(dòng)過(guò)程中不斷設(shè)置 topPadding    int loadSpace = (int) (lastY - tempY);//向上移動(dòng)的距離    int bottomPadding = loadSpace - footerHeight;//在移動(dòng)過(guò)程中不斷設(shè)置 bottomPadding    switch (state) {      case NONE:        //下拉移動(dòng)距離大于0        if (refreshSpace > 0) {          state = PULL; //狀態(tài)變成下拉狀態(tài)          refreshViewByState();        }        //上拉移動(dòng)距離大于0        if (loadSpace > 0) {          state = PULL;//狀態(tài)變成下拉狀態(tài)          loadViewByState();        }        break;      case PULL:        if (canRefreshEnabled) {          topPadding(topPadding);//在移動(dòng)過(guò)程中不斷設(shè)置 topPadding,讓 Header 隨著下拉動(dòng)作慢慢顯示        }        if (canLoadMoreEnabled) {          bottomPadding(bottomPadding);//在移動(dòng)過(guò)程中不斷設(shè)置 bottomPadding,讓 Footer 隨著上拉動(dòng)作慢慢顯示        }        //移動(dòng)距離大于headerHeight并且正在滾動(dòng)        if (canRefreshEnabled && refreshSpace > (headerHeight + 30) && scrollState == SCROLL_STATE_TOUCH_SCROLL) {          state = RELEASE;//提示釋放          refreshViewByState();        }        //移動(dòng)距離大于footerHeight并且正在滾動(dòng)        if (canLoadMoreEnabled && loadSpace > footerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {          state = RELEASE;//提示釋放          loadViewByState();//刷新footer布局        }        break;      case RELEASE:        if (canRefreshEnabled) {          topPadding(topPadding);          //移動(dòng)距離小于headerHeight          if (refreshSpace < headerHeight + 30) {            state = PULL;//提示下拉          } else if (refreshSpace <= 0) {            state = NONE;          }          refreshViewByState();//更新header        }        if (canLoadMoreEnabled) {          bottomPadding(bottomPadding);          //移動(dòng)距離小于footerHeight          if (loadSpace < footerHeight + 30) {            state = PULL;//提示下拉          } else if (loadSpace <= 0) {            state = NONE;          }          loadViewByState();//更新footer        }        break;    }  }

加載數(shù)據(jù)的時(shí)候,要根據(jù)狀態(tài)不斷改變 FooterView 的顯示,箭頭定義一個(gè)旋轉(zhuǎn)動(dòng)畫(huà)讓其跟隨滑動(dòng)距離實(shí)現(xiàn)旋轉(zhuǎn),進(jìn)度條也設(shè)置了逐幀動(dòng)畫(huà)實(shí)現(xiàn)自定義進(jìn)度條。

private void loadViewByState() {    TextView tip = footer.findViewById(R.id.tv_tip);    ImageView arrow = footer.findViewById(R.id.img_arrow);    ProgressBar progressBar = footer.findViewById(R.id.progress);    progressBar.setBackgroundResource(R.drawable.custom_progress_bar);    AnimationDrawable animationDrawable = (AnimationDrawable) progressBar.getBackground();    //給箭頭設(shè)置動(dòng)畫(huà)    RotateAnimation anim = new RotateAnimation(0, 180,        RotateAnimation.RELATIVE_TO_SELF, 0.5f,        RotateAnimation.RELATIVE_TO_SELF, 0.5f);    RotateAnimation anim1 = new RotateAnimation(180, 0,        RotateAnimation.RELATIVE_TO_SELF, 0.5f,        RotateAnimation.RELATIVE_TO_SELF, 0.5f);    anim.setDuration(200);    anim.setFillAfter(true);    anim1.setDuration(200);    anim1.setFillAfter(true);    switch (state) {      case NONE://正常,footer不顯示        bottomPadding(-footerHeight);        arrow.clearAnimation();        break;      case PULL://下拉狀態(tài)        arrow.setVisibility(VISIBLE);//箭頭顯示,進(jìn)度條隱藏        progressBar.setVisibility(GONE);        if (animationDrawable.isRunning()) {          animationDrawable.stop();        }        tip.setText("上拉可以加載");        arrow.clearAnimation();        arrow.setAnimation(anim);//箭頭向下        break;      case RELEASE://釋放狀態(tài)        arrow.setVisibility(VISIBLE);//箭頭顯示,進(jìn)度條隱藏        progressBar.setVisibility(GONE);        if (animationDrawable.isRunning()) {          //停止動(dòng)畫(huà)播放          animationDrawable.stop();        }        tip.setText("松開(kāi)開(kāi)始加載");        arrow.clearAnimation();        arrow.setAnimation(anim);//箭頭向上        break;      case REFRESHING://刷新?tīng)顟B(tài)        bottomPadding(50);        arrow.setVisibility(GONE);//箭頭顯示,進(jìn)度條隱藏        progressBar.setVisibility(VISIBLE);        animationDrawable.start();        tip.setText("正在加載...");        arrow.clearAnimation();        break;    }  }

4、下拉刷新完成回調(diào)

當(dāng)上拉加載完成時(shí),我們需要實(shí)現(xiàn)數(shù)據(jù)的刷新,并且要通知 Adapter 刷新數(shù)據(jù),這里我們定義一個(gè)監(jiān)聽(tīng)接口實(shí)現(xiàn)回調(diào)即可。回調(diào)在 ACTION_UP 的 RELEASE 狀態(tài)下進(jìn)行注冊(cè)。

private ILoadMoreListener iLoadMoreListener;  public void setILoadMoreListener(ILoadMoreListener iLoadMoreListener) {    this.iLoadMoreListener = iLoadMoreListener;  }  public interface ILoadMoreListener {    void onLoadMore();  }

5、測(cè)試

package com.dali.refreshandloadmorelistview;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import java.util.ArrayList;public class MainActivity extends Activity implements RefreshListView.IRefreshListener, RefreshListView.ILoadMoreListener {  private ArrayList<ApkEntity> apk_list;  private ListAdapter adapter;  private RefreshListView listView;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    setData();    showList(apk_list);  }  private void showList(ArrayList<ApkEntity> apk_list) {    if (adapter == null) {      listView = (RefreshListView) findViewById(R.id.listview);      listView.setIRefreshListener(this);      listView.setILoadMoreListener(this);      adapter = new ListAdapter(this, apk_list);      listView.setAdapter(adapter);    } else {      adapter.onDateChange(apk_list);    }  }  private void setData() {    apk_list = new ArrayList<ApkEntity>();    for (int i = 0; i < 10; i++) {      ApkEntity entity = new ApkEntity();      entity.setName("默認(rèn)數(shù)據(jù)" + i);      entity.setDes("這是一個(gè)神奇的應(yīng)用");      entity.setInfo("50w用戶");      apk_list.add(entity);    }  }  private void setRefreshData() {    for (int i = 0; i < 2; i++) {      ApkEntity entity = new ApkEntity();      entity.setName("默認(rèn)數(shù)據(jù) + 刷新" + i);      entity.setDes("這是一個(gè)神奇的應(yīng)用");      entity.setInfo("50w用戶");      apk_list.add(0, entity);    }  }  private void setLoadData() {    for (int i = 0; i < 2; i++) {      ApkEntity entity = new ApkEntity();      entity.setName("默認(rèn)數(shù)據(jù) + 加載" + (adapter.getCount() + i));      entity.setDes("這是一個(gè)神奇的應(yīng)用");      entity.setInfo("50w用戶");      apk_list.add(entity);    }  }  @Override  public void onRefresh() {    //添加刷新動(dòng)畫(huà)效果    Handler handler = new Handler();    handler.postDelayed(new Runnable() {      @Override      public void run() {        //獲取最新數(shù)據(jù)        setRefreshData();        //通知界面顯示數(shù)據(jù)        showList(apk_list);        //通知 ListView 刷新完成        listView.refreshComplete();      }    }, 2000);  }  @Override  public void onLoadMore() {    Handler handler = new Handler();    handler.postDelayed(new Runnable() {      @Override      public void run() {        //獲取最新數(shù)據(jù)        setLoadData();        //通知界面顯示數(shù)據(jù)        showList(apk_list);        //通知 ListView 刷新完成        listView.loadMoreComplete();      }    }, 2000);  }}

GitHub 源碼

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 湟中县| 中西区| 周口市| 土默特右旗| 故城县| 临洮县| 东台市| 嘉祥县| 商南县| 通山县| 姜堰市| 武山县| 睢宁县| 土默特右旗| 凤城市| 萨迦县| 固安县| 岳阳市| 吉木萨尔县| 陈巴尔虎旗| 赤城县| 长泰县| 岳阳县| 永修县| 汤阴县| 孝感市| 玉田县| 肥东县| 赤峰市| 光泽县| 亚东县| 连云港市| 舟曲县| 海林市| 大姚县| 宝清县| 孝昌县| 武穴市| 锡林浩特市| 芦溪县| 广宗县|