热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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  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:

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
   
 

pull_to_refresh_header.xml:

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
   
   
     
     
   
 

activity_main.xml:

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
        
       
 

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


推荐阅读
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
author-avatar
溪边莎草
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有