Android下拉刷新

2023-11-04

app开发中下拉刷新是最常接触到的一个功能,也有很多开源的框架,封装的非常棒。前段时间了解了一下ViewDragHelper,遂用它实现了下拉刷新的功能。

大概和我之前的ViewDragHelper之拖动加载(类似淘宝)这篇代码类似。只是做了相关改动。具体的可以看一下那篇博文了解一下用到的ViewDragHelper的一些知识点。该界面主要是一个LinearLayout,上面的下拉刷新是一个textview(用TV代替),当然这个可以定制,在此只是用一个textview代替,实现简单的功能,下面是一个listview(用LV代替),当然listview也是可以定制的,可以使gridview或者其他你想要的都可以,在此也是只用Listview代替。大概的讲讲吧:

首先,在onLayout中将TV置于屏幕上方,将LV充满屏幕;


上图中蓝色部分是整个手机的屏幕,红色部分是下拉提示TV。TV是置于屏幕之外的是不显示的。

@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		if (pullText.getTop() == 0) {
			viewHeight = pullText.getMeasuredHeight();
			pullText.layout(l, 0, r, b);
			myList.layout(l, 0, r, b);
			pullText.offsetTopAndBottom(-viewHeight);
		} else {
			pullText.layout(l, pullText.getTop(), r, pullText.getBottom());
			myList.layout(l, myList.getTop(), r, myList.getBottom());
		}
	}
上面的代码段中,pullText即是TV,myList是LV。这样在下拉LV的时候,TV就会跟着往下走,所以就会出现在屏幕中实现我们想要的效果。
<pre name="code" class="java">	/**
	 * 这是拖拽效果的主要逻辑
	 */
	private class DragHelperCallback extends ViewDragHelper.Callback {

		@Override
		public void onViewPositionChanged(View changedView, int left, int top,
				int dx, int dy) {
			int childIndex = 1;
			if (changedView == myList) {
				childIndex = 2;
			}
			onViewPosChanged(childIndex, top);
		}

		@Override
		public boolean tryCaptureView(View child, int pointerId) {
			return true;
		}

		@Override
		public int getViewVerticalDragRange(View child) {
			return 1;
		}

		@Override
		public void onViewReleased(View releasedChild, float xvel, float yvel) {
			refreshOrNot(releasedChild, yvel);
		}

		@Override
		public int clampViewPositionVertical(View child, int top, int dy) {
			int finalTop = top;
			if (child == pullText) {
				if (top > 0) {
					finalTop = 0;
				}
			} else if (child == myList) {
				if (top < 0) {
					finalTop = 0;
				}
				if(top >= viewHeight){
					pullText.setText("松开刷新");
				}else{
					pullText.setText("下拉刷新");
				}
			}
			return child.getTop() + (finalTop - child.getTop()) / 2;
		}
	}

  上面的代码段中,主要是在clampViewPositionVertical中判断滑动的位置,作用的子view。其他就不多说了,大致和之前的博客相同。主要说说onViewReleased吧。在此函数中是在用户手势抬起时响应的,所以我们在此实现下拉后的刷新。我们先定义一个接口,以便在刷新的时候调用。 

public interface pulltorefreshNotifier {
		public void onPull();
	}
public void setpulltorefreshNotifier(pulltorefreshNotifier pullNotifier) {
		this.pullNotifier = pullNotifier;
	}
private void refreshOrNot(View releasedChild, float yvel) {
		int finalTop = 0;
		if (releasedChild == pullText) {
			// 拖动第一个view松手
			if (yvel < -50) {
				finalTop = 0;
			} else {
				finalTop = viewHeight;
			}
		} else {
			// 拖动第二个view松手
			if (yvel > viewHeight - 5 || releasedChild.getTop() >= viewHeight) {
				finalTop = viewHeight;
				if (null != pullNotifier) {
					pullNotifier.onPull();
				}
				pullText.setText("正在刷新");
			}
		}

		if (VDH.smoothSlideViewTo(myList, 0, finalTop)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}
拖动第二个view时,也就是LV时,我们判断一下是否需要刷新,需要刷新则执行onPull();

然后我们来看一下主要的Activity:

package com.maxi.pulltorefreshtest;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.maxi.pulltorefreshtest.adapter.ProjectAdapter;
import com.maxi.pulltorefreshtest.widget.MyListView;
import com.maxi.pulltorefreshtest.widget.PullToRefreshGroup;
import com.maxi.pulltorefreshtest.widget.PullToRefreshGroup.pulltorefreshNotifier;

public class MainActivity extends Activity {
	private PullToRefreshGroup pullListgroup;
	private boolean isDown = false;
	private MyListView myList;
	private ProjectAdapter pa;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findView();
		init();
	}

	private void findView() {
		pullListgroup = (PullToRefreshGroup) findViewById(R.id.pulltorefresh);
		myList = pullListgroup.returnMylist();
	}

	private void init() {
		pulltorefreshNotifier pullNotifier = new pulltorefreshNotifier() {
			@Override
			public void onPull() {
				// TODO Auto-generated method stub
				downLoad();
			}
		};
		pullListgroup.setpulltorefreshNotifier(pullNotifier);
		pa = new ProjectAdapter(this);
		myList.setAdapter(pa);
		pa.notifyDataSetChanged();
	}

	private void downLoad() {
		if (!isDown) {
			isDown = true;
			new Thread(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					try {
						Thread.sleep(2000);
						handler.sendEmptyMessage(1);
					} catch (InterruptedException e) {
//						 TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start();
		}
	}

	@SuppressLint("HandlerLeak")
	private Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			super.handleMessage(msg);
			switch (msg.what) {
			case 1:
				pullListgroup.refreshComplete();
				isDown = false;
				break;
			default:
				break;
			}
		}

	};
}
我们在他刷新的时候执行downLoad();刷新数据。为了达到效果可以看出我让线程暂停2s。然后调用refreshComplete();
	public void refreshComplete() {
		if (VDH.smoothSlideViewTo(myList, 0, 0)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}
实现刷新好后让TV继续返回屏幕上方。

上段代码中我们发现MyListView是重写的ListView,主要是处理手势事件的。

package com.maxi.pulltorefreshtest.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;

public class MyListView extends ListView {
	boolean allowDragBottom = true; 
	float downY = 0;
	boolean needConsumeTouch = true; 
	public MyListView(Context context){
		super(context);
	}
	public MyListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		if (ev.getAction() == MotionEvent.ACTION_DOWN) {
			downY = ev.getRawY();
			needConsumeTouch = true;
			if (getMyScrollY() == 0) {
				allowDragBottom = true;
			} else {
				allowDragBottom = false;
			}
		} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
			if (!needConsumeTouch) {
				getParent().requestDisallowInterceptTouchEvent(false);
				return false;
			} else if (allowDragBottom) {
				if (downY - ev.getRawY() < -2) {
					needConsumeTouch = false;
					getParent().requestDisallowInterceptTouchEvent(false);
					return false;
				}
			}
		}
		getParent().requestDisallowInterceptTouchEvent(needConsumeTouch);
		return super.dispatchTouchEvent(ev);
	}

	public int getMyScrollY() {
		View c = getChildAt(0);
		if (c == null) {
			return 0;
		}
		int firstVisiblePosition = getFirstVisiblePosition();
		int top = c.getTop();
		return -top + firstVisiblePosition * c.getHeight();
	}
}
ok。先这样吧。像上拉加载更多,我感觉也可以这么实现。有时间试试吧,大家有时间也可以动动手试试。

好吧。大致就这些,有疑问或建议请留言,共同进步,谢谢!

项目中使用参考:Android聊天界面搭建

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android下拉刷新 的相关文章

  • 如何使用 kotlin Android 从 Url 读取 JSON?

    我正在使用 kotlin 来开发应用程序 现在我想从服务器获取 JSON 数据 在java中 我实现了Asyntask以及Rxjava来从Url读取JSON 我也在谷歌搜索 但我无法获得满足我的要求的正确详细信息 如何使用 kotlin 从
  • 视图无法解析为类型

    这里的视图似乎有什么问题 我该如何解决它 错误 视图无法解析为类型 public void onItemClick AdapterView
  • 如何使 FirebaseAuth.AuthStateListener 在 Kotlin 中工作?

    class LoginActivity AppCompatActivity private val firebaseAuth FirebaseAuth getInstance private val firebaseAuthListener
  • 通过意图使用多个电话号码添加新联系人

    我想使用添加新联系人ContactsContract Intents Insert 但问题是我不知道可以有多少个电话号码 据我了解 我只能使用三个电话号码PHONE SECONDARY PHONE TERTIARY PHONE常数 有什么办
  • 如何实现 ALTER TABLE 的示例[重复]

    这个问题在这里已经有答案了 我已经多次问过这个问题 但尚未得到完整的答案 如何实现 ALTER TABLE 语句以向数据库添加列 有人可以给我举个例子吗 请阅读SQLite ALTER TABLE 参考 http sqlite org la
  • 如何调试“com.android.okhttp”

    在android kitkat中 URLConnection的实现已经被OkHttp取代 如何调试呢 OkHttp 位于此目录中 external okhttp android main java com squareup okhttp 当
  • Android studio - 如何保存先前活动中选择的数据

    这是我的代码片段 这Textview充当按钮并具有Onclicklistner在他们 当cpu1000时Textview单击它会导致cpu g1000其代码如下所示的类 public class Game 1000 extends AppC
  • SQLite FTS4 使用特殊字符进行搜索

    我有一个 Android 应用程序 它使用 FTS4 虚拟表在 SQLite 数据库中搜索数据 它工作正常 但是当表中的数据包含特殊字符 如 或 时 SQLite MATCH 函数不会给出任何结果 我现在迷路了 谢谢 注意 默认的分词器真的
  • 在 android studio 中找不到 SDK 位置

    我刚刚在 android studio 中导入了我的 eclipse 项目 我一直这么说 Error SDK location not found Define location with sdk dir in the local prop
  • 警报对话框中的 Webview 不显示内容

    我正在开发一个 Android 应用程序 我需要在网络视图和警报对话框上显示一个网站 该站点显示在网络视图中 但不显示在警报对话框中 到目前为止 这是我的代码 WebView WebView myWebView WebView v find
  • 表面视图+gl表面视图+框架布局

    我是 java 和 OpenGL 的新手 我正在尝试获得一个相机预览屏幕 能够 同时显示 3D 对象 浏览完样本后 api 演示 我想结合示例的代码 api 演示就足够了 但不知何故它不起作用 迫使我 启动时关闭 错误被称为空指针 例外 有
  • Android:canvas.drawBitmap() 方法无法正常工作

    我已经发布了两个与此相关的问题 请参考此自定义饼图 1 https stackoverflow com questions 28343600 customize pie chart in quarter shape at the botto
  • react-native android fontFamily 不生效

    问题一 我在index android js的欢迎样式中添加了fontFamily 但没有效果 fontFamily 真的可以在 Android 上使用吗 欢迎 字体大小 20 fontFamily roboto thin 文本对齐 居中
  • 在android中从SD卡上传图像到facebook

    我无法从 SD 卡上传 Facebook 上的图像 我使用了下面的代码 但它没有给我错误 但同时它没有上传图像 byte data null try FileInputStream fis new FileInputStream filep
  • android系统用户和linux root用户有什么区别

    当我将手机连接到电脑并使用adb shell与我的手机通信并输入的命令ps命令输出当前在我的手机上运行的进程信息 我发现有两个特殊用户 一个是root 另一个是system 据我所知 Android是基于linux的 所以root用户是最大
  • JetPack Compose - 卡中行中的weight() 不起作用

    创建 Android 应用程序时 我将一些可组合项放在卡片的一行中 如下所示 但它没有按我的预期工作 我添加 weight 1f 的可组合项不再显示 data class Test val title String val text Str
  • 如何在android中安装和使用couch db

    我应该如何在 android 中安装和使用 couch Db 我的意思是本地沙发数据库 我可以在平板电脑和模拟器中使用它 为此我必须遵循哪些步骤 我目前正在开发一个使用它的项目 有两种选择 1 couchbase android 是的 co
  • Android View Canvas onDraw 未执行

    我目前正在开发一个自定义视图 它在画布上绘制一些图块 这些图块是从多个文件加载的 并将在需要时加载 它们将由 AsyncTask 加载 如果它们已经加载 它们只会被绘制在画布上 这工作正常 如果加载了这些图片 AsyncTask 就会触发v
  • 在线性布局内的 ScrollView 内并排对齐 TextView

    我有一个带有滚动视图的线性布局 我想保留它的当前格式 但只需将 textView2a 和 textView3a 并排放置 而不会破坏我当前的布局格式 我已经包含了我最近的尝试 但它们似乎不正确 提前致谢 Java菜鸟 当前有效的 XML
  • Keystore getEntry 在 Android 9 上返回 NULL

    c我已对存储在 Android 密钥库中的登录密码进行了加密和解密 在 Android 9 上 我观察到应用程序在尝试解密密码时崩溃 我无法重现它 但拥有 Pixel 3 的用户是崩溃的设备之一 下面是我如何从密钥库解密密码 private

随机推荐

  • 如何在 Debian 9 上设置 OpenVPN 服务器

    无论您是想在连接不可信的公共 Wi Fi 网络时安全可靠地访问互联网 绕过地理限制内容还是允许您的同事在远程工作时安全地连接到您的公司网络 使用 VPN 都是最佳解决方案 VPN 允许您连接到远程 VPN 服务器 使您的连接加密且安全 并通
  • 如何使用 Linux 命令行删除文件和目录

    本教程将向您展示如何使用rm unlink and rmdirLinux 中删除文件和目录的命令 如何删除文件 要从命令行删除 或删除 Linux 中的文件 请使用rm 删除 或unlink命令 The unlink命令允许您仅删除单个文件
  • Linux 中的 id 命令

    id是一个命令行实用程序 可以打印真实有效的用户和组 ID 使用id命令 语法为id命令如下 id OPTIONS USERNAME 如果省略用户名 则id命令显示有关当前登录用户的信息 当没有任何选项调用时 id打印真实用户 ID uid
  • 如何在 Debian 9 上安装 Elasticsearch

    Elasticsearch 是一个开源分布式全文搜索和分析引擎 它支持 RESTful 操作 允许您实时存储 搜索和分析大量数据 Elasticsearch 是最流行的搜索引擎之一 为具有复杂搜索要求的应用程序 例如大型电子商务商店和分析应
  • 如何在 Debian 9 上安装 PostgreSQL

    PostgreSQL 通常简称为 Postgres 是一个开源通用对象关系数据库管理系统 PostgreSQL 拥有许多高级功能 例如在线备份 时间点恢复 嵌套事务 SQL 和 JSON 查询 多版本并发控制 MVCC 异步复制等 在本教程
  • 如何在Linux中创建用户(useradd命令)

    Linux 是一个多用户系统 这意味着多个人可以同时与同一个系统交互 作为系统管理员 您有责任通过创建和管理系统的用户和组来管理系统的用户和组 删除用户并将它们分配给不同的groups 在本文中 我们将讨论如何使用创建新用户帐户userad
  • python采集信息+Python预处理+tableau绘制可视化大屏

    制作完成的效果 注 这个图绘制的右上角违和感较高 所以各位小伙伴绘制时要注意不要使用这种大块的图形 绘制一些可以设置背景色为透明的哪一种 最后一张图的话设计的是1920 1080的大小 太大了 所以录制的时候并没有完全录制上 现在制作可视化
  • WXML:微信小程序版HTML

    完整微信小程序 Java后端 技术贴目录清单页面 必看 WXML WeiXin Markup Language 是框架设计的一套标签语言 结合基础组件 事件系统 可以构建出页面的结构 3 7 1 标签与属性 常用基础标签text view
  • 微前端:一种的前端架构新思路

    在当今的Web开发世界 前端架构正在经历一场革命 随着应用程序的规模和复杂性日益增长 一个新的概念被引入 那就是 微前端 微前端架构为前端开发提供了新的思路和解决方案 使得团队能够更有效地构建大型Web应用 那么 什么是微前端呢 简单来说
  • 什么是SD-WAN?图文详解五大技术点

    目录 什么是SD WAN 为什么需要SD WAN 1 更快 规划最优路线 降低网络延时 2 更稳 绕开拥塞线路 避免抖动丢包 SD WAN 为极速远程而生 庞大机房节点数量决定扎实基建 千万终端实时探测网络质量 智能路线优化 高速数据包转发
  • SQLite 基础

    SQLite 为什么使用SQLite SQLite 命令 SQLite 安装 SQLite 命令 SQLite 语法 SQLite 语句 SQLite 数据类型 SQLite 特殊运算符 SQLite SQL 高级用法 SQLite PRA
  • UPF_iso cell 替换

    目标 使用stdand cell替换isolation cell 在低功耗SOC中 难免会有signal从掉电阈传输到未掉电阈 两个阈的电压相同 这个时候就需要用ISO cell做隔离 但在一些大工艺的cell中 是没有这种cell的 在这
  • ReactNative中js与原生如何交互

    第一部分 在ReactNative中 原生与js交互常用的是原生通过向js发送事件 参考webview源代码 1 定义事件与发送消息方法 public class ReactExpandListViewEvent extends Event
  • flash player_Flash Player的两种开源替代品

    flash player 2017年7月 Adobe敲响了其Flash Media Player的丧钟 宣布它将在2020年终止对曾经无处不在的在线视频播放器的支持 但是 实际上 Flash在过去八年中一直处于下滑状态破坏其声誉的零时差攻击
  • Docker----Docker容器的启动流程

    详细内容见 DevOps技术社区文章 Docker Docker容器的启动流程
  • new Option("文本","值",true,true).后面两个true分别表示默认被选中和有效!

    var url city cityList json post url parentCityCode code function data var jsonObj JSON parse data areaId append
  • 线程优先级设置

    线程测试需要root用户 不然创建不成功 所以要用sudo su命令 Linux内核的三种调度策略 1 SCHED OTHER 分时调度策略 2 SCHED FIFO 实时调度策略 先到先服务 一旦占用cpu则一直运行 一直运行直到有更高优
  • ad导入candence 更改pin引脚长度

    前言 很多时候我们使用的封装 可能是不完整的 引脚长度也不一样 原理图连接的时候就发现连接不上线 明显没对齐grid 1 右键edit pin 更改第一个引脚为short 然后下拉那个小点完成对目标覆盖 2 确认之后 再重新选择为line
  • 力扣刷题-56 - I. 数组中数字出现的次数、位运算的应用

    一个整型数组 nums 里除两个数字之外 其他数字都出现了两次 请写程序找出这两个只出现一次的数字 要求时间复杂度是O n 空间复杂度是O 1 c 位运算 位运算 计算机中是用二进制存储数据 一个字节包含8个位 每个 1 或者 0 就是一位
  • Android下拉刷新

    app开发中下拉刷新是最常接触到的一个功能 也有很多开源的框架 封装的非常棒 前段时间了解了一下ViewDragHelper 遂用它实现了下拉刷新的功能 大概和我之前的ViewDragHelper之拖动加载 类似淘宝 这篇代码类似 只是做了