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

作者:yuanhangLVli 时间:2023-05-12 23:27:28 

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>

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

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布局实现上拉加载下拉刷新功能网站的支持!

来源:http://blog.csdn.net/yuanhanglvli/article/details/53635400

标签:listview,上拉加载,下拉刷新
0
投稿

猜你喜欢

  • Android应用程序保持后台唤醒(使用WakeLock实现)

    2022-07-03 07:46:13
  • 面试初级Java开发问到Arrays

    2023-11-27 05:40:04
  • 解决spring boot启动扫描不到自定义注解的问题

    2023-10-29 14:31:48
  • 适配Android 8.0版本更新安装与通知栏的一些坑

    2022-05-01 13:23:25
  • 3分钟纯 Java 注解搭个管理系统的示例代码

    2023-05-29 07:57:46
  • Spring Boot 集成PageHelper的使用方法

    2021-10-04 19:16:30
  • Winform控件优化之圆角按钮1

    2021-05-31 20:15:36
  • Android View的事件分发机制深入分析讲解

    2023-06-18 21:28:49
  • C#实现简单文本编辑器

    2022-04-28 06:42:30
  • Android Activity通用悬浮可拖拽View封装的思路详解

    2023-08-08 15:31:48
  • Mybatis批量插入index out of range错误的解决(较偏的错误)

    2022-06-11 01:11:51
  • 深入了解Java中String、Char和Int之间的相互转换

    2022-09-14 10:18:54
  • C# 调用 JavaWebservice服务遇到的问题汇总

    2023-04-23 04:00:49
  • 一文带你搞懂Redis分布式锁

    2021-09-26 12:56:14
  • Java反射通过Getter方法获取对象VO的属性值过程解析

    2023-04-11 06:11:33
  • C++调试追踪class成员变量的方法

    2022-11-21 01:32:12
  • Android 字符串中某个字段可点击和设置颜色的方法

    2023-07-24 00:16:53
  • Springboot使用@Valid 和AOP做参数校验及日志输出问题

    2023-12-05 04:39:12
  • Java中的内存泄露问题和解决办法

    2022-05-12 20:02:35
  • 剑指Offer之Java算法习题精讲数组与字符串

    2021-05-24 19:21:45
  • asp之家 软件编程 m.aspxhome.com