I would like to know how can I make a Tap & Hold action in cocos2d-iPhone buttons?
Are you using Sneaky Input for your joystick/button? their button class can be setup so that it functions as a toggle, or only active on press(ie tap and hold). its somewhere on git hub and may be worth a look.
Related
TL;DR: Is there any way to have custom button style (custom pressed state) in SwiftUI on tvOS while it is still working correctly with Accessibility Focus API and therefore its hasFocus works in UI tests?
Please visit dedicated Github repo for a longer version and a sample project with UI tests example.
What is the problem?
To create a custom button in SwiftUI on tvOS and can customize it based on pressed state, you can implement custom ButtonStyle.
Button(...)
.buttonStyle(AnyCustomButtonStyle())
and then use ButtonConfiguration.isPressed in the view.
However, I have found that although the button visually looks focused, it does not really report as Focused in Accessibility API. See the sample project for example and actual test showing the problem.
Among other problems, it makes the button quite difficult to work with in tvOS UI tests. tvOS is relying on focus for navigation and because the button's hasFocus always stays false (even if the button renders in focused appearance), it can prevent a lot of useful APIs to work in tests.
Why do you need custom ButtonStyle on tvOS?
I know Apple provides some custom PrimitiveButtonStyle implementations (like CardButtonStyle), but those don't provide enough flexibility. They all modify your button (e.g. add background).
Not being able to use custom buttonStyle makes it impossible to implement for example Capsule-style buttons like this...
First button focused
First button focused and pressed
Please let's leave aside the discussion if it is a good idea or not 😃 ... Just trying to find if there is a solution or if it is eventually a bug of SwiftUI.
What is the issue with Accessibility?
Without custom button, the button reports as Focused to Accessibility in UI tests.
Without custom style
(lldb) po app
Attributes: Application, 0x12ed10b30, pid: 61273, label: 'FocusSwiftUI'
Element subtree:
→Application, 0x12ed10b30, pid: 61273, label: 'FocusSwiftUI'
...
Button, 0x12ed0c660, {{468.0, 477.0}, {298.0, 126.0}}, label: 'Button 1'
Button, 0x12ed0c770, {{453.0, 470.7}, {328.0, 138.7}}, Focused
Button, 0x12ed0c1e0, {{806.0, 477.0}, {303.0, 126.0}}, label: 'Button 2'
Button, 0x12ed0c2f0, {{791.0, 470.8}, {333.0, 138.5}}
...
However, the moment you set buttonStyle to any custom one, the output changes drastically...
(lldb) po app
Attributes: Application, 0x106d0cd40, pid: 70156, label: 'FocusSwiftUI'
Element subtree:
→Application, 0x106d0cd40, pid: 70156, label: 'FocusSwiftUI'
...
Button, 0x106d0ce50, {{707.0, 505.0}, {142.0, 71.0}}, label: 'Button 1'
Button, 0x106d0cf60, {{885.0, 505.0}, {146.0, 71.0}}, label: 'Button 2'
Button, 0x106d0d180, {{1067.0, 505.0}, {147.0, 71.0}}, label: 'Button 3'
...
Notice there is no more Focused button anywhere... We will never get any button with hasFocus == true in queries for example...
What else did I try?
I tried to experiment with many (probably all) .accessibility... modifiers before asking.
Many different results, but none of them ever had proper focus behavior in UI tests...
.accessibilityChildren: close to default button behavior in terms of accessibility structure (e.g. nested buttons)
.accessibilityRepresentation: button never gets visually highlighted
Temporary workaround
For now there seems to be no solution in sight. I have implemented rather complicated hack to get at least UI tests working for now.
In a nutshell: When the app is running in a context of UI tests (determined through Launch Arg), each affected button adds clear color background (it has no visual or behavioral impact) when focused. The background color then has a constant accessibilityIdentifier (e.g. "MY_FOCUSED", I call it "custom focus marker"). When evaluating if element is focused in UI tests, I then check if the button contains child element where accessibilityIdentifier == "MY_FOCUSED".
It is nasty, but somehow good enough for UI tests and actually works reliably so far. It works thanks to the fact there is always only one focused item at the same time and the "if focused -> set background" takes care of the automatic update of the "custom focus marker".
You can try to set accessibilityRepresentstion - does it help?
Button(..)
.buttonStyle(AnyCustomButtonStyle())
.accessibilityRepresentation {
Button(..)
}
Edit:
Another idea - what about having the “correct” Button in the background of your custom? Something like:
Button(..)
.buttonStyle(AnyCustomButtonStyle())
.background(
Button(..).opacity(0.0001) //it may work even with opacity 0
)
You may additionally improve it with making the visible button hidden to accessibility with .accessibility(hidden: true)
If you're looking for actual VoiceOver accessibility (not using it as a UI test tool I mean) you can use the isFocused environment variable and on change, call UIAccessibility.post(notification: .announcement, argument: "Your message")
Actually i'm developing a Apple Tv project in swift3.I faced some problem with focus navigation using remote.
Is there any way to change focus from one object to another object which i want.
I tried below code but not working......
override var preferredFocusedView: UIView? {
get {
return preferredFocusedView1
}
}
In the bellow screenshot i want to move focus from the pink icon to the star button when pressed down button of remote. how it is possible. plz provide me some code in details
I've made a simple click bot to automatically play an android game on my Windows PC. It currently identifies when certain things change on the screen then moves the mouse and clicks the correct button.
Currently I am using the following win32api functions to achieve this:
Win32api.SetCursorPos(Position)
Win32api.mouse_event(winn32con.MOUSEEVENTF_LEFTDOWN,0,0)
Win32api.mouse_event(winn32con.MOUSEEVENTF_LEFTUP,0,0)
These work great however when I use the bot it takes over my computer's mouse and I basically have to let it run. Is there anyway I could simulate a click without it actually using my mouse, or is there a way I could isolate the bot on one of my other screens and be able to work freely on the other?
There is a lib specific for deal with user interaction components and periferics: pyautogui
Here, is a short and easy to try documentation for performing/simulating mouse click DOWN & UP
https://pyautogui.readthedocs.org/en/latest/mouse.html#the-mousedown-and-mouseup-functions
Below is what I came up with. Wonder if there's easier way to do it.
Suppose I want only menu layer to be touchable while it's up.
I put invisible layer that will swallow touches.
bool tNoTouchLayer::init()
{
if(!CCLayer::init()) {
return false;
}
setIsTouchEnabled(true);
return true;
}
void tNoTouchLayer::registerWithTouchDispatcher()
{
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
}
bool tNoTouchLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
return true;
}
Now I can add the noTouchLayer before adding menu layer, and all touches would be stolen by noTouchLayer.
Lastly, i did find more info on this:
http://code.google.com/p/cocos2d-iphone/issues/detail?id=1033
the reason that menu items are stealing touches is because menu items have their touch priority set to the highest (lowest char value) possible...
you can change kCCMenutouchPriority to be 0 instead.
That's how you do it as far as I can tell. Note however that your code will not disable any menues added to the scene. To do that you have to remove the menu from the touch dispatcher when adding the popup and add it back again when removing the popup.
To remove a menu from the touch dispatcher you can do the following:
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(menu);
and to add it back you can do this:
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(menu, kCCMenuHandlerPriority, true);
where menu is your CCMenu node.
As a tip, I created a class like the one above but I also added the popup menu to it, creating one touch blocking menu in one node. :)
this isn't exactly the answer you are looking for, but here's something up for thought:
if you're trying to do this for a pop-up, would it be possible to try to pop up a subclass of UIAlertView (one that looks the way you want it to)?
http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-uialertview-custom-graphics/
Here's another approach:
keep state of the app and which layer is "on top".
in each of your menu listeners, have them all do a check to see if the state of your current layer should allow for that menu button to be pressed.
also, you can override "addchild" to see if it's a MenuItem, and if it is a MenuItem, then have it check to see if it should be enabled. if not, return immediately instead of executing the rest of the code
If I understand your question correctly, I guess you try to do something like "pause screen" to pop up and disable all other layers.
Well, you said in your comment that you won't like to enable touch event in other areas but not your pop-up's area. Basically, I would think we should think in term of layer for easier understanding, and easier to implement.
Let's see if we have "main layer" which holds other game objects to show as its childs (assume that they also are running animation). Now you touch a button and want to pop up "pause layer". You have to do the following in order to disable all touch event from others layer + objects.
Pause layers' schedule and actions [via pauseSchedulerAndActions()]
Pause all of its game objects inside the layer (ie. enemies) [via pauseSchedulerAndActions()]
Disable CCMenu object (if any), this will ignore touch event on CCMenu related object ie.CCMenuItemImage [via setEnabled(false)]
Disable touch event for layer itself [via setTouchEnabled(false)]
The first 2 points are about stop running any schedule method, and animation.
The latter 2 points are about stop accepting touch event. You can see that CCMenu* related class maintains its own touch event separately from CCLayer, thus we need to do additional effort by set to both CCMenu* object and the layer itself.
I tried this and it works well for me. Also it's better as we don't have to involve setting dispatcher directly in my opinion.
I have an textbox with onChange method and button to make some actions. But if I type some thing in textbox and not clicking any where , click that button, It calls onClick method and then onChange method.Or first onChange and then OnClick but I should disable all actions after that onChange method.
Add the check to your onClick() method. The onChange() for a text box is fired after a certain period of time or after you deselect your component. If you deselect your component by clicking on a button it sounds pretty natural to me to get the onClik first and then the onChange. There is no way of controlling (as far as I know) these events, except on server side.
Read this !
Keep in mind that you are developing a WEB application and not a Desktop Application. And event if the development of zk applications may look pretty similar to the desktop applications they are not and they have their limitations.
I found solution :
First for Textbox onFocus method I disable next button , and user cant click it.
Second for Textbox onBlure method I enable next button. (To be fired onBlure action user should click somewhere on window or press tab and this fires onChange action)