CCScrollView 的隐藏属性 —— 缩放

来源:互联网 发布:java ee是什么 编辑:程序博客网 时间:2024/06/05 18:23

        遇到一个很神奇的事情,之前的项目里面,有一个主地图的缩放功能,类似COC背景地图,可以拖动,可以双指缩放。

        一般说来,我们会想到写个layer通过多点触控自己实现,因为现有的引擎提供的组件没有能实现这个功能的(或者说我以前不知道。。。),但是我看这个项目代码的时候发现,整个工程里面,所有的touchmode全是kccOneByOne,也就是说全是单点模式,但是他确实用的是scrollView,确实能实现双指缩放。好神奇。

        然后我深入这个事情之后,发现了一系列颠覆我世界观的事情~~~ 

        先说scrollView,其实scrollView一直可以支持缩放,只不过被的隐藏了。在scrollView的代码的touchBegan里面,可以看到如下代码(引擎版本3.4,2.x的同理):

bool ScrollView::onTouchBegan(Touch* touch, Event* event){    ... ...    if (std::find(_touches.begin(), _touches.end(), touch) == _touches.end())    {        _touches.push_back(touch);    }    if (_touches.size() == 1)    { // scrolling        _touchPoint     = this->convertTouchToNodeSpace(touch);        _touchMoved     = false;        _dragging     = true; //dragging started        _scrollDistance = Vec2(0.0f, 0.0f);        _touchLength    = 0.0f;    }    else if (_touches.size() == 2)    {        _touchPoint = (this->convertTouchToNodeSpace(_touches[0]).getMidpoint(                        this->convertTouchToNodeSpace(_touches[1])));                _touchLength = _container->convertTouchToNodeSpace(_touches[0]).getDistance(                       _container->convertTouchToNodeSpace(_touches[1]));                _dragging  = false;    }     return true;}
        无关代码已经被省略,可以看到这里面有一个关于触摸点数量的判断,然后还有很多类似的代码(这里涉及一个诡异的问题):
   void setZoomScale(float s);   void setZoomScale(float s, bool animated);   float getZoomScale();   void setZoomScaleInDuration(float s, float dt);
        zoom的意思显然是缩放。

        从touchBegan里面可以看出,这里有一个多点判断,断点size=2的那个分支,发现不能命中断点。把设备打开多点模式,ios需要设置一下glview,具体请百度。发现断点可以成功命中,说明这一步正常。

        但是这个时候还是不能缩放,继续跟,发现touchMove里面如下代码:

void ScrollView::onTouchMoved(Touch* touch, Event* event){     ...  ...        else if (_touches.size() == 2 && !_dragging)        {            const float len = _container->convertTouchToNodeSpace(_touches[0]).getDistance(                                            _container->convertTouchToNodeSpace(_touches[1]));            this->setZoomScale(this->getZoomScale()*len/_touchLength);        }    ...  ...}
        会调用setZoomScale:

void ScrollView::setZoomScale(float s){    ...  ...        _container->setScale(MAX(_minScale, MIN(_maxScale, s)));    ...  ...}

        关键就是设置这个container的scale,里面涉及3个变量,一个是传入的想设置的scale,一个是minScale,一个是maxScale,但是max和min在初始化的时候,都被设置成了1。那么这个表达式 MAX(minscale , MIN(maxscale , s)) 的值,就会恒等为1。

        所以只要我们能让这个表达式的值发生变化,是不是就可以了?还真是这样。 不幸的是,这个maxscale和minscale的定义,是protect,并且没有提供任何访问函数。。。所以要么直接改掉源代码,要么继承一个子类,提供2个访问函数,来设置这2个值就可以了。

        乱入:在3.4的代码里面,已经有这2个值的访问函数,2.x的没有

        PS:无责任剧透,据说缩放的时候会有些位移的问题,把container的anchor设置为(0,0)可以解决。我没测,不知道


        总结:

        1、scrollView实现了双指缩放功能,但是被隐藏

        2、打开设备多点触控,并且设置minscale和maxscale,即可使用缩放功能(设置方法见上文)

        3、参考上面PS内容。


        诡异问题:为什么是单点的触摸模式,确可以达到2点缩放的效果?请看这里!

0 0
原创粉丝点击