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

ListView的下拉刷新和上拉加载

我们公司以前有道面试题,让开发人员当场写一个ListView的下拉刷新和上拉加载,时间2个小时左右,允许有微量Bug。自己想一想,也不知道能不能写的出来,所以今天有时间,参考了网上

我们公司以前有道面试题,让开发人员当场写一个ListView的下拉刷新和上拉加载,时间2个小时左右,允许有微量Bug。

自己想一想,也不知道能不能写的出来,所以今天有时间,参考了网上的一些资料,先写一个练手下。先看下效果图:

这里写图片描述这里写图片描述

实现原理

ListView有一个addHeaderView()和addFooterView()方法,就是添加一个头布局和一个脚布局。主要通过这两个方法来实现。

初始化的时候,添加头布局和脚布局。然后把头布局的paddingTop设置为负的头布局高度,这样头布局就会看不见了。脚布局同样处理。

在手指滑动的时候,不断的去改变paddingTop的值,这样,就形成下拉的效果了。

注意:对于ListView判断滑动到顶部和底部的监听

ListView自带一个setOnScrollListener()监听器,主要用来监听它的滑动时间的。

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
//空闲状态,停止滚动
break;
case OnScrollListener.SCROLL_STATE_FLING:
// 手指快速滚动
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
// 正在滚动
break;
}
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

}

调用方法

  • 直接引用PullToRefreshListView类到你的工程,copy布局文件。
  • 由于下拉刷新的头布局和上拉加载的布局是固定的,没有提供接口动态加载。所有如果要引用的话,得去修改xml文件。
  • 可以禁止下拉刷新或者上拉加载,通过setNeedPullToRefresh()和setNeedLoadMore()方法。
  • 每次刷新完毕,请调用refreshComplete()方法。
  • setOnRefreshListener()设置下拉和上拉的监听回调。
package com.geek.widget;

import java.text.SimpleDateFormat;
import java.util.Locale;

import com.zhou.customviewone.R;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
*
* 下拉刷新和上拉加载的ListView
*
* @author LeeShenzhou
*
*/

public class PullToRefreshListView extends ListView implements OnScrollListener {

// 头布局
private View mHeaderView;
private ImageView mImageArrow;
private ProgressBar mProgressBar;
private TextView mTxtState;
private TextView mTxtUpdateTime;

// 脚布局
private View mFooterView;

// 头布局的高度
private int headerHeight;

// 脚布局的高度
private int footerHeight;

private int mDownY;

// 下拉刷新
private final int DOWN_REFRESH = 0;
// 松开刷新
private final int RELEASE_REFRESH = 1;
// 正在刷新中
private final int REFRESHING = 2;

private int currentState = DOWN_REFRESH;

private boolean isLoadMore;

// 是否需要下拉刷新
private boolean isNeedPullToRefresh;
// 是否需要上拉加载更多
private boolean isNeedLoadMore;

/**
* 是否需要下拉刷新
*/

public void setNeedPullToRefresh(boolean need) {
this.isNeedPullToRefresh = need;
}

/**
* 是否需要上拉加载更多
*/

public void setNeedLoadMore(boolean need) {
this.isNeedLoadMore = need;
}

/**
* 刷新完成
*/

public void refreshComplete() {
isLoadMore = false;
currentState = DOWN_REFRESH;
mHeaderView.setPadding(0, -headerHeight, 0, 0);
mFooterView.setPadding(0, -footerHeight, 0, 0);
}

private OnRefreshListener listener;

public void setOnRefreshListener(OnRefreshListener listener) {
this.listener = listener;
}

public PullToRefreshListView(Context context) {
super(context);
init();
}

public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

private void init() {
isNeedLoadMore = true;
isNeedPullToRefresh = true;

isLoadMore = false;

// 初始化头布局
mHeaderView = View.inflate(getContext(), R.layout.layout_pull_to_refresh_header, null);
mImageArrow = (ImageView) mHeaderView.findViewById(R.id.header_image_arrow);
mProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.header_pb);
mTxtState = (TextView) mHeaderView.findViewById(R.id.header_state);
mTxtUpdateTime = (TextView) mHeaderView.findViewById(R.id.header_update_time);

mHeaderView.measure(0, 0); // 系统会帮我们测量出HeaderView的高度
headerHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -headerHeight, 0, 0);
addHeaderView(mHeaderView);

// 初始化脚布局
mFooterView = View.inflate(getContext(), R.layout.layout_pull_to_refresh_footer, null);
mFooterView.measure(0, 0);
footerHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -footerHeight, 0, 0);
addFooterView(mFooterView);

// 设置最后刷新时间
setLastUpdateTime();

setOnScrollListener(this);
}

private void setLastUpdateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
String time = sdf.format(System.currentTimeMillis());
if (mTxtUpdateTime != null) {
mTxtUpdateTime.setText("最新更新: " + time);
}
}

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!isNeedPullToRefresh) {
return super.onTouchEvent(ev);
}

switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownY = (int) ev.getY();
break;

case MotionEvent.ACTION_MOVE:
int moveY = (int) ev.getY();
final int offset = (moveY - mDownY) / 2;
int paddingTop = -headerHeight + offset;

if (getFirstVisiblePosition() == 0 && paddingTop > -headerHeight) {
if (currentState != REFRESHING) {
if (offset > headerHeight && currentState == DOWN_REFRESH) {
// 完全显示了
currentState = RELEASE_REFRESH;
changeHeaderView();
} else if (offset // 没有显示完全
currentState = DOWN_REFRESH;
changeHeaderView();
}
}

if (currentState == REFRESHING) {
mHeaderView.setPadding(0, offset, 0, 0);
} else {
mHeaderView.setPadding(0, paddingTop, 0, 0);
}
}
break;

case MotionEvent.ACTION_UP:
if (currentState == REFRESHING) {
mHeaderView.setPadding(0, 0, 0, 0);
setSelection(0);
return super.onTouchEvent(ev);
}

// 判断当前的状态是松开刷新还是下拉刷新
if (currentState == RELEASE_REFRESH) {
mHeaderView.setPadding(0, 0, 0, 0);
currentState = REFRESHING;
changeHeaderView();
setSelection(0);
if (listener != null) {
listener.onPullToRefresh();
}
} else if (currentState == DOWN_REFRESH) {
mHeaderView.setPadding(0, -headerHeight, 0, 0);
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}

private void changeHeaderView() {
switch (currentState) {
case DOWN_REFRESH:
// 下拉刷新
mTxtState.setText("下拉刷新");
mProgressBar.setVisibility(View.GONE);
mImageArrow.setVisibility(View.VISIBLE);
mImageArrow.setImageResource(R.drawable.arrow_down);
break;

case RELEASE_REFRESH:
// 松开刷新
mTxtState.setText("释放立即刷新");
mProgressBar.setVisibility(View.GONE);
mImageArrow.setVisibility(View.VISIBLE);
mImageArrow.setImageResource(R.drawable.arrow_pull);
break;

case REFRESHING:
// 正在刷新
mImageArrow.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mTxtState.setText("正在刷新...");
break;

default:
break;
}
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (!isNeedLoadMore || isLoadMore) {
return;
}
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
// 判断当前是否已经到了底部
if (getLastVisiblePosition() == (getCount() - 1)) {
isLoadMore = true;
mFooterView.setPadding(0, 0, 0, 0);
setSelection(getCount());
if (listener != null) {
listener.onLoadMore();
}
}
}
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem != 0) {
// 重置刷新状态
if (currentState != REFRESHING) {
currentState = DOWN_REFRESH;
}
}
}

public interface OnRefreshListener {

/**
* 下拉刷新
*/

void onPullToRefresh();

/**
* 上拉加载更多
*/

void onLoadMore();
}

}

源码下载:https://git.oschina.net/nszKnife/AndroidView


推荐阅读
  • java线程实现图片滚动_Android线程实现图片轮播
    一、实现效果本篇文章实现了简单的图片轮播,初始化3张资源图片,初始化3秒更换一次图片背景,轮换播放。二、知识点Thread线程start( ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 人脸检测 pyqt+opencv+dlib
    一、实验目标绘制PyQT界面,调用摄像头显示人脸信息。在界面中,用户通过点击不同的按键可以实现多种功能:打开和关闭摄像头, ... [详细]
  • 注:根据Qt小神童的视频教程改编概论:利用最新的Qt5.1.1在windows下开发的一个小的时钟程序,有指针与表盘。1.Qtforwindows开发环境最新的Qt已经集 ... [详细]
  • 请修改resxmldefault_workspace.xml文件,添加如下代码:    launcher:packageName完整的包名    launcher:cla ... [详细]
  • 使用PyQt5 for Python gui开发笔记:实现可滚动标签
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了使用PyQt5forPythongui的可滚动标签相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 我正在尝试创建一个在单击按钮时出现的表单。这是输出: ... [详细]
author-avatar
24吴梦琦_581
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有