思路:
1.列-时间:用一个ScrollView(columnScrollView)-可上下滚动
2.行-星期:用一个HorizontalScrollView(rowScrollView)-可左右滚动
3.内容:使用ScrollView(yScrollView)嵌套HorizontalScrollView(xScrollView)-可实现上下左右滚动
4.rowScrollView和xScrollView要同时滚动;columnScrollView和yScrollView要同时滚动 。
实现行和列属性始终保持在表格上边和左边。
代码如下:
监听这四个scrollview,做相应的处理,例如:
xScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
rowScrollView.scrollTo(scrollX, scrollY);
}
});
rowScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
xScrollView.scrollTo(scrollX, scrollY);
}});
问题:两个横向的scrollview互相监听,xScrollView滚动,在其监听方法中会调用rowScrollView的scrollTo方法,rowScrollView也跟随滚动,此时rowScrollView就监听到了,然后就会调用xScrollView的scrollTo方法,scrollTo一触发,就会被xScrollView监听到。。。但是为什么不会出现死循环?
查看ScrollView的源码发现如下方法
@Override
public void scrollTo(int x, int y) {
// we rely on the fact the View.scrollBy calls scrollTo.
if (getChildCount() > 0) {
View child = getChildAt(0);
x = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
y = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
if (x != mScrollX|| y != mScrollY) {
super.scrollTo(x, y);
}
}
}
//发现在某些特定的情况下才会真正的调用scrollTo方法。
//n-->一开始传递的参数,通知你要滚动n个像素值。
//me -->父控件宽度去掉左右内边距所占像素值。
//child-->子视图的宽占的像素值。
private static int clamp(int n, int my, int child) {
if (my >= child || n < 0) {
/* my >= child is this case:
* |--------------- me ---------------|
* |------ child ------|
* or
* |--------------- me ---------------|
* |------ child ------|
* or
* |--------------- me ---------------|
* |------ child ------|
*
* n < 0 is this case:
* |------ me ------|
* |-------- child --------|
* |-- mScrollX --|
*/
return 0;
}
if ((my+n) > child) {
/* this case:
* |------ me ------|
* |------ child ------|
* |-- mScrollX --|
*/
return child-my;
}
return n;
}
//以横向滚动为例:
当scrollview.width>=child.width,则不会形成滚动。
滚动距离n则一定是从0开始一直到50pixel。
mScrollX在View源码中注释是:The offset, in pixels, by which the content of this view *is scrolled horizontally 横向滚动的视图内容的偏移量。
对于mScrollX的理解可参考:http://www.jianshu.com/p/2b981f474daa
以上可知mScrollX>0,才能形成滚动。
1、xScrollView横向滚动x=50pixel,监听到后会调用rowScrollView的scrollTo方法。
2、rowScrollView不存在任何内边距,要能形成滚动,则my小于child,并且n是从0开始增加的,所以在scrollTo方法中调用clamp则会返回n。
3、x=0,1,2,3…..50,在scrollTo方法中x != mScrollX,那么就会真正的调用 super.scrollTo(x, y)。
//super.scrollTo(x, y),View类里的scrollTo方法
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
//方法中可知mScrollX = x
4、xScrollView滚动调用rowScrollView.scrollTo(x,y), rowScrollView一滚动就调用xScrollView.scrollTo(x,y)。
在rowScrollView中最开始调用scrollView中的scrollTo方法时,x != mScrollX,则调用super.scrollTo(x,y),此时mScrollX=x。
在rowScrollView监听方法里再调用xScrollView.scrollTo(x,y),此时xScrollView 中x==mScrollX,xScrollView不滚动,无死循环。
本文介绍了如何在Android中使用ScrollView实现类似表格的上下左右滚动效果。通过将ScrollView嵌套组合,实现列-时间的垂直滚动,行-星期的水平滚动。在滚动过程中,通过监听并处理各ScrollView的滚动事件,确保滚动同步。文章还分析了防止滚动死循环的原因,即当ScrollView的滚动位置等于mScrollX时,将不再触发滚动,避免了死循环的发生。

被折叠的 条评论
为什么被折叠?



