全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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开发者们能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。


# android  # 回到顶部  # scrolltotop  # 回到顶部按钮  # android使用Ultra-PullToRefresh实现下拉刷新自定义代码  # Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能  # Android开源项目PullToRefresh下拉刷新功能详解  # Android下拉刷新控件PullToRefresh实例解析  # Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码  # Android实现简单的下拉刷新pulltorefresh  # Android程序开发之使用PullToRefresh实现下拉刷新和上拉加载  # Android PullToRefreshLayout下拉刷新控件的终结者  # 分享Android中pullToRefresh的使用心得  # android使用PullToRefresh框架实现ListView下拉刷新上拉加载更多  # 自定义  # 临界值  # 用了  # 报错  # 来了  # 什么时候  # 还不  # 不就  # 回调  # 就可以  # 很遗憾  # 卷动  # 我也  # 给我  # 我还  # 太多  # 有个  # 出了  # 还在  # 多个 


相关文章: 如何通过可视化优化提升建站效果?  建站之星CMS五站合一模板配置与SEO优化指南  C++ static_cast和dynamic_cast区别_C++静态转换与动态类型安全转换  建站之星北京办公室:智能建站系统与小程序生成方案解析  实现点击下箭头变上箭头来回切换的两种方法【推荐】  模具网站制作流程,如何找模具客户?  制作农业网站的软件,比较好的农业网站推荐一下?  免费制作小说封面的网站有哪些,怎么接网站批量的封面单?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  制作假网页,招聘网的薪资待遇,会有靠谱的吗?一面试又各种折扣?  如何彻底删除建站之星生成的Banner?  如何快速查询域名建站关键信息?  大同网页,大同瑞慈医院官网?  电商平台网站制作流程,电商网站如何制作?  如何在VPS电脑上快速搭建网站?  可靠的网站设计制作软件,做网站设计需要什么样的电脑配置?  个人网站制作流程图片大全,个人网站如何注销?  建站之星体验版:智能建站系统+响应式设计,多端适配快速建站  建站之星伪静态规则如何设置?  行程制作网站有哪些,第三方机票电子行程单怎么开?  网站制作公司广州有几家,广州尚艺美发学校网站是多少?  如何制作网站标识牌,动态网站如何制作(教程)?  如何获取免费开源的自助建站系统源码?  常州自助建站:操作简便模板丰富,企业个人快速搭建网站  ,如何利用word制作宣传手册?  ui设计制作网站有哪些,手机UI设计网址吗?  重庆网站制作公司哪家好,重庆中考招生办官方网站?  如何用搬瓦工VPS快速搭建个人网站?  建站之星五站合一营销型网站搭建攻略,流量入口全覆盖优化指南  简单实现Android验证码  如何通过FTP服务器快速搭建网站?  建站之星导航菜单设置与功能模块配置全攻略  网站制作软件有哪些,制图软件有哪些?  如何基于云服务器快速搭建个人网站?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  平台云上自助建站如何快速打造专业网站?  英语简历制作免费网站推荐,如何将简历翻译成英文?  建站之星IIS配置教程:代码生成技巧与站点搭建指南  怀化网站制作公司,怀化新生儿上户网上办理流程?  深圳网站制作的公司有哪些,dido官方网站?  Android自定义控件实现温度旋转按钮效果  香港服务器选型指南:免备案配置与高效建站方案解析  台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?  php条件判断怎么写_ifelse和switchcase的使用区别【对比】  mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?  兔展官网 在线制作,怎样制作微信请帖?  C++时间戳转换成日期时间的步骤和示例代码  建站主机是否属于云主机类型?  建站ABC备案流程中有哪些关键注意事项?  如何撰写建站申请书?关键要点有哪些? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。