zoukankan      html  css  js  c++  java
  • Cocos2dx 小技巧(十五)话说ScrollView的delegate实现过程

    附:本文參加了CSDN博客大赛。亲假设认为这篇文章不错,就大胆的来投上一票吧!

    !!http://vote.blog.csdn.net/Article/Details?

    articleid=34140469

    转眼六月份都快过去了,我发现这个月我一篇博客都没发表。

    表示非常羞涩......

    下个月非常有可能会迎来博客大爆发。仅仅是博客的主题有点......呃,留点悬念吧。

    ---------------------

    有小伙伴和我私聊时说在看过我写的那篇 delegate相关的博文后。回过头再看看ScrollView托付的实现过程还是有点吃力。我赶紧搜出之前那篇博文看了看......不禁感慨:

    尼玛,这写的都是些啥?!

    怎么我自己都看晕了?

    做人要厚道!写博要实在!为了弥补之前的不足,以下我就以一个新手的角度(事实上自己就是新手)来研究下ScrollView的托付实现流程究竟是如何的。


    1、首先进入ScrollView.h文件里,在声明ScrollView这个类之前先声明一个托付类。之所以称之为托付,由于它的命名中包括 delegate 这个词

    例如以下:

    class ScrollView; //前向声明scrollView
    
    class ScrollViewDelegate
    {
    public:
        virtual ~ScrollViewDelegate() {}
    
        virtual void scrollViewDidScroll(ScrollView* view) = 0;
        virtual void scrollViewDidZoom(ScrollView* view) = 0;
    };

    能够看到在这个托付类的声明里有两个函数。一个是scrollViewDidScroll(),这是当scrollView在被拖动时会响应该函数;还有一个是scrollViewDidZoom。我想应该是当scrollView在进行缩放时会响应该函数。

    2、接下来就是声明ScrollView这个类了。一開始我本能认为既然ScrollView要与ScrollViewDelegate这个类关联起来。那么它就应该继承ScrollViewDelegate吧?可实际上并没有,ScrollView仅仅是单纯的继承一个Layer罢了。例如以下:
    class ScrollView : public Layer{};
    问题来了,ScrollView既然与ScrollViewDelegate没有“父子”关系,那么它是如何调用ScrollViewDelegate中的那些函数的呢?我继续看下ScrollView的类声明。


    发现有这么两个函数:

    ScrollViewDelegate* getDelegate() { return _delegate; }
    void setDelegate(ScrollViewDelegate* pDelegate) { _delegate = pDelegate; }
    ScrollViewDelegate* _delegate;
    这里比較easy理解,先声明一个ScrollViewDelegate* 类型的成员变量。然后通过setDelegate() 与 getDelegate()分别设置与获取_delegate对应的对象

    看到这里好像还不是非常理解_delegate究竟该怎么用,那起码有一些眉目了,毕竟ScrollViewDelegate已经浮出水面。不是那么神奇。继续往下看。

    3、在ScrollView.cpp文件里,我開始找下_delegate这个成员变量都在哪里使用过。非常快我在setContentOffset()这个函数中找到它的身影
    void ScrollView::setContentOffset(Point offset, bool animated/* = false*/)
    {
        if (animated)
        { //animate scrolling
            this->setContentOffsetInDuration(offset, BOUNCE_DURATION);
        } 
        else
        { 
    	...		...
            if (_delegate != NULL)
            {
                _delegate->scrollViewDidScroll(this);   //就是这里。
            }
        }
    }
    setContentOffset()这个函数大家应该都非常熟悉了,就是通过它来设置scrollView的偏移的。

    我们从上面的代码能够看到每当我们调用到setContentOffset()时,仅仅要_delegate这个变量不为空。那么都会调用以下这行代码:

    _delegate->scrollViewDidScroll(this);
    没错。ScrollView就是在这里调用到ScrollViewDelegate托付类中声明的函数scrollViewDidScroll,它的參数 this 也就是ScrollView这个类所指向的对象啦,我在这里就不多做解释啦。

    知道了上面这些,接下来就好办了。我们仅仅要知道在ScrollView中哪里有调用到setContentOffset() 这个函数就能够了

    4、我往下搜索 setContentOffset 这个关键词。发现有在好几个地方调用到,当中最关键的还是在onTouchMoved()这个触摸回调函数中使用到。
    onTouchMoved我也不用再多说了。每当我们触摸屏幕拖动时都会响应该函数。以下看下它的缩减版代码:
    void ScrollView::onTouchMoved(Touch* touch, Event* event)
    {
        if (!this->isVisible())
        {
            return;
        }
    
        if (std::find(_touches.begin(), _touches.end(), touch) != _touches.end())
        {
            if (_touches.size() == 1 && _dragging)
            { // scrolling
                ...
                
                if (frame.containsPoint(this->convertToWorldSpace(newPoint)))
                {
                    ...
                    this->setContentOffset(Point(newX, newY));//在这里调用到
                }
            }
            else if (_touches.size() == 2 && !_dragging)
            {
                const float len = _container->convertTouchToNodeSpace(_touches[0]).getDistance(
                                                _container->convertTouchToNodeSpace(_touches[1]));
                this->setZoomScale(this->getZoomScale()*len/_touchLength);//这里是调用与缩放相关的函数
            }
        }
    }

    5、好了,讲到这里一切都已经開始变得清晰了!

    如今我先整理下发型,然后简短的做个总结。
    1) 首先在scrollView拖动过程中都会调用onTouchMoved()函数,然后再该函数中调用到到setContainOffset()这个函数,这个函数就是用来设置它的偏移位置的。
    2) 在setContainOffset() 会调用到_delegate中的 scrollViewDidScroll()函数。
    3) 为什么_delegate能有这么大的权力调用ScrollViewDelegate中的函数呢?原因就在于它是ScrollViewDelegate声明的,说直接点它就是ScrollViewDelegate的私生子!

    !!



    6、以下我举个样例吧。

    我先声明一个叫CoolStar的类,

    class CoolStar : public Layer,public ScrollViewDelegate
    {
    public:
    	...
    	bool init();
    	CREATE_FUNC(CoolStar);
    	...	
    	//scroll 托付
    	void scrollViewDidScroll(MyScrollView* view);
    	void scrollViewDidZoom(MyScrollView* view);
    }
    CoolStar为什么要继承ScrollViewDelegate呢?别急。往下看init()函数的定义。

    bool CoolStar::init() { auto scroll_layer = Layer::create(); ... auto m_scroll = ScrollView::create(Size(...),scroll_layer); m_scroll->setDelegate(this);//看这里!

    return true; }


    上面我创建了一个scrollView,然后设置scrollView的托付指向当前类的对象,也就是this(看凝视的地方)
    而我们知道setDelegate()这个函数是有參数的,它的參数是一个指向ScrollViewDelegate托付类的指针。 例如以下:
    void setDelegate(ScrollViewDelegate* pDelegate)。
    这就要求我们创建ScrollView的这个类必须是继承与ScrollViewDelegate。否则你就无法如此洒脱的执行以下这步了:
    m_scroll->setDelegate(this);
    恩。如今应该知道为什么CoolStar这个类为什么要继承与ScrollViewDelegate托付类了吧。
    接下来定义两个scrollView的托付函数:
    void CoolStar::scrollViewDidScroll(MyScrollView* view)
    {
    	CCLOG("star is so cool");
    }
    void CoolStar::scrollViewDidZoom(MyScrollView* view)
    {
    }

    执行程序。发现每次拖动scrollView时控制台都会输出 "star is so cool"这串字符串。


    附:本文參加了CSDN博客大赛,亲假设认为这篇文章不错。就大胆的来投上一票吧!!!

    http://vote.blog.csdn.net/Article/Details?articleid=34140469


    尊重原创,转载请注明来源:http://blog.csdn.net/star530/article/details/34140469

  • 相关阅读:
    20200209 ZooKeeper 3. Zookeeper内部原理
    20200209 ZooKeeper 2. Zookeeper本地模式安装
    20200209 Zookeeper 1. Zookeeper入门
    20200206 尚硅谷Docker【归档】
    20200206 Docker 8. 本地镜像发布到阿里云
    20200206 Docker 7. Docker常用安装
    20200206 Docker 6. DockerFile解析
    20200206 Docker 5. Docker容器数据卷
    20200206 Docker 4. Docker 镜像
    Combining STDP and Reward-Modulated STDP in Deep Convolutional Spiking Neural Networks for Digit Recognition
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7058535.html
Copyright © 2011-2022 走看看