其实这个标题并不能完整表达实际的效果的描述,因为在开发很多应用的过程中,我们都有这么一个需求,那就是在某个页面中,又一行(或者一列)作为导航的菜单,而整页的内容,又因为过长而不得不加入滚动试图,如果说只是这样简单的需求的话,我们直接把导航的菜单固定在边缘,那样就一劳永逸了,但是实际上很多需求并不是简单的这样处理的,比如:在一个页面的顶部是缩略图,接着中间是一栏导航,下面是具体的内容;如图:

如果我们把顶部的图片和导航固定,那么下部可动范围就太小了,所以,更多的时候我们是需要这样的处理,当开始拖动界面以查看底部更多内容的时候,让界面中顶部的图片和中部的导航一起动,但是当导航栏到达顶部的时候,便固定在那里;同时,当拖动界面往下,底部内容拉去完以后,应该是导航栏和顶部图片一起往下,拖动到最后恢复为初始的样子。

根据现有的需要,我的简单思路是这样处理,整个页面是放入一个ScrollView之中,再加入一个默认是View.GONE的FrameLayout中,布局一个和在ScrollView中的导航栏一样的导航栏;监听ScrollView的滑动事件,当ScrollView的导航栏view的getLocationInWindow()获得的坐标y <= ScrollView.y,则处理把FrameLayout的导航栏显示出来,同理,返回时逆向处理。

思路基本理清,现在要做的就是实际的监听如何完成,因为ScrollView不是ListView可以监听滚动,默认的ScrollView只有一个onTouch(),虽然这个看似也能解决我们的问题,但是实际上,当你快速滑动的时候,你就会发现,想要的置顶的导航栏没有显示出来,直到再次触到屏幕,在能出来,显然这样的效果是不如意的。

纠结过后,考虑可否使用一个线程,每隔200ms触发一次判断,如果应该显示置顶的导航栏了,发送一个消息,然后处理,我测试了一下代码,这样的方法固然可行,但是后来想想,这样的操作,似乎不是很好,最后还是从测试代码中删去,不过这个方法可以作为备选方案。

经过几番摸索,觉得修改ScrollView来实现类似ListView的滚动监听似乎比较靠谱,所以决定写一个ObservableScrollView,这个类是继承ScrollView的,在内部增加一个借口回调,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.ilovn.app.test.floatnav;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

/**
* 动态ScrollView
*
* @author zhaoyong1990@gmail.com
*
*/
public class ObservableScrollView extends ScrollView {
private ScrollViewListener scrollViewListener = null;

public ObservableScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}

public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public ObservableScrollView(Context context) {
super(context);
}

public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}

@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}

public interface ScrollViewListener {

public void onScrollChanged(ObservableScrollView scrollView, int x,
int y, int oldx, int oldy);

}
}

这个ObservableScrollView是比较通用的,实际上我们这里的效果不需要那么详细的参数,只需要在scroll的视图实现这个借口,在回调函数中,处理导航栏的显示与消失即可。

看一下效果图:


本文系原创,转载请注明出处!