Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義listview布局實現上拉加載下拉刷新功能

Android自定義listview布局實現上拉加載下拉刷新功能

編輯:關於Android編程

listview實現上拉加載以及下拉刷新的方式有很多。下面是我寫的一種自定義的布局,復用性也比較的強。首先就是繼承的listview的自定義view。

     AutoListView.Java:

package com.example.mic.testdemo.view; 
import android.annotation.TargetApi; 
import android.content.Context; 
import android.os.Build; 
import android.os.Bundle; 
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.view.animation.Animation; 
import android.view.animation.LinearInterpolator; 
import android.view.animation.RotateAnimation; 
import android.widget.AbsListView; 
import android.widget.ImageView; 
import android.widget.ListView; 
import android.widget.ProgressBar; 
import android.widget.TextView; 
import com.example.mic.testdemo.R; 
import java.text.SimpleDateFormat; 
/** 
 * Created by DFLENOVO on 2016/8/3. 
 */ 
public class AutoListView extends ListView implements AbsListView.OnScrollListener { 
  public static final String FOOTER = "FOOTER"; 
  public static final String HEADER = "HEADER"; 
  private static final int PULL = 1; 
  private static final int NONE = 0; 
  //  private static final int RELEASE = 2; 
  private static final int REFRESHING = 2; 
  private static final int SPACE = 20; 
  private static final String TAG = "AutoListView"; 
  private RotateAnimation downAnimation; 
  private RotateAnimation upAnimation; 
  private Context context; 
  private LayoutInflater inflater; 
  private View footer; 
  private View header; 
  private int headerContentInitialHeight; 
  private int headerContentHeight; 
  private OnRefreshListener onRefreshListener; 
  private boolean loadEnable; 
  private OnLoadListener onLoadListener; 
  private int firstVisibleItem; 
  private boolean isLoadingMore = false; 
  private int startY; 
  private int state; 
  private ImageView iv_pull; 
  private int footerViewHeight; 
  private ProgressBar mProgressBar; 
  private TextView tvState; 
  private TextView tvLastUpdateTime; 
  private boolean isScrollToBottom; 
  public AutoListView(Context context) { 
    super(context); 
    initView(context); 
  } 
  public AutoListView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    initView(context); 
  } 
  public AutoListView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    initView(context); 
  } 
  @TargetApi(Build.VERSION_CODES.LOLLIPOP) 
  public AutoListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
    super(context, attrs, defStyleAttr, defStyleRes); 
    initView(context); 
  } 
  private void initView(Context context) { 
    initHeaderView(); 
    initFooterView(); 
    this.setOnScrollListener(this); 
// 
  } 
  private void initHeaderView() { 
    header = View.inflate(getContext(), R.layout.pull_to_refresh_header, null); 
    iv_pull = (ImageView) header 
        .findViewById(R.id.iv_pull); 
    mProgressBar = (ProgressBar) header 
        .findViewById(R.id.pb_listview_header); 
    tvState = (TextView) header 
        .findViewById(R.id.tv_listview_header_state); 
    tvLastUpdateTime = (TextView) header 
        .findViewById(R.id.tv_listview_header_last_update_time); 
    // 設置最後刷新時間 
    tvLastUpdateTime.setText("最後刷新時間: " + getLastUpdateTime()); 
    header.measure(0, 0); // 系統會幫我們測量出headerView的高度 
    headerContentHeight = header.getMeasuredHeight(); 
    header.setPadding(0, -headerContentHeight, 0, 0); 
    this.addHeaderView(header,HEADER,true); // 向ListView的頂部添加一個view對象 
    initAnimation(); 
  } 
  private void initAnimation() { 
    upAnimation = new RotateAnimation(0f, -180f, 
        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
        0.5f); 
    upAnimation.setDuration(500); 
    upAnimation.setFillAfter(true); // 動畫結束後, 停留在結束的位置上 
    downAnimation = new RotateAnimation(-180f, -360f, 
        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 
        0.5f); 
    downAnimation.setDuration(500); 
    downAnimation.setFillAfter(true); // 動畫結束後, 停留在結束的位置上 
  } 
  private String getLastUpdateTime() { 
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
    return sdf.format(System.currentTimeMillis()); 
  } 
  private void initFooterView() { 
    footer = View.inflate(getContext(), R.layout.foot_view, null); 
    footer.measure(0, 0); 
    footerViewHeight = footer.getMeasuredHeight(); 
    footer.setPadding(0, -footerViewHeight, 0, 0); 
    this.addFooterView(footer,FOOTER,true); 
  } 
  private void measureView(View child) { 
    ViewGroup.LayoutParams p = child.getLayoutParams(); 
    if (p == null) { 
      p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
          ViewGroup.LayoutParams.WRAP_CONTENT); 
    } 
    int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); 
    int lpHeight = p.height; 
    int childHeightSpec; 
    if (lpHeight > 0) { 
      childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, 
          MeasureSpec.EXACTLY);//得到的是size。 
    } else { 
      childHeightSpec = MeasureSpec.makeMeasureSpec(0, 
          MeasureSpec.UNSPECIFIED);//得到的是子布局的實際大小。 
    } 
    child.measure(childWidthSpec, childHeightSpec); 
  } 
  private void topPadding(int topPadding) { 
    header.setPadding(header.getPaddingLeft(), topPadding, 
        header.getPaddingRight(), header.getPaddingBottom()); 
    header.invalidate(); 
  } 
  @Override 
  public void onScrollStateChanged(AbsListView absListView, int i) { 
    if (i == SCROLL_STATE_IDLE 
        || i == SCROLL_STATE_FLING) { 
      // 判斷當前是否已經到了底部 
      if (isScrollToBottom && !isLoadingMore) { 
        isLoadingMore = true; 
        // 當前到底部 
        Log.i(TAG, "加載更多數據"); 
        footer.setPadding(0, 0, 0, 0); 
        this.setSelection(this.getCount()); 
        if (onLoadListener != null) { 
          onLoadListener.onLoad(); 
        } 
      } 
    } 
  } 
  @Override 
  public void onScroll(AbsListView absListView, int i, int i1, int i2) { 
    this.firstVisibleItem = i; 
    if (getLastVisiblePosition() == (i2 - 1)) { 
      isScrollToBottom = true; 
    } else { 
      isScrollToBottom = false; 
    } 
  } 
  @Override 
  public boolean onTouchEvent(MotionEvent ev) { 
    switch (ev.getAction()) { 
// 
      case MotionEvent.ACTION_DOWN: 
        startY = (int) ev.getY(); 
        break; 
      case MotionEvent.ACTION_MOVE: 
        int moveY = (int) ev.getY(); 
        // 移動中的y - 按下的y = 間距. 
        int diff = (moveY - startY) / 2; 
        // -頭布局的高度 + 間距 = paddingTop 
        int paddingTop = -headerContentHeight + diff; 
        // 如果: -頭布局的高度 > paddingTop的值 執行super.onTouchEvent(ev); 
        if (firstVisibleItem == 0 
            && -headerContentHeight < paddingTop) { 
          if (paddingTop > 0 && state == NONE) { // 完全顯示了. 
            Log.i(TAG, "松開刷新"); 
            state = PULL; 
            refreshHeaderViewByState(); 
          } else if (paddingTop < 0 
              && state == PULL) { // 沒有顯示完全 
            Log.i(TAG, "下拉刷新"); 
            state = NONE; 
            refreshHeaderViewByState(); 
          } 
          // 下拉頭布局 
          header.setPadding(0, paddingTop, 0, 0); 
        } 
        break; 
      case MotionEvent.ACTION_UP: 
        // 判斷當前的狀態是松開刷新還是下拉刷新 
        if (state == PULL) { 
          Log.i(TAG, "刷新數據."); 
          // 把頭布局設置為完全顯示狀態 
          header.setPadding(0, 0, 0, 0); 
          // 進入到正在刷新中狀態 
          state = REFRESHING; 
          refreshHeaderViewByState(); 
          if (onRefreshListener != null) { 
            onRefreshListener.onRefresh(); // 調用使用者的監聽方法 
          } 
        } else if (state == NONE) { 
          // 隱藏頭布局 
          header.setPadding(0, -headerContentHeight, 0, 0); 
        } 
        break; 
      default: 
        break; 
    } 
    return super.onTouchEvent(ev); 
  } 
// 
  private void refreshHeaderViewByState() { 
    switch (state) { 
// 
      case NONE: // 下拉刷新狀態 
        tvState.setText("下拉刷新"); 
        iv_pull.startAnimation(downAnimation); // 執行向下旋轉 
        break; 
      case PULL: // 松開刷新狀態 
        tvState.setText("松開刷新"); 
        iv_pull.startAnimation(upAnimation); // 執行向上旋轉 
        break; 
      case REFRESHING: // 正在刷新中狀態 
        iv_pull.clearAnimation(); 
        iv_pull.setVisibility(View.GONE); 
        mProgressBar.setVisibility(View.VISIBLE); 
        tvState.setText("正在刷新中..."); 
        break; 
      default: 
        break; 
    } 
  } 
  public void hideHeaderView() { 
    header.setPadding(0, -headerContentHeight, 0, 0); 
    iv_pull.setVisibility(View.VISIBLE); 
    mProgressBar.setVisibility(View.GONE); 
    tvState.setText("下拉刷新"); 
    tvLastUpdateTime.setText("最後刷新時間: " + getLastUpdateTime()); 
    state = NONE; 
  } 
  public void hideFooterView() { 
    footer.setPadding(0, -footerViewHeight, 0, 0); 
    isLoadingMore = false; 
  } 
  public void setOnRefreshListener(OnRefreshListener onRefreshListener) { 
    this.onRefreshListener = onRefreshListener; 
  } 
  public void setOnLoadListener(OnLoadListener onLoadListener) { 
    this.onLoadListener = onLoadListener; 
  } 
  public void onRefresh() { 
    if (onRefreshListener != null) { 
      onRefreshListener.onRefresh(); 
    } 
  } 
  public void onLoad() { 
    if (onLoadListener != null) { 
      onLoadListener.onLoad(); 
    } 
  } 
  public interface OnRefreshListener {//定義下拉刷新接口 
    public void onRefresh(); 
  } 
  public interface OnLoadListener {//定義上拉加載更多 
    public void onLoad(); 
  } 
} 

        上面的代碼就是實現的關鍵.下面是頭布局以及腳布局:

foot_view.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="wrap_content"> 
  <TextView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="加載更多" 
    android:textSize="20dp" 
    android:padding="10dp" 
    android:layout_centerHorizontal="true"/> 
</RelativeLayout> 

pull_to_refresh_header.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:orientation="horizontal"> 
  <FrameLayout 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_margin="10dip" > 
    <ImageView 
      android:id="@+id/iv_pull" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_gravity="center" 
      android:minWidth="30dip" 
      android:src="@mipmap/xlistview_arrow" /> 
    <ProgressBar 
      android:id="@+id/pb_listview_header" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_gravity="center" 
      android:visibility="gone" /> 
  </FrameLayout> 
  <LinearLayout 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center_vertical" 
    android:gravity="center_horizontal" 
    android:orientation="vertical" > 
    <TextView 
      android:id="@+id/tv_listview_header_state" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="下拉刷新" 
      android:textColor="#FF0000" 
      android:textSize="18sp" /> 
    <TextView 
      android:id="@+id/tv_listview_header_last_update_time" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginTop="5dip" 
      android:text="最後刷新時間: 2014-10-10 12:56:12" 
      android:textColor="@android:color/black" 
      android:textSize="14sp" /> 
  </LinearLayout> 
</LinearLayout> 

activity_main.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:id="@+id/activity_main" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:paddingBottom="@dimen/activity_vertical_margin" 
  android:paddingLeft="@dimen/activity_horizontal_margin" 
  android:paddingRight="@dimen/activity_horizontal_margin"  android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.mic.testdemo.MainActivity">       <com.example.mic.testdemo.view.AutoListView 
        android:id="@+id/lv" 
        android:layout_width="match_parent" 
       android:layout_height="match_parent"> 
      </com.example.mic.testdemo.view.AutoListView> 
</RelativeLayout> 

      上面所完成的步驟就是在listview上下加載不同的布局,上面也是要復用的代碼,下面的代碼就是怎麼使用的代碼了.

MainActivity.java:

public class MainActivity extends AppCompatActivity implements AutoListView.OnLoadListener,AutoListView.OnRefreshListener { 
  private TextView textView; 
  private String result; 
  private AutoListView listView; 
  private MyAdater adater; 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    listView = (AutoListView) findViewById(R.id.lv);} 
listView.setOnRefreshListener(MainActivity.this); 
listView.setOnLoadListener(MainActivity.this); 
@Override 
  public void onLoad() { 
  } 
  @Override 
  public void onRefresh() {} 

下面就是實現,就是在你需要的地方設置監聽,以及上面加載以及刷新需要的操作就可以了!

以上所述是小編給大家介紹的Android自定義listview布局實現上拉加載下拉刷新功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved