I have a couple of things going on in my view when porting the app to mobile (on iOS).
When I start a scroll with touching a TextField, the textfield focuses then stays fixed on the screen during scroll.
I put some validation on the field such that when the field is put out of focus, a modal pops up specifying the error. However, in iPhone, the textfield stays focused and appears over the dialog.
Note that I am using a JavaFX native touch field and not the Gluon version because I had issues with the focusedProperty for the Gluon version of the TextField. The way it works is that if the input is invalid, it will set the value of the field to an empty string and open the dialog.
I have tried the following approaches:
Prior to showing the modal, requestFocus on the View.
While scrollpane is scrolling, requestFocus on the scroll pane (the scrollpane has its own custom skin which I can add the requestFocus on it while it is scrolling).
The problem you are facing will happen with either the JavaFX TextField and the Gluon`s one, as the latter internally uses the built in JavaFX control.
The reason of the issue on iOS is this: When the JavaFX TextField gets the focus, a native iOS UITextField is added on top of the control, basically to enable the interaction with the native software keyboard.
You can see that the TextFieldBehavior has a specific call on iOS:
private void handleFocusChange() {
TextField textField = getControl();
if (textField.isFocused()) {
if (PlatformUtil.isIOS()) {
...
textField.getScene().getWindow().impl_getPeer().requestInput(text, type.ordinal(), w, h,
trans.getMxx(), trans.getMxy(), trans.getMxz(), trans.getMxt(),// + insets.getLeft(),
trans.getMyx(), trans.getMyy(), trans.getMyz(), trans.getMyt(),// + insets.getTop(),
trans.getMzx(), trans.getMzy(), trans.getMzz(), trans.getMzt(), textField.getFont().getSize());
...
}
}
}
that goes directly to the native implementation:
UITextField* textField = [[UITextField alloc] initWithFrame:CGRectMake(mxt + 1, myt + 1, mxx * (width - 2), myy * (height - 2))];
So far this works fine as long as you don't scroll and move the JavaFX TextField initial position while the native UITextField is visible.
Also note that the iOS layer with the native control is on top of the JavaFX layer (that's why you keep seeing the native editor on top of the dialog).
There is an open PR to support updating the native control position when the software keyboard shows up, translating both the JavaFX and the iOS control, and introduces the updateBounds method, that could be used in case a scroll event moves the TextField.
In the meantime, you will have to add some workaround to prevent scrolling while the TextField is focused.
Related
I have been having issues with using the ScrollToAsync function of a ScrollView when running on Android, not tested on iOS yet.
I'm using Xamarin.Forms version 2.5.1.444934 using .Net Standard
Testing on the Android Emulator (8.0, API26) and a Google Pixel (8.1 API27), both have the same issue.
I use NavigationPage and Navigation.PushAsync to move between pages (therefore have navigation bars on every page).
I want to create an auto populate field control, the user types in the first few letters and I look up the results in a database / static list of string and display the results below for the user to click/tap.
I have this working using a composite control (the contents of the frame marked interesting below).
The problem I have is scrolling the view to show the results.
My page has this layout hierarchy:-
ContentPage
StackLayout
ScrollView
StackLayout
Frame (some label and entry fields inside a stack layout)
Frame (some label and entry fields inside a stack layout)
Frame (some label and entry fields inside a stack layout)
Frame (the interesting one that deals with scrolling)
StackLayout
Heading Label
StackLayout
Label x:Name="ScrollToLabel"
Entry x:Name="ScrollToEntry"
Grid x:Name="ScrollToGrid"
Entry x:Name="Hidden" Text="I should stay visible as you type"
/StackLayout
/StackLayout
/Frame
Frame (some label and entry fields inside a stack layout)
Frame (some label and entry fields inside a stack layout)
/StackLayout
/ScrollView
StackLayout
Button Text = Done
/StackLayout
/StackLayout
/ContentPage
When the user clicks/taps in to ScrollToEntry, the keyboard opens and pans the control to above the keyboard (ok so far).
When the user starts typing in ScrollToEntry, the code populates ScrollToGrid with up to 5 results.
At this point I want to make sure that the grid results are visible for the user to tap on.
I have tried 2 different options, ScrollToAsync(ScrollToLabel, Start) and ScrollToAsync(Hidden, MakeVisible).
Neither work as I would like 100% of the time.
ScrollToAsync(ScrollToLabel, Start)
If the ScrollToEntry is at the bottom of the screen, the navigation bar is hidden and the view pans up too far.
The ScrollToLabel is now off the top of the screen.
When the second letter is clicked/tapped, the Navigation bar is restored and the scroll scrolls correctly, ScrollToLabel at the top of the screen.
If the ScrollToEntry is near the top of the screen, the navigation bar is not hidden and it scrolls correctly.
ScrollToAsync(Hidden, MakeVisible)
This is my preferred option because it would only scroll as far as needed to display all the results (not all the way to the top).
This works even worse than the first one.
In most cases, it does not scroll at all, I assume it thinks it already visible but is actually behind the keyboard?
If it does scroll, the label Hidden is still not displayed (I tested with both a HeightRequest="0" version and a visible version, both the same result).
I tried using the below code to change the adjust to resize.
Application.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
2 issues,
1. Because it resizes, the Done button now is above the keyboard, taking up space.
2. When clicking the hardware back button (not the done or navigation back button) the previous view now has a white space where the keyboard was.
If using the done or navigation back, the screen initially appears with the white space but then refreshes to full screen.
I have created a sample app that highlights the issues (by default using pan, not resize).
It's the most simple version of the layout I'm using...
Am I doing something wrong or is this just how it works? If its how it works, this must be a bug? If I'm doing it wrong, can someone tell me what or suggest a different way of doing it?
I have been using a UIView in my navigationBar as the titleView up to Xcode 8 iOS 10. The view was added in storyboard. In that UIView I have a label representing the title and underneath it a segmented control. This has worked fine up until iOS 11. Now I can no longer interact with the segmented control and the positioning is shifting up so that the title and half of the segmented control is off screen. I was using an empty space for the prompt field of the navigationBar to get the extra height.
Is there a way of adding a title and segmentedControl underneath it to a navigationBar without creating a custom navigationBar? I don't want to create a custom navigationBar because I want to keep the translucency properties of the default navigationBar.
At the moment here is what I see after running Xcode 9 iOS 11:
Add in Appdelegate.m
if ([UIScreen mainScreen].bounds.size.height >= 812)
{
[application setStatusBarStyle:UIStatusBarStyleLightContent];
self.window.clipsToBounds =YES;
self.window.frame = CGRectMake(0,40,self.window.frame.size.width,self.window.frame.size.height-20);
}
Best way to manage this is to add the segmentedControl directly in the navigationTitle area in the storyboard and afterwards add a title in the inspector title textfield in storyboard when navigationBar is selected. This will show both the title in large font and the storyboard above it exactly like the missed calls page of iOS
My GTK# (v2.12.44) app has a single Window with a single button on it. The button appears to be centered on the Window, because that's where the text appears, but the border/background for the button is shifted up and to the left for no reason I can see. Has anyone seen this before? I saw similar behavior from an Image widget. Note this only happens in Windows, not on (for example) Raspberry Pi/Jesse.
Here's the code:
Application.Init();
var window = new Window("test") {new Button("testing 1, 2, 3")};
window.Maximize();
window.ShowAll();
Application.Run();
Your code works well. Try to add a container before adding a button and set some parametrs you want to. Fill and Expand when adding Button.
In my TornadoFX (which is a wrapper to JavaFX8) app I create a ButtonBar with one button. I use the DSL (code, not XML) for that.
Unexpectedly, all my buttons are squashed on the right. Scenic View shows that there is a Region before all my buttons with Hgrow = Always.
Where does this Region come from?
How do I remove it / set to Hgrow = Never?
How in general do i get references to the children of a ButtonBar? GetChildrenUnmodifiable returns an empty list.
Thank you
That's what ButtonBar is supposed to do. According to the ButtonBar docs:
A ButtonBar is essentially a HBox, with the additional functionality for operating system specific button placement.
*emphasis mine
The button bar will add regions to push the buttons to where they are expected to be on your OS. To change where the buttons end up on the bar, you use ButtonBar.setButtonData(Button, ButtonData).
So, I've been programming an analog clock in JavaFX and have gotten the base functionality down. Now, I'm trying to add a drop-down menu when I click a custom button (triangle made with a Polygon). So far it all works fine, except the fact that the background of my StackPane is white when I try to add a ContextMenu either before or after clicking the button. So far Transparency has been fine up until now. Here's some pictures of the issue.
This is what it should look like (you can see my wallpaper because of the transparent window, as it should be.)
enter image description here
After I press the button for the drop down menu, the background changes.
enter image description here
JavaFX controls are styled by CSS. The first time you create a control, the default user agent stylesheet (modena.css) is loaded and the styles defined in it are applied to the scene graph. Other JavaFX node classes, such as shapes, image views, and layout panes, do not enforce CSS loading (this is to enhance performance for graphically-intensive applications that do not need CSS).
So it sounds as though the context menu is the first control you create: when you create and display it, it will apply the default CSS to the scene. The default background color for the root pane is a non-transparent color, so while your Scene and Stage may be transparent, once the CSS is applied the scene's content is not.
The fix is to specify transparency for the root pane:
root.setStyle("-fx-background-color: transparent;");
or the equivalent in an external stylesheet.
To answer my own question in case anyone else wants to know, it seems that when the ContextMenu is added to the scene, the Stage's initStyle(StageStyle.TRANSPARENT) gets overridden and shows the Parent's colors. Since I didn't initialize any CSS styles for the root, it just showed white. The fix would be to:
//the Parent layout Pane
parent.setStyle("-fx-background-color: rgba(0, 0, 0, 0.0)");