android pulldown view,Android控件PullRefreshViewGroup实现下拉刷新和上拉加载
本文实例为大家分享了Android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下
先分享下源码:Android实现下拉刷新和上拉加载更多
实现思路:由PullRefreshViewGroup控件来接管标准控件(比如RecyclerView、ListView等)的滑动,调用标准控件的内部方法进行短距离滑动,不再由标准控件自己来处理事件,而完全由PullRefreshViewGroup控件来处理触摸事件。标准控件内部的滑动距离等属性,通过反射获得computeVerticalScrollExtent、computeVerticalScrollRange、computeVerticalScrollOffset这三个方法来获得。
PullRefreshViewGroup控件的布局如下
部分代码实现
触摸滑动事件处理
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean bret = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mPreY = ev.getY();
Log.d(TAG, "mPreY:" + String.valueOf(mPreY));
}
break;
case MotionEvent.ACTION_MOVE: {
float curY = ev.getY();
float distance = curY - mPreY;
if (Math.abs(distance) >= mTouchSlop) {
mSliding = bret = true;
//修正第一次滑动的卡顿
if (distance > 0) {
mPreY += mTouchSlop;
} else {
mPreY -= mTouchSlop;
}
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
} else {
mSliding = bret = false;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
bret = mSliding;
}
break;
}
return bret ? true : super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean bret = false;
vTracker.addMovement(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mPreY = event.getY();
bret = true;
}
break;
case MotionEvent.ACTION_MOVE: {
float curY = event.getY();
float distance = curY - mPreY;
Log.d(TAG, "mPreY:" + String.valueOf(mPreY) + " distance:" + String.valueOf(distance));
if (distance != 0) {
bret = true;
if (mSrcHeightHead == -1 && mHasPullRefresh) {
View child0View = mHeadView;
mSrcHeightHead = child0View.getHeight();
}
scrollBy(distance);
}
mPreY = curY;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
mPreCurY = 0;
View child0View = mHeadView;
int child0Height = null != child0View ? child0View.getHeight() : 0;
int child0Height2 = null != child0View ? child0View.getLayoutParams().height : 0; //视图的最终高度是有这个来决定的,请看onMeasure 函数的实现
// int child0Height3 = child0View.getMeasuredHeight();
if (child0Height2 != child0Height) {
child0Height = child0Height2;
}
int child0Top = null != child0View ? child0View.getTop() : 0;
int dy = child0Height - mSrcHeightHead + (mSrcHeightHead - Math.abs(child0Top));
Log.d(TAG, "onTouchEvent()ACTION_UP child0Height:" + String.valueOf(child0Height) + " mSrcHeightHead:" + String.valueOf(mSrcHeightHead) + " child0Top:" + String.valueOf(child0Top));
if (dy > 0) {//恢复拉伸视图的位置
if (!mLoadingMore && dy > mCanRefreshHeight && child0Top + child0Height2 > mCanRefreshHeight && mRefreshLoad != null) {
dy -= mCanRefreshHeight;
if (!mPullRefreshLoading) {
mPullRefreshLoading = true;
mTvRefreshInfo.setText("正在加载...");
mRefreshLoad.pullRefreshStartLoad();
}
}
mScroller.startScroll(0, 0, 0, -dy);
invalidate();
} else {
vTracker.computeCurrentVelocity(1000);
float yvel = vTracker.getYVelocity();
if (yvel != 0) {//为了满足内部视图的快速滚动( 中间内容视图 )
mScroller.fling(0, 0, 0, (int) yvel, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
invalidate();
}
}
vTracker.clear();
bret = true;
}
break;
}
return bret ? true : super.onTouchEvent(event);
}
小距离滑动代码
private void scrollBy(float distance) {
View child0View = mHeadView;
View child1View = getChildAt(null == mHeadView ? 0 : 1);
float distanceRemain = 0;
int child0Top = null != child0View ? child0View.getTop() : 0;
// int child0Height = child0View.getHeight();
if (distance < 0) {//向上
int child1Top = child1View.getTop();
// int child1Height = child1View.getHeight();
//child0View 缩小
if (-1 != mSrcHeightHead && null != child0View && child0View.getHeight() > mSrcHeightHead) {
float off = distance;
if (child0View.getHeight() + distance < mSrcHeightHead) {
off = -(child0View.getHeight() - mSrcHeightHead);
distance -= off;
} else {
distance = 0;
}
child0View.getLayoutParams().height += (int) off;
child1Top += (int) off; //child0view 缩小的同时, child1view 的高度也会随之上升 这里很重要
requestLayout();
child1View.offsetTopAndBottom((int) off);
if (null != mTailView) {
mTailView.offsetTopAndBottom((int) off);
}
}
if (distance != 0) {
if (child0Top + mSrcHeightHead + distance <= 0) {
distanceRemain = -(distance + (child0Top + mSrcHeightHead));//正数
distance = -(child0Top + mSrcHeightHead);//负数
}
//可以显示加载更多吗?
boolean bDirectDown = false;
boolean bCanScroll = child1View.canScrollVertically(1) || child1View.canScrollVertically(-1);
if (!bCanScroll) {
int child1ChildCount = 0;
if (child1View instanceof ViewGroup) {
child1ChildCount = ((ViewGroup) child1View).getChildCount();
}
if (child1ChildCount > 0) {
ViewGroup viewGroupChild1 = (ViewGroup) child1View;
View child1LastItem = viewGroupChild1.getChildAt(child1ChildCount - 1);
int child1ViewBottom = viewGroupChild1.getBottom();
int child1LastItemBottom = child1LastItem.getBottom() + child1Top; //相对于 ImageScaleViewGroup 的位置
//增加 child1ViewBottom > getHeight() 来控制 ScrollView
if (child1LastItemBottom == getHeight()) {
bDirectDown = true;
}
}
}
//正在下拉刷新的时候,不能显示加载更多
if ((bCanScroll || bDirectDown) && null != mTailView && !mPullRefreshLoading) {
int nVerticalScrollExtent = 0, nVerticalScrollRange = 0, nVerticalScrollOffset = 0;
Class c = null;
try {
c = Class.forName(child1View.getClass().getName());
} catch (Exception ex) {
}
try {
if (null == mComputeVerticalScrollExtent) {
Method computeVerticalScrollExtent = findcomputeVerticalMethod(c, "computeVerticalScrollExtent");
computeVerticalScrollExtent.setAccessible(true);
mComputeVerticalScrollExtent = computeVerticalScrollExtent;
}
nVerticalScrollExtent = (int) mComputeVerticalScrollExtent.invoke(child1View);
} catch (Exception ex) {
}
try {
if (null == mComputeVerticalScrollRange) {
Method computeVerticalScrollRange = findcomputeVerticalMethod(c, "computeVerticalScrollRange");
computeVerticalScrollRange.setAccessible(true);
mComputeVerticalScrollRange = computeVerticalScrollRange;
}
nVerticalScrollRange = (int) mComputeVerticalScrollRange.invoke(child1View);
} catch (Exception ex) {
}
try {
if (null == mComputeVerticalScrollOffset) {
Method computeVerticalScrollOffset = findcomputeVerticalMethod(c, "computeVerticalScrollOffset");
computeVerticalScrollOffset.setAccessible(true);
mComputeVerticalScrollOffset = computeVerticalScrollOffset;
}
nVerticalScrollOffset = (int) mComputeVerticalScrollOffset.invoke(child1View);
} catch (Exception ex) {
}
int range = nVerticalScrollRange - nVerticalScrollExtent;
if (nVerticalScrollOffset + distanceRemain > range) {
float nOff = distanceRemain - (range - nVerticalScrollOffset);
distanceRemain = range - nVerticalScrollOffset;
distance -= nOff;
}
int child3Bottom = mTailView.getBottom();
if (child3Bottom + distance < getHeight()) {
distance = getHeight() - child3Bottom;
}
}
if (!bCanScroll) {
distanceRemain = 0;
}
}
} else {//向下
int nScrollOffset = 0;
try {
Class c = Class.forName(child1View.getClass().getName());
Method computeVerticalScrollOffset = findcomputeVerticalMethod(c, "computeVerticalScrollOffset");//c.getDeclaredMethod("computeVerticalScrollOffset");
computeVerticalScrollOffset.setAccessible(true);
nScrollOffset = (int) computeVerticalScrollOffset.invoke(child1View);
} catch (Exception ex) {
}
int child2Top = null != mTailView ? mTailView.getTop() : getHeight();//注意默认值
if (child2Top < getHeight()) {
if (child2Top + distance > getHeight()) {
distanceRemain = distance - (getHeight() - child2Top);
distance = getHeight() - child2Top;
}
} else if (nScrollOffset > 0) {//内部有滚动,那么就要计算内部滚动距离,其他分配给整体滚动
if (nScrollOffset - distance <= 0) {
distanceRemain = -nScrollOffset;
// distance = distance - nScrollOffset;
distance = 0; //内部能滚动,不让外部去滚动
if (!mScroller.isFinished()) {
mScroller.abortAnimation(); //内部滚动完后,立即停止
}
} else {
distanceRemain = -distance;//负数
distance = 0;
}
} else {
if (child0Top + distance > 0) {//child0放大,child1移动
int off = (int) (child0Top + distance);
distance = -child0Top;
if (null != child0View) {
child0View.getLayoutParams().height += off;
requestLayout();
} else {
off = 0;
}
child1View.offsetTopAndBottom(off);
if (null != mTailView) {
mTailView.offsetTopAndBottom(off);
}
}
}
}
if (0 != (int) distance) {
if (null != child0View) {
child0View.offsetTopAndBottom((int) distance);
}
child1View.offsetTopAndBottom((int) distance);
if (null != mTailView) {
mTailView.offsetTopAndBottom((int) distance);
}
requestLayout();//奇酷360这里必须调用, 否则显示有点问题
}
scrollByForMidView(distanceRemain);//外部无法滚动的时候,内部滚动
if (!mPullRefreshLoading && !mLoadingMore) {
int tailviewTop = null != mTailView ? mTailView.getTop() : getHeight();//注意默认值
if (tailviewTop < getHeight() && mHasLoadMore) {//加载更多
mLoadingMore = true;
if (mRefreshLoad != null) {
mRefreshLoad.pullUpStartLoadMore();
}
} else {
if (mHasPullRefresh) {
if (distance < 0) {
int child0Bottom = child0View.getBottom();
if (child0Bottom < mCanRefreshHeight) {
mTvRefreshInfo.setText("下拉刷新");
}
} else {
int child0Bottom = child0View.getBottom();
if (child0Bottom > mCanRefreshHeight) {
mTvRefreshInfo.setText("松开刷新");
}
}
}
}
}
}
处理标准控件小距离滚动代码,这里ListView有点特殊。
private void scrollByForMidView(float distanceRemain) {
if (0 != (int) distanceRemain) {
View child1View = getChildAt(null == mHeadView ? 0 : 1);
if (child1View instanceof ListView) {
((ListView) child1View).smoothScrollBy((int) distanceRemain, 0);
} /*else if (child1View instanceof ScrollView){
((ScrollView) child1View).smoothScrollBy(0,(int) distanceRemain);
}*/ else {
child1View.scrollBy(0, (int) distanceRemain);
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
android pulldown view,Android控件PullRefreshViewGroup实现下拉刷新和上拉加载相关推荐
- android--------自定义控件ListView实现下拉刷新和上拉加载
开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...
- Android下拉刷新和上拉加载更多
Android下拉刷新和上拉加载更多 下拉刷新 通过android系统提供的组件:SwipeRefreshLayout 一.基本使用 1 xml中 添加 SwipeRefreshLayout 组件 该 ...
- android 官方上拉,手把手教你实现RecyclerView的下拉刷新和上拉加载更多
纵观多数App,下拉刷新和上拉加载更多是很常见的功能,但是谷歌官方只有一个SwipeRefreshLayout用来下拉刷新,上拉加载更多还要自己做. 基于RecyclerView简单封装了这两个操作, ...
- android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...
转载:http://blog.csdn.net/xiabing082/article/details/48781489 1. 大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...
- android自定义控件几种,Android 自定义View一个控件搞定多种水波纹涟漪扩散效果 - CSDN博客...
效果图 实现思路 这个效果实现起来并不难,重要的是思路 此View满足了多种水波纹涟漪扩散效果,这要求它能满足很多的变化 根据上面的样式,可以看出此View需要满足以下变化 圆圈从中心可循环向外扩散 ...
- android下拉刷新和上拉加载的一个简单库
介绍一个android下拉刷新.上拉加载的库: https://github.com/chrisbanes/Android-PullToRefresh 使用方式,创建好一个Android项目,导入li ...
- C# 系统应用之TreeView控件 (一).显示树状磁盘文件目录及加载图标
在C#系统应用毕设U盘防御软件中需要实现文件不可恢复的删除,首先需要实现类似于资源管理器的界面,通过TreeView控件显示"我的电脑"所有磁盘文件树状目录并加载相应图标.显示结果 ...
- NTKO OFFICE控件手动安装, 解决IE浏览器无法加载 Activex 控件的解决办法
NTKO OFFICE控件手动安装 在安装ntko之前先要查看本地ie浏览器的版本,1.如果是ie9及ie9以上的浏览器,可以直接参考下面的办法,2.如果是ie8的话那就要先找到本地32位的浏览器,在 ...
- element tree ui 全选_element UI tree 控件,点击父节点进行异步加载,异步加载的数据不能全选...
异步加载不能有多级数据,异步的只能一级级加载 贴上我的代码 html :load="loadNode" node-key='id' lazy ref="tree" ...
最新文章
- linux 普通用户 mysql_Linux普通用户部署mysql
- (十二)struts2的类型转换
- 记一次前端问题解决历程(Cannot read Property ‘call‘ of undefined)
- c#判断输入textbox是否为数字
- 上海市提出IDC建设指导意见,新建IDC限制PUE1.3以下
- 100. 相同的树 golang
- float js 正则 验证_爬虫篇 | 200 行代码实现一个滑动验证码
- Java 1.7 ThreadPoolExecutor源码解析
- 程序局部性(时间局部性与空间局部性)与循环展开原理详解
- 凸优化-Proximal GD
- 装机员Ghost一键备份还原使用方法(硬盘装系统)
- 个人投资者金融期货开户的条件
- 花花嬉游团的千岛湖懒人游~~
- Git:Terminal is dumb, but EDITOR unset
- 计算机辅助测试图示,计算机基础知识:计算机辅助测试
- Halcon找圆系列(4)测量圆直径/半径的方法之暴力拟合法 vs 测量工具法
- 弹性盒子 -- flex
- Creating orkut style status update div-textbox using jQuery
- Android BLE 蓝牙开发指南(三)外围设备端开发详解
- php生成ods文件,odsPhpGenerator