Lag When Activating Text Field Inside iOS 8 Custom Keyboard - ios

I want to add a search field inside my custom keyboard that allows the user to search for content which can then be input into the main text document for which the keyboard is being displayed.
However, calling -becomeFirstResponder on the UITextField object causes a 3-4 second lag during which no input is accepted. The same thing happens if I call -resignFirstResponder. I can set the text property of the text field just fine, but that means that there is no caret, and the text is truncated to fit.
On calling (become|resign)FirstResponder, I get the following messages in the log:
2014-10-28 13:39:50.920 Giffy KB[2073:514844] Received 0 images
2014-10-28 13:39:57.942 Giffy KB[2073:514745] <_UIRemoteInputViewController: 0x14762a030> timed out waiting for fence barrier from com.theappical.giffage.giffagekb
2014-10-28 13:39:58.446 Giffy KB[2073:514745] View service did not balance fencing 'begin' messages with 'end' messages within a second; timing out.```
Other third party keyboards seem not to use textfields (they use custom views instead). Does that mean this is a bug at Apple's end, or is there something I can do to resolve it?

Filed a bug report with Apple for the same, ended up faking a text field using a UILabel. As of now (iOS 8.1 latest), this issue has yet to be resolved.

Related

SwiftUI TextField with non-default keyboard does not update the bound value

I am using a TextField to update a numeric value in my app model. The page editing the values is triggered from a NavigationView. Everything works fine when I use a default keyboard, ie:
TextField("Enter a number", value: $userData.chosenNumber, formatter: NumberFormatter())
.keyboardType(.default)
will update the value of userData.chosenNumber when hitting the Return key and this change is reflected on the main navigation screen (userData is an EnvironmentObject).
However, the same code using .keyboardType(.numberPad) instead won't show a Return key, and userData.chosenNumber won't be updated when navigating back to the main view. This happens both in the simulator and live on device (but things work as expected using SwiftUI live preview, or in the simulator when hitting the physical keyboard Return key).
Is there a way to get the new value picked up please without having to use a default keyboard?
--Edit--
Based on pawello2222's suggestion in the comments, I tried the solution in this other SO's question but that didn't fully work in my case.
What the other question suggests: introducing a Binding<String> (via a computed property) that acts as intermediate between the value I want to modify and the string displayed in the UI.
This works to modify the value inside my view.
However the runtime fails to detect that the EnvironmentObject injected by the parent view is modified, so after leaving the view the app UI is not refreshed and the other views do not get updated.
(For some context, my app computes a diver's bottom time based on an air tank site and the diver's air consumption. The detail view is used to edit the diver's air consumption value while another view displays the resulting bottom time. So in my case the diver's consumption gets updated, but the bottom time doesn't receive an update, unlike what happens with a standard keyboard.)

iOS Custom Keyboard Types

I'm worked on a custom keyboard and Apple review team rejected it because the keyboard does not support 'Numbers and Decimals' types.
So, I found that the problem is that when a text field requires those specific type of keyboard (for example to inset age, measures, or other numeric values), my keyboard 'misses to respond'.
I understood, reading from Apple documentation, that you must respond to the UIKeyboardTpye property per text object's.
I searched for specific delegate of the UIInputViewController but I wasn't able to find something close to that.
In this forum I found that one good place to examine the current keyboard type required is the textDidChange: delegate, but, it is not called.
I suppose this responder is called when your keyboard, somehow, 'declares' to iOS that it can handle Numbers or Decimal types. In fact I created a simple app with a simple UITextView that requires the Decimal keyboard type:
textView.keyboardType = UIKeyboardTypeDecimalPad;
And I put a NSLog() in the keyboard extension Input View Controller textDidChange: delegate.
As I tap on the text view my delegate is not called, instead the standard Decimal keypad is shown and in the Xcode console I see the following message:
Can't find keyplane that supports type 8 for keyboard iPhone-Portrait-DecimalPad; using 405786210_Portrait_iPhone-Simple-Pad_Default
I noticed also that this message comes when the UITextView requires the not-allowed keyboard types, i.e. the phonepad. All other keyboard types do not issue that message and the custom keyboard is shown and the textDidChange: delegate is correctly called.
The Numbers and Decimal types are surely allowed and are a MUST for the review team guys. Why the behave as a forbidden-types?
I think we need to 'declare', for example in the info.plist that our extension supports various keyboard types, but... well or more simply... I do not get the point... so... I'm asking... How can I add multiple keyboard types to my keyboard extension??
Thank you very much for help!
After the second rejection of my keyboard extension they sent me a screenshot. I noticed that they, generally, test apps on iPad. This made me think.
After some test it came out that the Numbers and Decimal types do not respond the same way on iPhone and iPad.
On iPhone a text view requiring Numbers or Decimal type keyboard always shows the iOS keypad, i.e. the custom extension is not called.
On the other side, on the iPad a text view requiring Numbers or Decimal type keyboard activates the custom extension.
Finally, after provided a standard numeric keypad (even if my keyboard uses hand-written techniquies) it was approved.

How to simulate a soft keyboard click on IOS simulator?

I am using XCTest to test my IOS app.
As part of a test case I need to enter a number into a field (which is not a text box)
When I record the test, following code is generated when I use the soft keyboard on the simulator(IPAD/IPhone)
app.staticTexts["0"].tap() //Line 1
app.typeText("23") //Line 2
When I execute the test, the soft keyboard pops up after Line 1. But when Line 2 is executed, following error appears
UI Testing Failure - Neither element nor any descendant has keyboard focus
My app requires to be installed on IPads/IPhones. So I need to make it run through the soft keyboard route only.
So I think typeText is not the correct method. What is the method to simulate clicks on a soft/virtual keyboard in an IOS simulator?
You need to call typeText() on the element with keyboard focus, not just app.
If the element was a text field, you would find the text field element and call typeText() on that.
let element = app.textFields["myTextField"]
element.typeText("23")
You will need to replace the query with your own one for finding the element which has keyboard focus. Usually, this would be a descendant of UITextField but you will need to use a more custom query if you are using a custom view instead.

Appium: How to wait for new element with same name as visible one to appear on screen?

We're using Appium with iOS Simulator and test functions written in Java.
We have an iOS App with screen 1 containing a UICollection view, and tell Appium to click on one of its elements.
This opens screen 2 (and the scrolling animation takes about 500 ms), which also contains an UICollection view. I want to find out the size of the UICollection view of the second screen with Appium.
The problem is that Appium is too fast and executes the findElements() method directly after the click, which causes it to find the UICollection view of the first screen.
clickOnElementOnFirstScreen();
webDriver.findElements( By.className( "UIACollectionCell" ) ).size();
// is supposed to find the UICollection view on the second screen,
// but actually finds the UICollection view on the first screen
Appium provides several waiting functions. However as far as I can see all of them are intended to be used in this fashion:
"wait until element at location X / with name X becomes visible"
If I try to use these waiting functions, they don't wait at all because they immediately find the UICollection view of the first screen, which has the same location and name as the one on the second screen.
The only solution I have found is to use Thread.sleep:
Thread.sleep(1000);
webDriver.findElements( By.className( "UIACollectionCell" ) ).size();
But we don't want to use Thread.sleep in code that will run on the client's server on hundreds of tests.
We might be able to modify the App and enter metadata into the views so that Appium is able to distinguish them, but this situation occurs in several places and the App is being programmed by the client, so we want to avoid this too.
What is a simple and safe way to wait for the new screen to appear, without modifying the code of the iOS App?
I have found only dirty workaround for this issue.
static waitFor(Duration duration) {
try {
def WebDriverWait wait = new WebDriverWait(mobileDriver, duration.standardSeconds)
wait.until(visibilityOfElementLocated(By.xpath("//Fail")))
//Wait until false case is visible to ensure proper timeout
} catch (Exception e) {
}
}
Another workaround/solution that has been posted on the Appium forums is:
First search for some other element that distinguishes the 2. screen from the 1. screen; once that is visible, it's safe to search for the originally desired element.

Whatsapp Message Layouting - time and message in the same row

I was wondering how WhatsApp handles the time shown in every message.
For those who don't know:
If the message is very short, the text and time are in the same row. (tine in the end of row)
If the message is long, the time is in the bottom right corner - the text wrapped around it.
if you have some idea how to do it please let me know
Here is the requested screenshot (please ignore checkmarks):
You can use a single attributed string with different text attributes for the main message, and the timestamp. iOS will then internally do all this for you automatically.
Otherwise you can use exclusion paths which are a part of TextKit.

Resources