Using Layout manager to position and center UI components

Basically Im trying to create a simple styled message box with its text and buttons centered.

var ExitGameLayer = cc.Layer.extend({
	_mainLayout: null,
	_yesCallBack: null,
	_noCallBack: null,
   ctor: function(yesCallBack, noCallBack) {
        this._super();
		
		var winSize = cc.winSize;
		
		this._mainLayout = new ccui.Layout();
		this._mainLayout.setLayoutType(ccui.Layout.RELATIVE);
		//this._mainLayout.setPosition(0, 0);
		this._mainLayout.setPosition(winSize.width / 2 - (1029/2), winSize.height / 2 -( 696/2 ));
		//this._mainLayout.setContentSize(winSize.width, winSize.height);
		this._mainLayout.setContentSize(1029, 696);
		this._mainLayout.setBackGroundImage(res.Popup_png);
		this.addChild(this._mainLayout);
		
		this._yesCallBack = yesCallBack;
		this._noCallBack = noCallBack;
    },
	onEnter: function() {
        this._super();
		
		var message = new ccui.Text("Quit the game?", _b_getFontName(res.Bombing_ttf), 200);
		message.setColor(cc.color.BLACK);
		var rlp1 = new ccui.RelativeLayoutParameter();
		rlp1.setRelativeName("message");
		rlp1.setAlign(ccui.RelativeLayoutParameter.CENTER_IN_PARENT);
		message.setLayoutParameter(rlp1);	
				
		var yesButton = new ccui.Button(res.YesButton_png);
        //startButton.setTitleText(stringRes.Start);
        //startButton.setTitleColor(cc.color.WHITE);
        //startButton.setTitleFontName(_b_getFontName(res.Bombing_ttf));
        //startButton.setTitleFontSize(100);
        yesButton.addTouchEventListener(this._yesButtonClicked, this);
        var rlp2 = new ccui.RelativeLayoutParameter();
		rlp2.setRelativeToWidgetName("message");
        rlp2.setAlign(ccui.RelativeLayoutParameter.LOCATION_BELOW_LEFTALIGN);
        //rlp2.setMargin(20, 0, 0, 50);
        yesButton.setLayoutParameter(rlp2);
		
        var noButton = new ccui.Button(res.NoButton_png);
        //startButton.setTitleText(stringRes.Start);
        //startButton.setTitleColor(cc.color.WHITE);
        //startButton.setTitleFontName(_b_getFontName(res.Bombing_ttf));
        //startButton.setTitleFontSize(100);
        noButton.addTouchEventListener(this._noButtonClicked, this);
        var rlp3 = new ccui.RelativeLayoutParameter();
		rlp3.setRelativeToWidgetName("message");
        rlp3.setAlign(ccui.RelativeLayoutParameter.LOCATION_BELOW_RIGHTALIGN);
        //rlp3.setMargin(0, 0, 20, 50);
        noButton.setLayoutParameter(rlp3);     

		this._mainLayout.addChild(message);
		this._mainLayout.addChild(yesButton);
		this._mainLayout.addChild(noButton);
	},
	close: function() {
        this.parent.removeChild(this);
    },
    _noButtonClicked: function() {
        if(this._noCallBack)
            this._noCallBack();
        this.close();
    },
    _yesButtonClicked: function() {
        if(this._yesCallBack)
            this._yesCallBack();
    }
});

This produces:

As you can see the Quit The Game? text is centered but the buttons arent, and yes I know why that is ( due to the RelativeLayoutParameters I am providing), but Ive tried everything and just cant get both the text and the buttons to be centered as a whole - if that makes sense? Any help would be greatly appreciated.

I have been using the api docs and trawling through the javascript to learn how to use everything so I might be missing something fairly obvious, as I find cocos2d js cant really nest layouts easily, because you need to provide sizes and positions for them which kind of defeats the purpose IMO - or at least when comparing to other LayoutManagers for example in Java Swing. Otherwise great tool I’m enjoying working with it :slight_smile: .

Thanks in advance

I am not sure as I don’t use layouts.

What I do instead is layout according to the size of the parent or another node

parent / 2 is then center
parent / 4 is on the left
etc.

You could also use the size and position of the quit game label to then decide where to place the buttons. Just a thought.

1 Like

@slackmoehrle Thanks mate, Ive thought about going absolute lol, but yeah, having Layouts work nicely will help in cases like creating more complex stuff UIs.

With that said if by tomorrow there are no other suggestions or solutions I will have a go at what you are saying.

Fixed using an absolute layout as suggested by @slackmoehrle!

var ExitGameLayer = cc.Layer.extend({
   _mainLayout: null,
   _yesCallBack: null,
   _noCallBack: null,
   _backgroundLeftInset: 26, // the pop up image doesnt completely fill the actualy png so we hardcode insets to center ui components
   _backgroundRightInset: 24,
   _width: 1029, // should be calculated as assets folder can change and this will be invalid
   _height: 696,
  ctor: function(yesCallBack, noCallBack) {
       this._super();
   	
   	var winSize = cc.winSize;
   	
   	this._mainLayout = new ccui.Layout();
   	this._mainLayout.setLayoutType(ccui.Layout.ABSOLUTE);
   	this._mainLayout.setPosition((winSize.width / 2) - (this._width / 2), (winSize.height / 2) - ( this._height / 2));
   	this._mainLayout.setContentSize(this._width, this._height);
   	this._mainLayout.setBackGroundImage(res.Popup_png);
   	this.addChild(this._mainLayout);
   	
   	this._yesCallBack = yesCallBack;
   	this._noCallBack = noCallBack;
   },
   onEnter: function() {
       this._super();
   	
   	var message = new ccui.Text(stringRes.Quit, _b_getFontName(res.Bombing_ttf), sizeRes.TextLarge);
   	message.setPosition((this._width / 2), (this._height / 2) + (message.height / 2) + sizeRes.Padding);
   	var lp1 = new ccui.LayoutParameter();
   	message.setLayoutParameter(lp1);				
   	message.setColor(cc.color.BLACK);		
   	
   	var yesButton = new ccui.Button(res.YesButton_png);
       yesButton.addTouchEventListener(this._yesButtonClicked, this);
   	yesButton.setPosition((this._width / 2) - ((yesButton.width - this._backgroundLeftInset) - sizeRes.Padding), (this._height / 2) - (yesButton.height / 2) - sizeRes.Padding);
   	var lp2 = new ccui.LayoutParameter();
   	yesButton.setLayoutParameter(lp2);	
   	
   	var noButton = new ccui.Button(res.NoButton_png);
       noButton.addTouchEventListener(this._noButtonClicked, this);
   	noButton.setPosition((this._width / 2) + ((noButton.width - this._backgroundRightInset) - sizeRes.Padding), (this._height / 2) - (noButton.height / 2) - sizeRes.Padding);
   	var lp3 = new ccui.LayoutParameter();
   	noButton.setLayoutParameter(lp3);	
   	
   	this._mainLayout.addChild(message);
   	this._mainLayout.addChild(yesButton);
   	this._mainLayout.addChild(noButton);
   },
   close: function() {
       this.parent.removeChild(this);
   },
   _noButtonClicked: function() {
       this.close();
       if (this._noCallBack)
           this._noCallBack();
   },
   _yesButtonClicked: function() {
       this.close();
       if (this._yesCallBack)
           this._yesCallBack();
   }
});

Awesome! Thanks for asking a clear question and providing code and an image to help us understand.

1 Like