热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Android自定义StickinessView粘性滑动效果

这篇文章主要为大家详细介绍了Android自定义StickinessView粘性滑动效果的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

design包的出现,Android界面发生了巨大变化,各种滑动配合的效果,下面我就粘性滑动中的一种进行自定义,效果图如下:


大家看到效果了,这里我是继承了LinerLayout,方便一点,若果是ViewGroup的话,也就复杂一点点。这里分为三部分:

1.head1,顶部可移动的Layout。
2.head2,固定的头部,不会滑动除屏幕外。
3.可滑动的Layout(这里只可以是ListView,不过也可以是任何可滑动的View,只要给出Head可滑动的时机即可)

本StickinessView的难点在于,解决滑动冲突和事件的拦截处理,接下来我一一道来。

一、首先,要确定HeadLayout什么时候可以拦截事件,那么就要确定ListView到达顶部和底部的时机。

 @Override
 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  View v = mListView.getChildAt(0);
  //当firstItem的top为0的时候就认为已经到达ListView的顶部了
  if (mListView.getChildCount() > 0 && firstVisibleItem == 0) {
   //滑动到顶部
   if (v.getTop() == 0) {
    //滑动到顶部了
    isListViewTop = true;
   } else {
    isListViewBottom = false;
   }
  }else if (mListView.getChildCount()>0&&firstVisibleItem+visibleItemCount==totalItemCount){
   final View bottomChildView = mListView.getChildAt(mListView.getChildCount()-1);
//当最后一个itemView的bottom>=ListView的高度的时候,那么就认为到达底部了
   if    (mListView.getHeight()>=bottomChildView.getBottom()){
    isListViewBottom = true;
   }else {
    isListViewBottom = false;
   }
  }else {
   isListViewBottom = false;
   isListViewTop = false;
  }

原因很简单,因为View的getTop和getBottom方法是相对父容器的位置,熟悉Layout方法的,想必就会很明白了。

二、知道了HeadView拦截事件的时机,我们就要搞清楚在此基础之上,我们到底啥时候拦击点击事件,进行滑动。

 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
  switch (ev.getAction()) {
   case MotionEvent.ACTION_DOWN:
    touchY = ev.getRawY();
    isIntercept = false;
    break;
   case MotionEvent.ACTION_MOVE:
    float distant = ev.getRawY() - touchY;
    if (isListViewTop) {
     switch (mHeadPosition) {
      case TOP:
       if (distant > 0) isIntercept = true;
       break;
      case CENTER:
       isIntercept = true;
       break;
     }
    }
    if (isListViewBottom){
     switch (mHeadPosition) {
      case CENTER:
       isIntercept = true;
       break;
      case BOTTOM:
       if (distant <0) isIntercept = true;
       break;
     }
    }

    break;
   case MotionEvent.ACTION_UP:
    isIntercept = true;
    break;
  }
  return isIntercept;
 }

跟大家讲解一下onInterceptTouchEvent(MotionEvent ev),这个方法会最先调用,当一个事件序列拦截一次后,那么这个事件的后续事件动作就不会再调用该方法,也就是说,当该ViewGroup决定拦截某个事件后,那么它注定要消费后续的事件动作。这里贴出HeadView的位置状态

public static final int TOP = 0;//收缩状态
public static final int CENTER = 1;//中间状态
public static final int BOTTOM = 2;//展开状态

关于细节,想必大家画个图就可以知道了,注意一点:在拦截事件序列的时候,一般ACTION_DOWN事件不可以被拦截,因为拦截的话,没得意义了,后续事件就无法控制了,不可能继续往ChildView传递事件序列。

三、移动HeadView。

@Override
public boolean onTouchEvent(MotionEvent event) {
 switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   //获取不到的
   break;
  case MotionEvent.ACTION_MOVE:
   int distant = (int) (touchY - event.getRawY());
   if (getScrollY() + distant-1  0) {
    scrollTo(0, getScrollY() + distant);
   }
   break;
  case MotionEvent.ACTION_UP:
   if (getScrollY() == 0) mHeadPosition = BOTTOM;
   if (getScrollY() == MAXY) mHeadPosition = TOP;
   if (getScrollY() > 0 && getScrollY()  MAXY / 2) {
    mScroll.startScroll(0, getScrollY(), 0, MAXY-getScrollY(),100);
    invalidate();
    mHeadPosition = TOP;
   }
   if (getScrollY() 

这里为了使得滑动跟家顺畅我使用了Scroller这个类,该类是专门处理弹性滑动的工具类,先初始化构造器,在调用startScroll()方法(其中四个参数:滑动的x,滑动的y,滑动x的偏移量,滑动y的偏移量),然后刷新视图,最后重写computeScroll()方法,

@Override
public void computeScroll() {
 super.computeScroll();
 if (mScroll.computeScrollOffset()){
  scrollTo(mScroll.getCurrX(),mScroll.getCurrY());
  postInvalidate();
 }
}

好了,基本完成,我们还要第一时间获取HeadView的高度,那么在onMeasure()中获取比较好,并且只获取一次如下

 if (MAXY == -1)
  MAXY = mHeadSecond.getMeasuredHeight();

在onFinishInflate()方法中,该方法的执行标志着所有的View都已经add完毕,这里我们进行初始化是比较妥当的。

 @Override
  protected void onFinishInflate() {
  super.onFinishInflate();
  int count = getChildCount();
  //本粘性布局只支持ListView
  if (count == 3 && getChildAt(2) instanceof ListView)
   init();
 }
 /**
  * 初始化
  */
 private void init() {
  //获得子元素
  mHeadFiest = getChildAt(0);
  mHeadSecOnd= getChildAt(1);
  mListView = (ListView) getChildAt(2);
  mListView.setOnScrollListener(this);
  mScroll = new Scroller(getContext());
 }

好了,基本就是这些。
GitHub地址:https://github.com/yzzAndroid/LianXinView

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 【MicroServices】【Arduino】装修甲醛检测,ArduinoDart甲醛、PM2.5、温湿度、光照传感器等,数据记录于SD卡,Python数据显示,UI5前台,微服务后台……
    这篇文章介绍了一个基于Arduino的装修甲醛检测项目,使用了ArduinoDart甲醛、PM2.5、温湿度、光照传感器等硬件,并将数据记录于SD卡,使用Python进行数据显示,使用UI5进行前台设计,使用微服务进行后台开发。该项目还在不断更新中,有兴趣的可以关注作者的博客和GitHub。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 标题: ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
author-avatar
手机用户2502885897
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有