当前位置: 首页 > 编程笔记 >

Android自定义listview布局实现上拉加载下拉刷新功能

邵修诚
2023-03-14
本文向大家介绍Android自定义listview布局实现上拉加载下拉刷新功能,包括了Android自定义listview布局实现上拉加载下拉刷新功能的使用技巧和注意事项,需要的朋友参考一下

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布局实现上拉加载下拉刷新功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!

 类似资料:
  • 本文向大家介绍Android自定义下拉刷新上拉加载,包括了Android自定义下拉刷新上拉加载的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android自定义下拉刷新上拉加载的具体实现步骤,供大家参考,具体内容如下 实现的方式是SwipeRefreshLayout + RecyclerView 的VIewType 首先看效果: 总的思路: 布局文件 下拉刷新的实现思路 用于测试的

  • 本文向大家介绍Android自定义ListView实现下拉刷新,包括了Android自定义ListView实现下拉刷新的使用技巧和注意事项,需要的朋友参考一下 首先呈上效果图 当今APP,哪个没有点滑动刷新功能,简直就太落伍了。正因为需求多,因此自然而然开源的也就多。但是若想引用开源库,则很麻烦,比如PullToRefreshView这个库,如果把开源代码都移植到项目中,这是件很繁琐的事,如果用依

  • 本文向大家介绍Android ListView实现上拉加载更多和下拉刷新功能,包括了Android ListView实现上拉加载更多和下拉刷新功能的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家介绍了Android ListView下拉刷新功能的实现方法和功能,供大家参考,具体内容如下 1、ListView优化方式 界面缓存:ViewHolder+convertView 分页加载:上拉刷新

  • 本文向大家介绍Android实现上拉加载更多以及下拉刷新功能(ListView),包括了Android实现上拉加载更多以及下拉刷新功能(ListView)的使用技巧和注意事项,需要的朋友参考一下 首先为大家介绍Andorid5.0原生下拉刷新简单实现。 先上效果图; 相对于上一个19.1.0版本中的横条效果好看了很多。使用起来也很简单。 几行代码就可以实现下拉刷新,效果也还不错,不用引入第三方ja

  • 本文向大家介绍Android RefreshLayout实现下拉刷新布局,包括了Android RefreshLayout实现下拉刷新布局的使用技巧和注意事项,需要的朋友参考一下 项目中需要下拉刷新的功能,但是这个View不是ListView这类的控件,需要ViewGroup实现这个功能,一开始网上大略找了一下,没发现特别合适的,代码也是没怎么看懂,所以决定还是自己写一个。   于是翻出Xlist

  • 本文向大家介绍RecyclerView下拉刷新上拉加载,包括了RecyclerView下拉刷新上拉加载的使用技巧和注意事项,需要的朋友参考一下 一 、前言 最近实在太忙,一个多礼拜没有更新文章了,于是今晚加班加点把demo写出来,现在都12点了才开始写文章。 1.我们的目标 把RecyclerView下拉刷新上拉加载更多加入到我们的开发者头条APP中。 2.效果图 3.实现步骤 找一个带上拉刷新下