Android scrollToTop实现点击回到顶部(兼容PullTorefreshScrollview)

前言

最近因为项目组需求,特研究了一下“回到顶部”效果,即:页面里有scrollview,内容很多,当滑动到页面下面或者更深时,需要回到顶部,即可点击出现的按钮,省得回滑N久。我没有搜,或许网上有很多这样的例子,此文写的不好的地方,望指点。

效果图如下

实现方法

初一看是不是觉得很简答?没错,当时我也是这样想的页面内容很长,就弄个scrollview,回到顶部按钮需要固定在右下角,故大概的布局代码:

<?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:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.znke.pulltorefresh_top.MainActivity"> <!--<com.znke.pulltorefresh_top.tool.ToTopScrollView .../>--> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/tv_top" android:scrollbars="none"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:text="111111111111" android:textSize="20sp" /> ........... <View android:layout_width="match_parent" android:layout_height="2dp" android:background="#AAAAAA" /> <TextView android:layout_width="match_parent" android:layout_height="80dp" android:gravity="center" android:text="12000000000000" android:textSize="20sp" /> </LinearLayout> </ScrollView> <com.znke.pulltorefresh_top.tool.ToTopImageView android:id="@+id/imageView_to_top" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="5dp" android:layout_marginRight="5dp" android:background="@drawable/to_top" /> </RelativeLayout>

然后在activity中设置下面事件不就完了嘛!!!

mScrollView.setOnScrollChangeListener();

很遗憾,报错。alt+enter搞定错误不就完了嘛!很遗憾,运行继续报错,报空指针,神奇吧,找不出来。翻阅资料后发现,scrollview的onScrollChanged方法是受保护的。故按照网上的资料,自定义ScrollView类,暴露出onScrollChanged方法:

public class ToTopScrollView extends ScrollView { private OnMyScrollListener onMyScrollListener; public void setOnMyScrollListener(OnMyScrollListener onMyScrollListener) { this.onMyScrollListener = onMyScrollListener; } ... @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if(onMyScrollListener != null) onMyScrollListener.onScrollChanged(l,t,oldl,oldt); } public interface OnMyScrollListener{ void onScrollChanged(int x, int y, int oldx, int oldy); } }

然后在activity中设置setOnMyScrollListener()方法,就可以监控scrollview的状态了。剩下的就是自定义imageview的逻辑了。

可是,自定义ToTopImageView里面怎么弄呢?它需要有一个高度临界值,与activity传递scrollview的scrollY值比较,来判定ToTopImageView是否显示。代码简单,搞定。

只是这样有个小问题,onScrollChanged方法是监控滚动状态的,没有说停止。如果在里面判断超过临界值就显示与隐藏imageview,那么会一直设置imageview。这样肯定不是最佳的方法。如果能在滚动停止时再判定是否需要显示与隐藏imageview就好了。此时我还没有想太多,动手简单实现了刚才的分析。

实现后,感觉挺爽。然而在准备加到项目中时发现,我们项目用了PullToRefresh刷新代码库,也简单,把自定义的Scrollview替换就可以了。运行,糟糕,没有效果,然后调试,事件没有处罚,可能是PullToRefresh库把事件屏蔽了,咋办?找onTouchListener监听方法呗。

于是改用了测试:

mScrollView.setOnTouchListener()

我去,没有调佣,把pullToRefreshScrollView里面各种监听方法都试遍了,没用。他只提供了顶部和底部的上拉、下拉刷新监听,毛用。

于是查看其源码,发现把事件拦截了。而且pullToRefreshScrollView根本就不是scrollview,看源码:

@Override protected ScrollView createRefreshableView(Context context, AttributeSet attrs) { ScrollView scrollView; if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { scrollView = new InternalScrollViewSDK9(context, attrs); } else { scrollView = new ScrollView(context, attrs); } scrollView.setId(R.id.scrollview); return scrollView; }

他里面提供了一个方法可以或得到Scrollview:

final ScrollView scrollView = mScrollView.getRefreshableView();

回想起了以前项目也这么用过,只是当时不明白这句话干啥的,白写。

然后就用上面这种方法得到scrollview,再设置onscrollchanged方法监听滑动。运行报错,同样无效。于是只能换onTouchListener监听了。

但是这样问题来了,我们只能监听到手势,即何时按下、移动和弹起。当快速滑动手指弹起后,scrollview还在滚动的,什么时候去拿到它的scrollY值呢?犯愁了。

此时不得不用最开始分析的方法,在自定义imageview里面定义线程,扫描当前scrollY和上一次保存的对比,不一样即说明仍在滚动,一样即表明scrollview滚动停止了。

什么时候开启线程呢?在onTouch回调中down、move或者up时调用。

试想下:

如果在down中调用时,用户只在scrollview上点击或短距离滑动,imageview里面要不停地开启线程?浪费资源。

如果在up中调用时,当用户按着屏幕一口气滑过临界值,还不松手呢?还不显示imageview吗?也行,个人觉得不太好。
于是,我选择在move中调用imageview地线程。有人会想,这样会不会启动N多个线程呢?move一直在移动呢。“在iamgeview判断下线程的状态即可,如果已经启动了,就不启动呗”。或许这么写不太好,但我认为是实时的,用户体验好。

看代码:

/** * 获取待监控的view对象 * 实时调起线程,监控是否scroll停止,来判断是否需要显示imageView * @param targetView 需要监控的对象 */ public void tellMe(View targetView) { if (targetView == null) throw new IllegalArgumentException("please set targetView who to scrollTo"); if (this.targetView == null) this.targetView = targetView; if (!isStarting) { new Thread(scanThread).start(); } }

此处注意,我偷懒了,没有单独设置方法传递需要滚动的scrollview,在此处引进来了。线程加了判断。此处不要传递scrollview的scrollY值进来。比喻当你手指离开屏幕后,之前传递进来的scrollY就已经过时了,scrollview仍在滑动。在消息回调里面实时获取再判断

private class MyCallback implements Runnable { @Override public void run() { /** * 获取实时的卷动值,不要传递scroll值给我 */ endScrollX = targetView.getScrollX(); int scrollY = targetView.getScrollY(); if (endScrollY != scrollY) { endScrollY = scrollY; } else { if (endScrollY >= limitHeight) { if (!thisStateVisible) visible(); } else { if (thisStateVisible) gone(); } /** * 已判定,卷动停止,显示或隐藏当前view已完成 * 退出监控scroll线程 */ clearCallBacks(); } } }

由于是用线程来检测scrollview的滚动状态,我用了延时消息。此时又有另外一个潜在bug。在自定义imageview中创建了handler属于主线程,子线程中需要发延时消息。如果延时消息发出后,activity退出了呢?反复这么弄呢?有人会说没谁会这么无聊的。但这毕竟还是潜在的OOM。于是我简单的做了线程控制和消息清除的代码,过于简单。感谢评论。

主要思路和逻辑都分析完了,使用起来很简答,你不用关心自定义imageview里面的逻辑(除非你想改进)。

在activity中

private PullToRefreshScrollView mScrollView; private ToTopImageView imageView_to_top; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pull_to_refresh_scroll_view); imageView_to_top = (ToTopImageView) findViewById(R.id.imageView_to_top); imageView_to_top.setLimitHeight(800); mScrollView = (PullToRefreshScrollView) findViewById(R.id.scrollView); final ScrollView scrollView = mScrollView.getRefreshableView(); //mScrollView.setOnTouchListener(); 无效 scrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_MOVE: imageView_to_top.tellMe(scrollView); break; } return false; } }); } @Override protected void onDestroy() { imageView_to_top.clearCallBacks(); super.onDestroy(); }

页面上,在你觉得合适的位置:

<com.znke.pulltorefresh_top.tool.ToTopImageView android:id="@+id/imageView_to_top" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="5dp" android:layout_marginRight="5dp" android:background="@drawable/to_top" />

完事。

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位Android开发者们能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

时间: 2024-07-28 18:54:46

Android scrollToTop实现点击回到顶部(兼容PullTorefreshScrollview)的相关文章

Android悬浮按钮点击返回顶部FloatingActionButton

先看一下Android悬浮按钮点击回到顶部的效果: FloatingActionButton是Design Support库中提供的一个控件,这个控件可以轻松实现悬浮按钮的效果 首先,要在项目中使用这个悬浮按钮就要先把design这个包导入项目 gradle中加入依赖 compile 'com.android.support:design:25.0.0' 接下来就是在xml中使用: 我这里是放置一个listView模拟返回顶部 <?xml version="1.0" encodi

jquery实现点击回到顶部以及定点滚动

1.思路 DOM的每个标签以及浏览器本身都有一个scrollTop属性,这不是CSS可以控制的(目前),这个值指的是在一个指定的容器内当前可视顶部距离内容顶部的距离,如果这个容器是浏览器的话,那么滚动条的上边距就是这个值. 那么,如果想要回到顶部的话,设置scrollTop的值为0即可,滚动到指定位置也可以设置这个值为指定的数值. 设置scrollTop为0: $(window).scrollTop(0); 设置scrollTop为指定数值: var T=200;//这个是number类型,不需

Jquery实现点击页面回到顶部_jquery

a)下面看看实现,实现很简单,通过JQ判断滚动条向下滚动的长度大于多少时显示[回到顶部+回到首页]的图标(换一种理解:滚动条顶端距离页面顶部的距离),另外一种实现方法,就是通过锚标记,很好理解,就是标记一个位置,事件激活时,给我回到这个位置 b)JQ判断滚动条向下滚动的长度大于多少时,这个方法,也可以用来做页面的自动加载...就是你不停滚动,数据就不停加载...用户体验很好的喔[有时间就写] 1)首先我们写好DOM结构.写好CSS样式表 /* HTML */ <div style="wid

jquery实现的动态回到顶部特效代码_jquery

本文实例讲述了jquery实现的动态回到顶部特效代码.分享给大家供大家参考,具体如下: 这款jquery动态回到顶部特效,不是一下子就回到了网页顶部,而是带点缓冲的效果,有动画效果,使用了jQuery插件,这是个非常常用的网页特效,希望大家喜欢哦. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/jquery-back-top-dh-style-codes/ 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DT

jQuery回到顶部的代码_jquery

在一些网站上,我们经常见到返回顶部的效果,本文给大家介绍基于jquery如何实现返回顶部效果.感兴趣的朋友跟着小编一起看下实现代码吧. 首先需要在顶部添加如下html元素: <p id="back-to-top"><a href="#top"><span></span>返回顶部</a></p> 其中a标签指向锚点top,可以在顶部防止一个<a name="top">

jQuery实现带有动画效果的回到顶部和底部代码_jquery

本文实例讲述了jQuery实现带有动画效果的回到顶部和底部代码.分享给大家供大家参考,具体如下: 这款动画版的回到顶部和底部效果代码,也算是比较常见的一款网页特效了,像淘宝网就有这种效果,使用了jQuery插件,加入了动画效果. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/jquery-animate-style-scroll-top-buttom-codes/ 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C

jQuery实现分章节锚点“回到顶部”动画特效代码_jquery

本文实例讲述了jQuery实现分章节锚点"回到顶部"动画特效.分享给大家供大家参考,具体如下: 这里演示基于jquery实现的分章节动画实现"回到顶部"的效果,可通过 网页顶部的数字序号直接进入网页的章节,当处于第二章节的时候,网页右侧会显示竖排的控制按钮,点击按钮会回到相应章节,其实也就是定义好的锚点,当然也可回到顶部,网页上见到的回顶部大多不是这个样子,所以本款效果还挺新颖. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js

Android开发之Activity的中部或底部回到顶部

我们浏览淘宝商品详情的时候会遇到回到顶部这个功能,下面就说说这个功能的简单实现 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ScrollView android:id="

JS 滚动事件window.onscroll与position:fixed写兼容IE6的回到顶部组件_javascript技巧

现在网上的回到顶部组件,懂不懂就一大段让人看不懂javascript代码,还各种不兼容.起始这个组件,完全可以自己利用javascript的滚动事件window.onscroll与position:fixed手写.IE6的兼容性问题主要出现在position:fixed上面,如何解决已经在<[CSS]IE6中的position:fixed问题与随滚动条滚动的效果>(点击打开链接)介绍过了. 下面具体说说如何利用JavaScript中的滚动事件window.onscroll实现这个回到顶部组件.