欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Android制作一个锚点定位的ScrollView

程序员文章站 2022-11-20 21:51:03
因为遇到了一个奇怪的需求:将垂直线性滚动的布局添加一个indicator。定位布局中的几个标题项目。为了不影响原有的布局结构所以制作了这个可以锚点定位的scrollview,就像markdown的锚点...

因为遇到了一个奇怪的需求:将垂直线性滚动的布局添加一个indicator。定位布局中的几个标题项目。为了不影响原有的布局结构所以制作了这个可以锚点定位的scrollview,就像markdown的锚点定位一样。所以自定义了一个scrollview实现这个业务anchorpointscrollview

完成效果图

Android制作一个锚点定位的ScrollView

需求分析

怎么滚动?

一个锚点定位的scrollview。在scrollview中本身有smoothscrollby(int,int)、scrollto(int,int)这种可以滚动到指定坐标位置的方法。我们可以基于这个方法来进行定位view的位置。

smoothscrollby(int,int)是增量滚动。即从当前位置增加减少滚动距离。

scrollto(int,int)是绝对坐标滚动。滚动到指定的坐标位置。

这里我选择的是使用smoothscrollby这个方法来进行处理。

滚动到哪里?

我已经确定使用smoothscrollby来进行布局的滚动。那么下一步就是要知道滚动到下一个view要多少距离,怎么确定下一个view的坐标位置。

首先要确定view的位置。如果我们通过view.gety()获取的话这个是绝对不正确的。因为view.gety()是当前view与自己父view的嵌套坐标关系。而scrollview内部是个linearlayout,而且布局中也有很多的嵌套关系,所以不能使用view.gety()来获取view的坐标。

使用getlocationonscreen(intarray)获取view在屏幕上的绝对坐标位置,再减去scrollview的绝对坐标位置,就得到了。当前view与scrollview的相对位置关系。它们之间的差值就是我们要滚动的距离。

代码实现

我们写一个方法,让scrollview滚动到指定的view位置。

这里的offset参数是滚动的额外偏移量。来保证滚动的时候预留一些额外空间。

现在已经可以滚动到指定的view位置了。接下来就是比较难的了。

Android制作一个锚点定位的ScrollView

锚点变化位置处理

现在只是能够滚动到指定的view了,但是这并不能完全满足业务需求。在ui上是要有一个indicator指示器的,来指示当前已经滚动到哪个位置。

所以我们先增加一个集合,来保存滚动的锚点view。

并增加方法添加views

分析: 我们已经有了需要定位,需要监听变化的views,当scrollview滚动的时候,我们可以通过onscrollchangelistener监听滚动,并获取注册的锚点view的位置改变信息。在onscrollchange中计算滚动偏移和滚动到哪个view。

在注册onscrollchangelistener的时候我们也要保留外部的监听器使用。

我们接下来的所有操作都将会在computeview()这个方法中进行

我们先封装一个数据体用于保存view与坐标的对应关系。

在onsizechanged的时候,获取当前scrollview的坐标位置

这里的[mpos]在之后都将表示当前scrollview的坐标位置

查找最近两个view

我们该如何确定哪个view滚动的位置已经临近mpos了。我们可以使用一个简单的查询算法来找到。

演示

我们可以遍历view的y坐标与当前的y坐标进行对比然后得到当前y坐标临近的两个值。 我们通过一个测试方法演示一下

大家也可以自己运行一下例子修改tag的大小来验证一下。

我们通过这个简单的算法,抽象的应用到我们的业务逻辑中。

我们通过上面的计算,拿到了当前坐标mpos与之相邻的前一个viewpos和后一个viewpos,而且也得到了滚动到了哪个下标位置index。如果在当前滚动位置之前没有所注册的view即为null。如果在当前滚动位置之后没有所注册的view即为null。

现在我们有了这几个信息参数:

  • mpos: 当前滚动布局scrollview的顶部坐标.
  • previousview:当前滚动位置的前一个view,或者说是y坐标小于mpos的最近的view。
  • nextview:当前滚动位置的下一个view,或者说是y坐标大于mpos的最近的view。
  • scrollindex: 即当前滚动到哪个注册的view范围之内了。这个参数的改变周期是,当下一个nextview成为previousview之前,这个值将一直为当前previousview的下标位置。

Android制作一个锚点定位的ScrollView

计算距离

计算previousview与mpos的距离,nextview与mpos的距离. 这个距离其实很好计算。直接拿两个坐标相减即可得到。

这里的代码,在计算滚动距离的时候,要先进行view==null的判断。因为如果是null的话,有两种情况。

  • 开始滚动时还未滚动到,注册的第一个view时。第一个view为nextview。previousview==null。
  • 滚动到底部了,在滚动下去,后面没有注册的锚点了,最后一个view为previousview,nextview==null

Android制作一个锚点定位的ScrollView

在计算出距离的同时对scrollindex的坐标位置也进行修复。如果还没滚动到第一个注册的锚点view,那么scrollindex=0,如果没有nextview了说明到最后了,scrollindex=最后。还有一种情况就是由于最后一个注册的锚点view的高度,根本不够滚动到scrollview顶部的话。就对这个下标位置进行修复。我们在一开始查找相邻两个view的时候就将isscrollbottom参数进行了初始化。而isfixbottom我们根据业务需求进行设置。

计算距离最终得到了两个参数:

~ previousviewdistance:previousview与mpos的距离。

~ nextviewdistance: nextview与mpos的距离。

Android制作一个锚点定位的ScrollView

计算百分比

有了相隔的距离,接下来我们就可以去求向上滚动时previousview的逃离百分比与nextview的进入百分比。

Android制作一个锚点定位的ScrollView

前一个view的逃离百分比previousratio的值= previousviewdistance/前一个view与下一个view的距离

而下一个view的进入百分比nextratio=1.0-prevousratio.

代码

经过上面的计算我们得到了这几个数据:

  • viewdistancedifference:previousview与nextviewy坐标之差。即前后相距的距离
  • previousratio:前一个view的逃离百分比,previousview与mpos的距离百分比。
  • nextratio:下一个view的进入百分比,nextview与mpos的的距离百分比。

这样就算是完工了。

回调监听

最后我们将这些参数进行分类,交给页面去处理。

增加一个interface

将数据填入

最后再看一眼完成的效果

这里的indicator用的是magicindicator。代码都再github上了。大家自己观摩一下吧。

Android制作一个锚点定位的ScrollView

其实还是有很多优化的空间的。比如查找最相邻的两个view时的算法。在最后注册的1-3个view不足以滚动到顶部的时候,可以让index的变化更加优雅等等。。有待改进。

以上就是android制作一个锚点定位的scrollview的详细内容,更多关于android 制作scrollview的资料请关注其它相关文章!