zoukankan      html  css  js  c++  java
  • [cocos2dx] 让UIButton支持disable状态

    摘要: 主要解决cocos2dx-2.2.2版本中, UIButton显示不了disable状态图的问题. 顺便, 理解了一下cocos2dx中UIWidget的渲染原理.



    发现问题

    enter image description here
    在cocostudio中添加一个UIButton组件, 我们可以看到通常以一下按钮的三态:normal,pressed,disable. 但是,当我们设置了disable状态之后, 在我们的游戏项目中, 对某个按钮执行button->setEnable(false)后, 按钮居然完全不见了?!

    解决方法

    1. 修改Widget::visit()方法, 改为:

      void Widget::visit()
      {
          CCNodeRGBA::visit();
      }

      即, 删除if判断.

    2. 修改Widget::setEnable()方法, 改为:

      void Widget::setEnabled(bool enabled)
      {
          _enabled = enabled;
          if(_widgetChildren && _widgetChildren->count() > 0)
          {
              CCObject* child;
              CCARRAY_FOREACH(_widgetChildren, child)
              {
                  ((Widget*)child)->setEnabled(enabled);
              }
          }
          setBright( enabled );//增加此行
      }

      即, 增加setBright( enabled );行.

    如果想知其所以然的, 下面是解释.

    解释

    Widget的诡异渲染

    Widget::visit()的实现如下:

    void Widget::visit()
    {
        if (_enabled)
        {
            CCNodeRGBA::visit();
        }    
    }

    如果您没时间仔细看过cocos2dx的源码, 这里可以有一个简单的解释:
    1. visit()方法最初是从CCNode继承过来的. 也就是说任何显示对象都有这个方法.
    2. CCNode::visit()就是CCNode的渲染函数, 是视图渲染中最重要的一个函数, 跟IOS开发中的UIView::draw()功能类似. 框架在每一帧都会调用这个方法, 而这个方法负责当前组件的openGL绘制. 我们可以看下CCNode::visit()的实现来作为验证:

    void CCNode::visit()
    {
        ...
        this->draw();
        ...
    }
    //算了, 这段代码有点长, 有些人时间比较宝贵可能没兴趣看. 我就放在***附录***了.(*^__^*)

    看到这里, 你肯定一经发现问题了: 为什么只有在_enabledtrue的时候才渲染?难道不是坑爹么?disable状态就不理了么?
    可能cocos2dx另有打算, 我没理解清楚. 不过这个功能既然不符合我的要求, 我就果断的把那个if去掉了. (谁让咱们是程序员呢?).

    但是, 问题并没有完全结束. 还是没有显示disable状态.

    Widget的enable?

    UIButton::setEnable()方法比较短, 贴出来看看.

    void Widget::setEnabled(bool enabled)
    {
        _enabled = enabled;
        if(_widgetChildren && _widgetChildren->count() > 0)
        {
            CCObject* child;
            CCARRAY_FOREACH(_widgetChildren, child)
            {
                ((Widget*)child)->setEnabled(enabled);
            }
        }
    }

    发现这段代码除了把_enable和所有孩子的_enable状态设为false, 没做任何事情. 通过查看widget的代码, 很容易看到, widget的三态是通过下面的是三个函数实现的:

    void Widget::onPressStateChangedToNormal(){}
    void Widget::onPressStateChangedToPressed(){}
    void Widget::onPressStateChangedToDisabled(){}

    不错,他们都是空函数.子类根据需要来实现这三个函数.
    下面是setBright的实现:

    void Widget::setBright(bool bright)
    {
        _bright = bright;
        if (_bright)
        {
            _brightStyle = BRIGHT_NONE;
            setBrightStyle(BRIGHT_NORMAL);
        }
        else
        {
            onPressStateChangedToDisabled();
        }
    }

    由上代码可以看出. 而我们调用setBright(false), 即可根据widget当前的状态, 渲染不同的图像.

    附录

    代码片段一CCNode::visit()

    void CCNode::visit()
    {
        // quick return if not visible. children won't be drawn.
        if (!m_bVisible)
        {
            return;
        }
        kmGLPushMatrix();
    
         if (m_pGrid && m_pGrid->isActive())
         {
             m_pGrid->beforeDraw();
         }
    
        this->transform();
    
        CCNode* pNode = NULL;
        unsigned int i = 0;
    
        if(m_pChildren && m_pChildren->count() > 0)
        {
            sortAllChildren();
            // draw children zOrder < 0
            ccArray *arrayData = m_pChildren->data;
            for( ; i < arrayData->num; i++ )
            {
                pNode = (CCNode*) arrayData->arr[i];
    
                if ( pNode && pNode->m_nZOrder < 0 ) 
                {
                    pNode->visit();
                }
                else
                {
                    break;
                }
            }
            // self draw
            this->draw();
    
            for( ; i < arrayData->num; i++ )
            {
                pNode = (CCNode*) arrayData->arr[i];
                if (pNode)
                {
                    pNode->visit();
                }
            }        
        }
        else
        {
            this->draw();
        }
    
        // reset for next frame
        m_uOrderOfArrival = 0;
    
         if (m_pGrid && m_pGrid->isActive())
         {
             m_pGrid->afterDraw(this);
        }
    
        kmGLPopMatrix();
    }

    Written with StackEdit.

  • 相关阅读:
    Qt刷新机制的一些总结(Qt内部画的时候是相当于画在后台一个对象里,然后在刷新的时候调用bitblt统一画,调用window的api并不会影响到后面的那个对象)
    delphi中formatFloat代码初探(在qt下实现floatformat的函数)
    Qt中如何写一个model(自定义一个RowNode,我没有碰到过)
    DNN简介以及安装
    理解C# 4 dynamic(4) – 让人惊艳的Clay
    C#基础知识系列八(const和readonly关键字)
    ASP.NET MVC 5 -从控制器访问数据模型
    随机数的算法
    c#拷贝
    MVC UnitOfWork EntityFramework架构
  • 原文地址:https://www.cnblogs.com/jhzhu/p/3619722.html
Copyright © 2011-2022 走看看