I have a TextField and a ModalDrawer in a compose screen. I would like to close the soft keyboard when the user opens the drawer, but I haven't been able to figure out how. There is no onOpened lifecycle event that gets triggered in ModalDrawer afaik.
You can use the confirmStateChange parameter in rememberDrawerState() and call keyboardController.hide() when the drawerValue becomes DrawerValue.open like this:
val keyboardController = LocalSoftwareKeyboardController.current
val state = rememberDrawerState(
initialValue = DrawerValue.Closed,
confirmStateChange = {
if (it == DrawerValue.Open) {
keyboardController?.hide()
}
true
}
)
ModalDrawer(
drawerState = state,
...
) {
...
}
Related
I have a composable like here.
#Composable
fun MyBasicTextField() {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember{ FocusRequester() }
BasicTextField(
modifier = Modifier
.focusRequester(focusRequester),
keyboardActions = keyboardActions ?: KeyboardActions(onAny = { keyboardController?.hide() }),
)
LaunchedEffect(Unit) {
Log.d(TAG, "focusRequester.requestFocus()")
focusRequester.requestFocus()
}
}
When the screen where this composable is used opens for the first time, always the keyboard is shown (above log message is visible).
Then I leave the app at that state and open another app (opening a link on that screen, which opens the default browser for instance)
Tapping on the BACK button (triangle) leaved the other app (e.g. webbrowser) and comes back to the initial screen: Either with opened Android keyboard on some devices or without any keyboard showing.
I have the feeling that the screen did not notice the missing keyboard (which disappreared while leaving the app for the browser) and thus does not recompose anything?
Can I flag to compose the screen from fresh everytime I re-/compose it?
I'm not sure why you need this, because focusing and showing keyboard every time re-composition happens may be undesirable, what if the user is doing something else on the screen which updates the field, you don't want want to show the keyboard but re-composition happens and you pop it again.
Having said this it's of course doable:
For example the argument passed into the LaunchedEffect determines if during re-composition the block will be run.
So you could try something like this:
#Composable
fun MyBasicTextField() {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember{ FocusRequester() }
var launchKey by remember { mutableStateOf(0) }
BasicTextField(
modifier = Modifier
.focusRequester(focusRequester),
keyboardActions = keyboardActions ?: KeyboardActions(onAny = { keyboardController?.hide() }),
)
//passing launchKey instead of Unit
LaunchedEffect(launchKey++) {
Log.d(TAG, "focusRequester.requestFocus()")
focusRequester.requestFocus()
}
}
We have used view pager (react-native-community/react-native-viewpager) in our app, and there are 3 sections of each and every page , all 3 sections are clickable, for making it clickable we are using TouchableHighlight.
So whenever I'm changing my page by swiping. If my touch for sliding is inside TouchableHighlight in IOS it is taking it as click else in android it is working fine.
Posting this for help for other users like me.
Answer from developer of this library.
Hey,
you can use onPageScrollStateChanged method, to block button interaction.
switch(pageScrollState){
case "idle": enableButton();
default: disableButton();
}
or I have used this approach.
this.state = {
shouldEnableClick: true,
};
pageScroll = (event) => {
draggingValue = event.nativeEvent.offset
isNotStill = (draggingValue == 0 || draggingValue == 1) ? true : false
{Platform.OS == 'ios' && this.changeValue(isNotStill)}
}
changeValue(isNotStill) {
if (this.state.shouldEnableClick !== isNotStill) {
this.setState({ shouldEnableClick: isNotStill })
}
}
and in component I am using it like
let enableCLick = this.state.shouldEnableClick
let clickAction = () => this.myAction()
<TouchableHighlight
onPress={enableCLick && clickAction}/>
I'm developing a UWP-App with a WebView inside. At the WebView I want to use the forward and backward buttons of the mouse to navigate forward and backward. At default the WebView doesn't support it. (a normal browser does)
So I've found the PointerPressed Event and in this event I can check if the pointer-device is the mouse and if the pointer-properties are IsXButton1Pressed or IsXButton2Pressed. If I implement it on other usercontrols it works perfectly. But on the WebView usercontrol it doesn't work.
That's how I implemented it on other usercontrols:
private void Page_PointerPressed(object sender, PointerRoutedEventArgs e)
{
PointerPoint currentPoint = e.GetCurrentPoint(this);
if(currentPoint.PointerDevice.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
PointerPointProperties pointerProperties = currentPoint.Properties;
if(pointerProperties.IsXButton2Pressed)
{
if (grd_content.Children.Count == 1 && grd_content.Children[0] is Interfaces.IWebNavigation)
{
Interfaces.IWebNavigation iWebNav = (Interfaces.IWebNavigation)grd_content.Children[0];
e.Handled = iWebNav.GoForward();
}
}
else if(pointerProperties.IsXButton1Pressed)
{
if (grd_content.Children.Count == 1 && grd_content.Children[0] is Interfaces.IWebNavigation)
{
Interfaces.IWebNavigation iWebNav = (Interfaces.IWebNavigation)grd_content.Children[0];
e.Handled = iWebNav.GoBackward();
}
}
}
}
How can I implement the mouse forward and backward button on a WebView usercontrol?
I am using iOS version of 10.2 and xcode version is 8.3.
Can anyone let me know how to hide the keyboard in iOS mobile automation using Appium?
programming language used: Java.
I tried driver.hideKeyboard(), but it doesn't work for me.
So, I tried with way:
by pressing the button specified key name and way
inspect key coordinate with appium and perform action. Both ways are work for me.
// way 1
driver.findElementByXPath(String.format("//XCUIElementTypeButton[#name='%s']", "Done")).click();
// way 2
TouchAction touchAction = new TouchAction(driver);
touchAction.tap(new PointOption().withCoordinates(345, 343)).perform();
You could use java_client library methods:
driver.findElementByAccessibilityId("Hide keyboard").click();
driver.hideKeyboard(HideKeyboardStrategy.TAP_OUTSIDE);
driver.hideKeyboard(HideKeyboardStrategy.PRESS_KEY, "Done");
I noticed that "Done" is not part of the keyboard group. So I tried to use the name "Done" as my reference to get the element. I tried this on my end and it works.
driver.findElementByName("Done").click();
The "driver" set declared as IOSDriver.
You can use below code snippet to hide keyboard:
driver.getKeyboard().pressKey(Keys.RETURN);
Solution for Python - 2020:
#staticmethod
def hide_keyboard(platform):
"""
Hides the software keyboard on the device.
"""
if platform == "Android":
driver.hide_keyboard()
elif platform == "iOS":
driver.find_element_by_name("Done").click()
i prefer to tap last key on keyboard for iOS instead of hide:
#HowToUseLocators(iOSXCUITAutomation = LocatorGroupStrategy.CHAIN)
#iOSXCUITFindBy(className = "XCUIElementTypeKeyboard")
#iOSXCUITFindBy(className = "XCUIElementTypeButton")
private List<IOSElement> last_iOSKeyboardKey;
#HowToUseLocators(iOSXCUITAutomation = LocatorGroupStrategy.CHAIN)
#iOSXCUITFindBy(className = "XCUIElementTypeKeyboard")
#iOSXCUITFindBy(iOSNsPredicate = "type == 'XCUIElementTypeButton' AND " +
"(name CONTAINS[cd] 'Done' OR name CONTAINS[cd] 'return' " +
"OR name CONTAINS[cd] 'Next' OR name CONTAINS[cd] 'Go')")
private IOSElement last_iOSKeyboardKey_real;
public boolean tapLastKeyboardKey_iOS() {
System.out.println(" tapLastKeyboardKey_iOS()");
boolean bool = false;
setLookTiming(3);
try {
// one way
//bool = tapElement_XCTest(last_iOSKeyboardKey.get(last_iOSKeyboardKey.size()-1));
// slightly faster way
bool = tapElement_XCTest(last_iOSKeyboardKey_real);
} catch (Exception e) {
System.out.println(" tapLastKeyboardKey_iOS(): looks like keyboard closed!");
System.out.println(driver.getPageSource());
}
setDefaultTiming();
return bool;
}
I tried using all of above method. In some case, it doesn't work perfectly. In my way, it will tap on top left of keyboard.
public void hideKeyboard() {
if (isAndroid()) {
driver.hideKeyboard();
} else {
IOSDriver iosDriver = (IOSDriver) driver;
// TODO: Just work for Text Field
// iosDriver.hideKeyboard();
// TODO: Tap outside of Keyboard
IOSElement element = (IOSElement) iosDriver.findElementByClassName("XCUIElementTypeKeyboard");
Point keyboardPoint = element.getLocation();
TouchAction touchAction = new TouchAction(driver);
touchAction.tap(keyboardPoint.getX() + 2, keyboardPoint.getY() - 2).perform();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Since the IOS device keyboard doesn't have any "Done" or "Enter" buttons anymore so we can't use any of the Appium server utility interface like HideKeyboardStrategy.
I basically used the TouchAction class tap method to tap at top of the screen and dismiss the keyboard.
TouchAction touchAction = new TouchAction(driver);
int topY = driver.manage().window().getSize().height / 8;
int pressX = driver.manage().window().getSize().width / 2;
touchAction.tap(new PointOption().withCoordinates(pressX, topY)).perform();
Quick & simple solution :
I always try to tap anywhere on screen, may be on
Static text
Image
after entering to hide keyboard unless I explicitly has requirement of interacting with keyboard. This works pretty well for me. Try it :)
I'm creating a game in XNA that runs on a PC.
On the splash screen, the user has three options. If they press "Enter" the game will begin, if they press "M" they'll go to the Help menu and if they press "W" I want that to take them to my website.
I'm using Process.Start to open the browser to my website.
The problem is that when I press "W", sometimes it will open 1 browser with the website. However, most of the time it will open anywhere from 3 - 7 browsers simultaneously.
Why is it opening multiple browsers simultaneously?
How do I make it open only 1 browser when "W" is pressed?
Here is my code. I haven't built my website yet, so I'm using yahoo.com as the destination:
private void UpdateSplashScreen()
{
KeyboardState keyState = Keyboard.GetState();
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W))
{
Process.Start("IExplore.exe", "www.yahoo.com");
}
}
Thanks,
Mike
A common way to handle this is to always track the keyboard state from the previous frame. If a key wasn't down on the previous frame, but is down this frame then you know it was just pressed. If the key was down on the previous frame then you know it's being held down.
// somewhere in your initialization code
KeyboardState keyState = Keyboard.GetState();
KeyboardState previousKeyState = keyState;
...
private void UpdateSplashScreen()
{
previousKeyState = keyState; // remember the state from the previous frame
keyState = Keyboard.GetState(); // get the current state
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter) && !previousKeyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M) && !previousKeyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W) && !previousKeyState.IsKeyDown(Keys.W))
{
Process.Start("IExplore.exe", "www.yahoo.com");
}
}
I usually create a KeyPressed function which cleans things up a bit.
bool KeyPressed(Keys key)
{
return keyState.IsKeyDown(key) && !previousKeyState.IsKeyDown(key);
}
The code you are using runs about 60 times a second; you may only press your key down for 100ms or so but in that time it checks to see if W is pressed down about 7 times. As such, it opens a large number of browser windows.
Try recording a timestamp (using DateTime.Now) of when you open the browser and then check that a certain time has elapsed (~2 secs?) before allowing another window to be opened. Or, create a boolean flag that is set false by opening the browser, so the browser can be opened only once.
Thanks guys, that's what the problem was.
Callum Rogers solution was the easiest:
I declared a boolean:
bool launchFlag = false;
Then checked it and set it to true after the website launched.
private void UpdateSplashScreen()
{
KeyboardState keyState = Keyboard.GetState();
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W))
{
if (launchFlag == false)
{
Process.Start("IExplore.exe", "www.yahoo.com");
launchFlag = true;
}
}
}
I held the W key down for 30 seconds and it launched just 1 browser!
Thanks,
Mike