How to get initial keyboard focus on an Android compose app?
My view looks like
Parent { Child { Button} }
I tried implementing it in the Parent composable function....
FocusRequester is not initialized. Here are some possible fixes:
1. Remember the FocusRequester: val focusRequester = remember { FocusRequester() }
2. Did you forget to add a Modifier.focusRequester() ?
3. Are you attempting to request focus during composition? Focus requests should be made in response to some event. Eg Modifier.clickable { focusRequester.requestFocus() }
The following code woirks like a charm....
fun Modifier.requestInitialFocus() = composed {
val first = remember { FocusRequester() }
LaunchedEffect(first) {
delay(1)
first.requestFocus()
}
focusRequester(first)
}
Original:
This error does not happen when implementing it in the composable function, where the target element is a direct child....
So implementing it in the Child seems to be a solution....
I'm trying to create a TextField in Jetpack Compose for users to enter their first and last name.
Is there a way to allow ONLY letters and whitespaces ([a-zA-Z\s]) as input? I've tried every single option available, including KeyboardType.Text, KeyboardType.Ascii, KeyboardType.Uri, but they all show numbers!
Am I missing something obvious? Honestly, I'm kind of shocked that Google doesn't offer this option out of the box.
Try this:
val pattern = remember { Regex("[a-zA-z\\s]*") }
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = {
if (it.matches(pattern)) {
text = it
}
}
)
In Android it's not possible to show a keyboard containing only letters (and it's not related to compose). Keyboard apps don't support it either.
There are other kinds of keyboards (like number-only keyboard), but the view of the keyboard is still controlled by the keyboard app.
It's best to filter the given input based on the needed criteria. For example:
onValueChange = {
text = it.letters()
}
private fun String.letters() = filter { it.isLetter() }
I just started with UI testing in Xcode 7 and hit this problem:
I need to enter text into a textfield and then click a button. Unfortunately this button is hidden behind the keyboard which appeared while entering text into the textfield. Xcode is trying to scroll to make it visible but my view isn't scrollable so it fails.
My current solution is this:
let textField = app.textFields["placeholder"]
textField.tap()
textField.typeText("my text")
app.childrenMatchingType(.Window).elementBoundByIndex(0).tap() // hide keyboard
app.buttons["hidden button"].tap()
I can do this because my ViewController is intercepting touches:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
view.endEditing(false)
super.touchesBegan(touches, withEvent: event)
}
I am not really happy about my solution, is there any other way how to hide the keyboard during UI testing?
If you have set up your text fields to resign FirstResponder (either via textField.resignFirstResponder() or self.view.endEditing(true)) in the textFieldShouldReturn() delegate method, then
textField.typeText("\n")
will do it.
Swift 5 helper function
func dismissKeyboardIfPresent() {
if app.keyboards.element(boundBy: 0).exists {
if UIDevice.current.userInterfaceIdiom == .pad {
app.keyboards.buttons["Hide keyboard"].tap()
} else {
app.toolbars.buttons["Done"].tap()
}
}
}
Based on a question to Joe's blog, I have an issue in which after a few runs on simulator the keyboards fails to hide using this piece of code:
XCUIApplication().keyboard.buttons["Hide keyboard"]
So, I changed it to: (thanks Joe)
XCUIApplication().keyboard.buttons["Hide keyboard"]
let firstKey = XCUIApplication().keys.elementBoundByIndex(0)
if firstKey.exists {
app.typeText("\n")
}
What I try to do here is detecting if the keyboard stills open after tap the hide button, if it is up, I type a "\n", which in my case closes the keyboard too.
This also happens to be tricky, because sometimes the simulator lost the focus of the keyboard typing and this might make the test fail, but in my experience the failure rate is lower than the other approaches I've taken.
I hope this can help.
I always use this to programmatically hide the keyboard in Swift UITesting:
XCUIApplication().keyboards.buttons["Hide keyboard"].tap()
XCUIApplication().toolbars.buttons["Done"].tap()
With Swift 4.2, you can accomplish this now with the following snippet:
let app = XCUIApplication()
if app.keys.element(boundBy: 0).exists {
app.typeText("\n")
}
The answer to your question lies not in your test code but in your app code. If a user cannot enter text using the on-screen software keyboard and then tap on the button, you should either make the test dismiss the keyboard (as a user would have to, in order to tap on the button) or make the view scrollable.
Just make sure that the keyboard is turned off in the simulator before running the tests.
Hardware->Keyboard->Connect Hardware Keyboard.
Then enter your text using the paste board
textField.tap()
UIPasteboard.generalPasteboard().string = "Some text"
textField.doubleTap()
app.menuItems["paste"].tap()
I prefer to search for multiple elements that are possibly visible to tap, or continue, or whatever you want to call it. And choose the right one.
class ElementTapHelper {
///Possible elements to search for.
var elements:[XCUIElement] = []
///Possible keyboard element.
var keyboardElement:XCUIElement?
init(elements:[XCUIElement], keyboardElement:XCUIElement? = nil) {
self.elements = elements
self.keyboardElement = keyboardElement
}
func tap() {
let keyboard = XCUIApplication().keyboards.firstMatch
if let key = keyboardElement, keyboard.exists {
let frame = keyboard.frame
if frame != CGRect.zero {
key.forceTap()
return
}
}
for el in elements {
if el.exists && el.isHittable {
el.forceTap()
return
}
}
}
}
extension XCUIElement {
///If the element isn't hittable, try and use coordinate instead.
func forceTap() {
if self.isHittable {
self.tap()
return
}
//if element isn't reporting hittable, grab it's coordinate and tap it.
coordinate(withNormalizedOffset: CGVector(dx:0, dy:0)).tap()
}
}
It works well for me. This is how I would usually use it:
let next1 = XCUIApplication().buttons["Next"]
let keyboardNext = XCUIApplication().keyboards.firstMatch.buttons["Next"]
ElementTapHelper(elements: [next1], keyboardElement: keyboardNext).tap()
Nice thing about this is you can provide multiple elements that could be tapped, and it searches for keyboard element first.
Another benefit of this is if you are testing on real devices the keyboard opens by default. So why not just press the keyboard button?
I only use this helper when there are multiple buttons that do the same thing, and some may be hidden etc.
If you are using IQKeyboardManager you can easily do this:
app.toolbars.buttons["Done"].tap()
This way you capture the "Done" button in the keyboard toolbar and hide the keyboard. It also works for different localizations.
I am working with IOS by using xamarin ,I am new to technology I have one requirement ,That is I don't want to allow any special character in my text box .How can I do this any one help me
thanks
What you can do is use ShouldChangeCharacters delegate.
Using it you can decide weather or not to update the text of the UITextField.
For example lets say you have a UITextField named textField:
textField.ShouldChangeCharacters = (textField, range, replacementString) => {
if (isSpecialCharacter) {
return false;
} else {
return true;
}
};
I try to find the caret position in an editable div.
Also it should be nice to get the selected text in this div.
I try to assimilate this:
Editable Div Caret Position
But it dosen’t work.
I'll be happy to give any Idea.
Thanks in advance
Some code snippet
HTML
<a on-click="{{chooseMenu}}" which-menu="1">Menu 1</a>
Dart
void chooseMenu(Event event, var detail, var target) {
event.preventDefault();
event.stopPropagation();
Selection sel;
Range range;
sel = window.getSelection();
if(sel != null) {
range = sel.getRangeAt(0);
range.collapse(false);
}
currentSubMenu = int.parse(target.attributes['which-menu']);
}
This worked for me in Dartium.
The other code from the referenced SO question is probably to support other browsers.
Dart usually generates JS code that works in all supported browsers.
You have to test yourself if the generated JS really works in the browsers you want to support.
EDIT
We store the selection whenever it changes. Maybe there are better events but I couldn't find one.
But it worked fine for me.
We insert the new node at the previously stored selection.
// must be accessible by getRange, insertNodeAfterSelection
DivElement editable;
Range range;
// store reference to our contenteditable element
editable = (document.querySelector('#editable') as DivElement);
// subscribe selection change events
document.onSelectionChange.listen(getRange);
void insertNodeAfterSelection(Node node) {
range.collapse(false);
range.insertNode(node);
}
void getRange(Event e) {
if(document.activeElement != editable) { // save only selection changes on our contenteditable
return;
}
print(e);
Selection sel;
sel = window.getSelection();
if(sel != null) {
range = sel.getRangeAt(0);
}
}
You have to decide yourself where you put those code parts. I added some comments as support.
EDIT
using the mousedown event instead of click should help around this issue
Preserve text selection in contenteditable while interacting with jQuery UI Dialog and text input