Design and Implementation of pop-up dialog box for cocos2d-x3.x

Source: Internet
Author: User

Design and Implementation of pop-up dialog box for cocos2d-x3.x

First define a class PopupLayer


Code PopupLayer. h


# Ifndef _ crossDT_PopupLayer __# define _ crossDT_PopupLayer __# include "cocos2d. h "# include" cocos-ext.h "USING_NS_CC; using namespace cocos2d: extension; class PopupLayer: public Layer {public: PopupLayer ();~ PopupLayer (); virtual bool init (); CREATE_FUNC (PopupLayer); // virtual void registerWithTouchDispatcher (void); bool onTouchBegan (Touch * touch, Event * unused_event ); static PopupLayer * create (const char * backgroundImage); void setTitle (const char * title, int fontsize = 20); void setContentText (const char * text, int fontsize = 20, int padding = 50, int paddintTop = 100); void setCallbackFunc (Object * target, SEL_CallFuncN callfun); bool addButton (const char * normalImage, const char * selectedImage, const char * title, int tag = 0); virtual void onEnter (); virtual void onExit (); private: void buttonCallback (CCObject * pSender); // The blank area int m_contentPadding on both sides of the text content; int m_contentPaddingTop; CCObject * m_callbackListener; SEL_CallFuncN m_callback; menus (Menu *, m _ pMenu, MenuButton); sums (Sprite *, m _ sfBackGround, SpriteBackGround ); vertex (Scale9Sprite *, m _ s9BackGround, Sprite9BackGround); CC_SYNTHESIZE_RETAIN (LabelTTF *, m _ ltTitle, LabelTitle); vertex (LabelTTF *, m _ ltContentText, labelContentText) ;};# endif


Code in PopupLayer. cpp

# Include "PopupLayer. h "PopupLayer: PopupLayer (): m _ pMenu (NULL), m_contentPadding (0), m_contentPaddingTop (0), m_callbackListener (NULL), m_callback (NULL ), m _ sfBackGround (NULL), m _ s9BackGround (NULL), m _ ltContentText (NULL), m _ ltTitle (NULL) {} PopupLayer ::~ PopupLayer () {CC_SAFE_RELEASE (m _ pMenu); CC_SAFE_RELEASE (m _ sfBackGround); CC_SAFE_RELEASE (m _ ltContentText); CC_SAFE_RELEASE (m _ ltTitle ); CC_SAFE_RELEASE (m _ s9BackGround);} bool PopupLayer: init () {if (! Layer: init () {return false;} this-> setContentSize (CCSizeZero); // initialize the required Menu CCMenu * menu = CCMenu: create (); menu-> setPosition (CCPointZero); setMenuButton (menu); setTouchEnabled (true); return true;} bool PopupLayer: onTouchBegan (cocos2d: CCTouch * pTouch, cocos2d :: CCEvent * pEvent) {// CCLog ("PopupLayer touch"); return true;} PopupLayer * PopupLayer: create (const char * backgroundImage) {PopupLayer * ml = PopupLayer :: create (); ml-> setSpriteBackGround (CCSprite: create (backgroundImage); ml-> setSprite9BackGround (Scale9Sprite: create (backgroundImage); return ml;} void PopupLayer :: setTitle (const char * title, int fontsize) {CCLabelTTF * ltfTitle = CCLabelTTF: create (title, "", fontsize); setLabelTitle (ltfTitle);} void PopupLayer :: setContentText (const char * text, int fontsize, int padding, int paddingTop) {CCLabelTTF * ltf = CCLabelTTF: create (text, "", fontsize); setLabelContentText (ltf ); m_contentPadding = padding; encoding = paddingTop;} void PopupLayer: setCallbackFunc (cocos2d: CCObject * target, callback callfun) {m_callbackListener = target; m_callback = callfun;} bool PopupLayer :: addButton (const char * normalImage, const char * selectedImage, const char * title, int tag) {CCSize winSize = CCDirector: sharedDirector ()-> getWinSize (); CCPoint pCenter = ccp (winSize. width/2, winSize. height/2); // create Image menu button CCMenuItemImage * menuImage = CCMenuItemImage: create (normalImage, selectedImage, this, menu_selector (PopupLayer: buttonCallback )); menuImage-> setTag (tag); menuImage-> setPosition (pCenter); // Add text instructions and set the position CCSize imenu = menuImage-> getContentSize (); CCLabelTTF * ttf = CCLabelTTF:: create (title, "", 20); ttf-> setColor (ccc3 (0, 0, 0); ttf-> setPosition (ccp (imenu. width/2, imenu. height/2); menuImage-> addChild (ttf); getMenuButton ()-> addChild (menuImage); return true;} void PopupLayer: buttonCallback (cocos2d :: CCObject * pSender) {CCNode * node = dynamic_cast
 
  
(PSender); CCLog ("touch tag: % d", node-> getTag (); if (m_callback & m_callbackListener) {(m_callbackListener-> * m_callback) (node);} this-> removeFromParent ();} void PopupLayer: onEnter () {CCLayer: onEnter (); CCSize winSize = CCDirector: shareddire () -> getWinSize (); CCPoint pCenter = ccp (winSize. width/2, winSize. height/2); CCSize contentSize; // set the parameter and load if (getContentSize () at runtime (). equals (CCSizeZero) {getSpriteBackGround ()-> setPosition (ccp (winSize. width/2, winSize. height/2); this-> addChild (getSpriteBackGround (), 0, 0); contentSize = getSpriteBackGround ()-> getTexture ()-> getContentSize ();} else {Scale9Sprite * background = getSprite9BackGround (); background-> setContentSize (getContentSize (); background-> setPosition (ccp (winSize. width/2, winSize. height/2); this-> addChild (background, 0, 0); contentSize = getContentSize () ;}// Add button, and set its location this-> addChild (getMenuButton (); float btnWidth = contentSize. width/(getMenuButton ()-> getChildrenCount () + 1); Vector
  
   
VecArray = getMenuButton ()-> getChildren (); CCObject * pObj = NULL; int I = 0; for (auto & e: vecArray) {CCNode * node = dynamic_cast
   
    
(E); node-> setPosition (Point (winSize. width/2-contentSize. width/2 + btnWidth * (I + 1), winSize. height/2-contentSize.height/3); I ++;}/* CCARRAY_FOREACH (array, pObj) {CCNode * node = dynamic_cast
    
     
(PObj); node-> setPosition (ccp (winSize. width/2-contentSize. width/2 + btnWidth * (I + 1), winSize. height/2-contentSize. height/3); I ++;} * // display the dialog box title if (getLabelTitle () {getLabelTitle ()-> setPosition (ccpAdd (pCenter, ccp (0, contentSize. height/2-35366f); this-> addChild (getLabelTitle ();} // display the text content if (getLabelContentText () {CCLabelTTF * ltf = getLabelContentText (); ltf-> setPosition (ccp (winSize. width/2, winSize. height/2); ltf-> setDimensions (CCSizeMake (contentSize. width-m_contentPadding * 2, contentSize. height-m_contentPaddingTop); ltf-> setHorizontalAlignment (kCCTextAlignmentLeft); this-> addChild (ltf);} // The displayed CCAction * popupLayer = CCSequence: create (CCScaleTo :: create (0.0, 0.0), CCScaleTo: create (0.06, 1.05), CCScaleTo: create (0.08, 0.95), CCScaleTo: create (0.08, 1.0), NULL ); this-> runAction (popupLayer);} void PopupLayer: onExit () {CCLog ("popup on exit. "); CCLayer: onExit ();}
    
   
  
 


Add

# Include "HelloWorldScene. h "# include" PopupLayer. h "USING_NS_CC; Scene * HelloWorld: createScene () {// 'Scene 'is an autorelease object auto scene = scene: create (); // 'player' is an autorelease object auto layer = HelloWorld: create (); // add layer as a child to scene-> addChild (layer ); // return the scene return scene;} // on "init" you need to initialize your instancebool HelloWorld: init (){// /// // 1. super init first if (! Layer: init () {return false;} CCSize winSize = CCDirector: sharedDirector ()-> getWinSize (); CCPoint pointCenter = ccp (winSize. width/2, winSize. height/2); // Add a background image/* CCSprite * background = CCSprite: create ("HelloWorld.png"); background-> setPosition (pointCenter ); background-> setScale (1.5f); this-> addChild (background); * // popupLayer (); // Add menu CCMenu * menu = CCMenu: create (); CCMenuItemFont * MenuItem = CCMenuItemFont: create ("popup", this, menu_selector (HelloWorld: menuCallback); menuItem-> setPosition (ccp (winSize. width/2, winSize. height/2); menuItem-> setColor (ccc3 (255, 0, 0); menu-> addChild (menuItem); menu-> setPosition (CCPointZero ); this-> addChild (menu); return true;} void HelloWorld: popupLayer () {// define a pop-up layer and input a background image PopupLayer * pl = PopupLayer :: create ("popuplayer/BackGround.png "); // ContentSize is an optional setting and can be left unspecified. If it is set as a 9-chart scale pl-> setContentSize (CCSizeMake (400,350 )); pl-> setTitle ("My name and one leaf"); pl-> setContentText. If you don't want to see the flowers and flowers, you will find a different fragrance. ", 20, 60,250); // sets the callback function. The callback returns a CCNode to get the button clicked for tag judgment. // This is only implemented as an encapsulation, if delegate is used, you can control the parameters more flexibly. pl-> setCallbackFunc (this, callfuncN_selector (HelloWorld: buttonCallback); // Add the button and set the image and text, tag Information pl-> addButton ("popuplayer/pop_button.png", "popuplayer/pop_button.png", "OK", 0); pl-> addButton ("popuplayer/pop_button.png ", "popuplayer/pop_button.png", "cancel", 1); // Add to current layer this-> addChild (pl);} void HelloWorld: menuCallback (cocos2d :: object * pSender) {popupLayer ();} void HelloWorld: buttonCallback (cocos2d: Node * pNode) {CCLog ("button call back. tag: % d ", pNode-> getTag ());}


Below is the code reprinted on the Internet, the code inside the cocos2d-x2.x, there are some modifications

We often need such functions to bring up a layer and give some prompts to the user. This is also a modal window. When the current dialog box is not confirmed, we cannot continue to operate on it. How can we design such functions reasonably ~ This is the question to be discussed in this article. One leaf does not tend to provide a complete solution and a bunch of source code. Instead, we will tell you how to perfect it based on your own needs, and how to teach people to fish instead of to fish ~

Function Analysis

Let's design a dialog box with several buttons (customizable number). Of course, there is a title that will let others see its function at a glance. There are some detailed prompt text in it, it must be a modal window, and the window size is variable, so as to better adapt to different screen sizes. Of course, there is also an important function, with the pop-up effect ~ Although the implementation is not difficult or simple from a technical point of view, it will be presented to users with a good user experience.

In terms of usage, I try to make the interface design as concise and easy to use as possible, as shown below. As for the internal implementation, it is free to use. The interface functions are exposed and used by others, so first define it as needed, which will clarify your implementation steps (the source code used in this article can be obtained from here ):

Class PopupLayer: public CCLayer {public: PopupLayer ();~ PopupLayer (); virtual bool init (); CREATE_FUNC (PopupLayer); // you need to rewrite the touch registration function to respecify the virtual void registerWithTouchDispatcher (void) at the touch level. // rewrite the touch function, returns true forever, shields other layers, and achieves the "Modal" effect bool ccTouchBegan (cocos2d: CCTouch * pTouch, cocos2d: CCEvent * pEvent); // architecture, and set the dialog box background image static PopupLayer * create (const char * backgroundImage); // It can display the title, and set the display text size void setTitle (const char * title, int fontsize = 20); // text content, padding is the distance reserved for text to both sides of the dialog box. This is controllable, and the distance from the top is also void setContentText (const char * text, int fontsize = 20, int padding = 50, int paddintTop = 100); // callback function. When you click the button, we close the colleagues at the pop-up layer and need a callback function, to notify us which button we have clicked (if there are multiple) void setCallbackFunc (CCObject * target, SEL_CallFuncN callfun); // to add the button, a function is encapsulated, input necessary parameters bool addButton (const char * normalImage, const char * selectedImage, const char * title, int tag = 0 ); // In order to make the attribute take effect before the display layer, choose to dynamically display virtual void onEnter (); virtual void onExit ();} In onEnter ();};

In terms of usage, the above functions are defined for external calls to fulfill basic functional requirements. Of course there are also some hidden functions, such as setContentSize. Start our next design ~

OnEnter dynamic build pop-up layer

As mentioned above, the size of the modal window is variable and can be obtained through ContentSize. If ContentSize is not set, the window size is as large as that of the input image, set the window size to the specified size. We know that there are many attribute settings like this, and there are two ways to complete such a function.

First, real-time settings and real-time refresh, such as instatic PopupLayer* create(const char* gackgroundImage)Create an genie, set the image, and add it to the current layer.setContentSizeAfter obtaining the genie through this method, we can modify the size of the genie (obviously, the setContentSize method is not implemented in this article, but it does not affect the description ).

Second, keep attributes and dynamically build them. Such an implementation is instatic PopupLayer* create(const char* gackgroundImage)Internally, only the image name is saved, whilesetContentSizeYou can also focus only on your own work. Finally, in an appropriate execution period, based on the above two parameters, the dynamic creation of the requested genie, and this operation is particularly appropriate in onEnter.

Another example is used to illustrate the difference between real-time refresh and dynamic build. The definition contains an addButton method. How many buttons can be added to the current dialog box? Of course, they are not sure, but they are determined that their positions vary with the number of buttons. If a button is displayed in the center (divided into two parts ), if there are two (triplicate distance) and real-time refresh, we need to create a new button in each addButton method and set the correct position, of course, when setting a new position, you need to determine whether a button already exists and modify the position of the button before q. it is foreseeable that each time you add a button, you need to refresh the previously set values in real time. If the code logic is simple and good, if the logic is very complex and there are many dependency attributes, it will be difficult to control. If dynamic formation is used, in addButton, we only need to use a set (similar mechanism) to save all the button information. That's all, and then read the information in onEnter, add buttons to the interface in real time. When running the button, the attribute is basically determined (the number of buttons here ). You only need to calculate the positions of each button at a time, so the logic processing is quite clear ~

It can be said that dynamic build is definitely better than real-time refresh? Of course not. An example of using real-time Refresh: using a real-time refresh solution in the CCControl framework of the Cocos2d-x can be seen in many places likeneedsLayout()After setting a property of a control, you must update the layout of the control based on the property.

The real-time refresh and dynamic build methods need to be selected based on the actual situation to simplify our development. In the text, they are basically designed in the form of dynamic build, because all the attributes are determined when the pop-up layer is running, and there is no need to refresh the attributes in real time.

The Touch priority of the pop-up layer. The operation is consistent with the display.

-128 is a meaningful number, which is the default touch level of CCMenu. If we do not use the built-in menu items, we can handle the touch level issues well, just a slightly larger value. However, you need to write the button for implementation. Of course, the use of CCMenu is also advantageous, it encapsulates a very useful click operation. To simplify development, we use CCMenu as the button for the dialog box. So how many touch levels should we set for the pop-up layer?

When setting the touch level, remember one sentence and the operation is consistent with the display. Why? Now, we assume that, in order to block operations on all layers outside the pop-up layer, we set the pop-up layer level to-129, in this way, it is ensured that it is modal (in general, except for the CCMenu level, user-defined does not need to be so large ), however, if there are other layers above the current pop-up layer (or other layers above the parent node of the pop-up layer, such as multi-layer UI design), and The CCMenu button is also available, the CCMenu button displayed on the pop-up layer cannot be clicked. This is not scientific! Actually, the CCMenu in the pop-up layer cannot be clicked, but we can solve this problem by passing the touch message of the pop-up layer to the CCMenu in the layer. Therefore, it is not advisable to blindly pursue the highest touch priority. It cannot perform the same operations as the display, but the priority smaller than CCMenu cannot shield other CCMenu operations below, therefore, for the pop-up layer itself, it is reasonable to set it to-128. For these elements of the same level (the pop-up layer and CCMenu), this can be done, and the display is prioritized at the top. If there is a layer above the pop-up layer, you can click it. Why not! What we need to do is to use logical control to bring up layer nodes and add them to the top of the scenario.

For a solution that is consistent with the operation and display, you can refer to the other two articles in one leaf, lightweight design of multi-layer UI touch events, and CCScrollView to achieve the help interface and level selection. Of course, CCMenu is not used, but a set of rules is created independently.

Implementation Scheme of callback Functions

Because we use CCMenu as the button, we can pass in the callback function of CCMenu as a parameter. This process is really simple, but another problem is that after the event is processed, close the current layer, so this is not the case. You need to encapsulate it further, set the button callback function of the pop-up layer to an internal implementation, and then at the upper layer of the callback to it, close the dialog box later (the closed operation is completed by the dialog box layer). There are two methods for callback, one isdelegateCallback. You need to define the interface, which is inherited from the upper layer to implement the interface, and pass in the pop-up layer as a parameter. The pop-up layer calls the delegate Interface Method for implementation, this method is used in many places in the Cocos2d-x. The other is function binding, just like CCMenu.

Here, one leaf selects the latter. If one or two buttons are fixed in the current pop-up layer, I will use delegate to implement function callback, which will make the callback steps clearer. However, the design here is that the number of buttons is variable, and the functions are also different. Use the callback function, bind the CCNode parameter, and mark it with its tag. Which button is clicked, of course, this does not mean that using that method is absolutely good or bad. Delegate is more rigorous in parameter transmission.void setCallbackFunc(CCObject* target, SEL_CallFuncN callfun);The definition is similar to the callback mechanism of CCMenu. A CCNode is used as a parameter and Its tag is used to indicate which button is currently clicked.

Call at the pop-up layer
Void Popup: popupLayer () {// define a pop-up layer and input a background image PopupLayer * pl = PopupLayer: create ("popuplayer/BackGround.png "); // ContentSize is an optional setting and can be left unspecified. If it is set as a 9-chart scale pl-> setContentSize (CCSizeMake (400,350 )); pl-> setTitle ("My name and one leaf"); pl-> setContentText. If you don't want to see the flowers and flowers, you will find a different fragrance. ", 20, 60,250); // sets the callback function. The callback returns a CCNode to get the button clicked for tag judgment. // This is only implemented as an encapsulation, if delegate is used, you can control the parameters more flexibly. pl-> setCallbackFunc (this, callfuncN_selector (Popup: buttonCallback); // Add the button and set the image and text, tag Information pl-> addButton ("popuplayer/pop_button.png", "popuplayer/pop_button.png", "OK", 0); pl-> addButton ("popuplayer/pop_button.png ", "popuplayer/pop_button.png", "cancel", 1); // Add to current layer this-> addChild (pl);} void Popup: buttonCallback (cocos2d :: CCNode * pNode) {// print tag 0, OK, 1, cancel CCLog ("button call back. tag: % d ", pNode-> getTag ();} // the key code is displayed. The current layer executes the CCAction * popupLayer = CCSequence: create (CCScaleTo :: create (0.0, 0.0), CCScaleTo: create (0.06, 1.05), CCScaleTo: create (0.08, 0.95), CCScaleTo: create (0.08, 1.0), NULL );

Here, the popup button is a CCMenu, the two buttons in the pop-up layer are also CCMenu, And the touch priority level of the layer itself is-128, which is the same level, so as to say, the operation is consistent with the display. The only thing to note is the logic control. When is the pop-up layer and the node pop-up layer (generally the scenario grass-roots layer is responsible ), to ensure that it is displayed at the top.

Through the above discussion and practice, the basic model of the dialog box is completed, which implements the following functions:

  • Implementation of a pop-up dialog box
  • Implementation of modal windows (logical control required)
  • Supports multiple buttons, adaptive positions, and callback Functions
  • Set title and content
  • SupportedFigure 9To control the size of the pop-up box.

    Of course, there are many other functions that are not taken care of, or are not perfect. This requires the user to expand and customize it. For example, such a layer should at least be a singleton, at any time, only one exists, which can be implemented in singleton mode. For the content of the pop-up layer, only the title and content are available, and the title is fixed, you can also set buttons more flexibly.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.