Closed Arvant closed 1 year ago
@Arvant have you seen the cpp-test example? Maybe you can comparing your implementation with this one first?
@Arvant have you seen the cpp-test example? Maybe you can comparing your implementation with this one first?
yes i see it. But this problem has been there for a long time in cocos2d
yes i see it. But this problem has been there for a long time in cocos2d
? What are you mean? Have you a link to this cocos2d issue too? Is the cpp-test example not working/usable for your example/situation?
yes i see it. But this problem has been there for a long time in cocos2d
? What are you mean? Have you a link to this cocos2d issue too? Is the cpp-test example not working/usable for your example/situation?
i early in cocos2d-x have this problem and I create custom tab for solve this. now i test above code in axmol and see the problem is exist too. this case not use in test project and you need to create simple project and insert my code in project.
this case not use in test project and you need to create simple project and insert my code in project.
Sprite::create("equipment/brown.png");
@Arvant can you provide a working example?);
this case not use in test project and you need to create simple project and insert my code in project.
Sprite::create("equipment/brown.png");
@Arvant can you provide a working example?);
yes I upload test. test repo
Remove this line:
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, layerColorPopup);
Remove this line:
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, layerColorPopup);
if you went to create popup you need this listener to Swallow touches.
Sorry I'm out. Your example works now. Thats was the challenge.
@Arvant Please close this issue. Thanks
If you're creating a popup with the tab control on it, then this line:
this->addChild(tab);
should be this:
layerColorPopup->addChild(tab);
This wouldn't be causing your issue though, since the touch event is hitting the layerColorPopup before it gets to the tab control, which is actually strange.
@Arvant Please close this issue. Thanks
The problem isn't solved, as there does seem to be some issue with how the touches are being handled.
Please provide an example. And please compare the cpp-test example with your implementation too.
Please provide an example. And please compare the cpp-test example with your implementation too.
The code provided by the OP, while a little messy and harder to follow, is actually the correct example.
This is the structure:
Scene
|-- PopupLayer
|--TabControl
|-- TabHeader1
|-- TabHeader2
|-- TabHeaderN... etc
The problem seems to be that the touch input is being received by the PopupLayer, then TabControl (Widget)/TabHeader (Widget), at least from what I can see in the output. From my understanding, the highest layers should be getting input before the lower layers, but that isn't what seems to be happening here.
When a touch event occurs, the method EventDispatcher::sortEventListenersOfSceneGraphPriority()
is eventually called to sort the event listeners. In here is where the problem first appears. The UIButton is first in the list, then the layerColorPopup
, then the HelloWorld
scene, then any tab control header widgets. This causes the button touch handler to be called first, then the layerColor, then the scene, and finally the tab header widgets. That is the reason why the button touch works, but the tab controls do not.
The tab control widgets should be higher up in priority, and ahead of the layerColorPopup
, but they are not. I am not sure why this is happening as of yet, and unfortunately I don't have any more time at the moment to look into it.
@Arvant Note, get rid of tab->setGlobalZOrder(44444);
from the example you provided, because that is not required, and just adds more confusion to the issue.
EDIT: I have a feeling that it has something to do with child nodes, and how they are added when they are children of Widget nodes. The addProtectedChild
that is used in Widgets adds child objects to a _protectedChildren
list, yet the sorting used by methods called from sortEventListenersOfSceneGraphPriority
use the _children
list. Since the protected child nodes are missing from the _children
list, they aren't included in the priority list. Take a look at EventDispatcher::visitTarget(Node* node, bool isRootNode)
to see what I am referring to.
@Arvant The reason the button can still be pressed is because it happens to be a child of the layerColorPopup
, added via addChild
, so it exists in the _children
list. The tab control itself is added via addChild
, but it's not actually what receives the touch input, as the TabHeader
widgets are the the ones that get the touch input, and they are added to the TabControl
via addProtectedChild
.
@Arvant There is a work-around for this, but you would need to be aware of a few things.
Let's say you create the following: Scene is at global Z of 0. Popup layer is at a global Z of 100 (arbitrary value, as long as it's greater than the scene global Z value).
When you create the popup, also create another layer (let's call it TouchBlockLayer) and give it a global Z of less than the popup layer (even 0), and add a touch event listener to it. Then, add this layer to the scene.
What happens now is that your popup will work as intended, but no touch events will propagate through the TouchBlockLayer to the scene below it.
So it will be like this:
Scene (globalZ = 0)
|-- TouchBlockLayer (globalZ = 0 to 99.9999 etc)
|-- PopupLayer (globalZ = 100)
|--Popup child (like tab control etc) (globalZ = 100)
What you need to look out for is that all children of the popup layer must be at the same or greater global Z values than the popup. It's best to just make them all the same as the popup global Z unless you have a specific reason not to.
This will work, as this is actually the method I use to achieve something like what you're trying to do. When you remove the popup, also remove the TouchBlockLayer.
@Arvant There is a work-around for this, but you would need to be aware of a few things.
Let's say you create the following: Scene is at global Z of 0. Popup layer is at a global Z of 100 (arbitrary value, as long as it's greater than the scene global Z value).
When you create the popup, also create another layer (let's call it TouchBlockLayer) and give it a global Z of less than the popup layer (even 0), and add a touch event listener to it. Then, add this layer to the scene.
What happens now is that your popup will work as intended, but no touch events will propagate through the TouchBlockLayer to the scene below it.
So it will be like this:
Scene (globalZ = 0) |-- TouchBlockLayer (globalZ = 0 to 99.9999 etc) |-- PopupLayer (globalZ = 100) |--Popup child (like tab control etc) (globalZ = 100)
What you need to look out for is that all children of the popup layer must be at the same or greater global Z values than the popup. It's best to just make them all the same as the popup global Z unless you have a specific reason not to.
This will work, as this is actually the method I use to achieve something like what you're trying to do. When you remove the popup, also remove the TouchBlockLayer.
rh101 I test this way before but it not work for me. I have forced to use layer and button to simulate tab control in popups. I have this problem in cocos2d-x 4 too. I debug cocos2d-x touch listener like you and see that it have problem in touch priority. I work with global Z order and fixed touch priority too but not work that.
@Arvant The method I described with global Z does in fact work, since I've been using it for years, but, it may not be ideal, since it requires tracking the global Z etc.
I think I've found a more reliable solution to this issue, and it seems to be working. A PR will be up soon. Even if the PR is not merged in, you can just merge in the changes with your own copy of the engine code. The changes are trivial.
@Arvant The PR #1224 is up. Merge it in to your own code to check if it works.
@Arvant The PR was simplified, as it is better to keep the functionality contained in EventDispatcher rather than add unnecessary functionality to Node and ProtectedNode.
@rh101 Thanks for this PR.
@rh101 it work perfect. Thanks for this PR.
@Arvant Please close this issue since the PR with the fix has been merged into the dev branch.
when I create a layer and add Tabcontrol to it. if set the layout listener setswallow to true and return true in touch began. the tab bar not work. but if add button to this layout the button work.
` auto listener = EventListenerTouchOneByOne::create(); listener->setSwallowTouches(true);
`