Android用scrollview做一张表

本文介绍了如何在Android中使用ScrollView实现类似表格的上下左右滚动效果。通过将ScrollView嵌套组合,实现列-时间的垂直滚动,行-星期的水平滚动。在滚动过程中,通过监听并处理各ScrollView的滚动事件,确保滚动同步。文章还分析了防止滚动死循环的原因,即当ScrollView的滚动位置等于mScrollX时,将不再触发滚动,避免了死循环的发生。

这里写图片描述
这里写图片描述

思路:
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不滚动,无死循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值