The default iOS behaviour of a Xamarin.Forms DatePicker view is the iOS "Wheel" UIDatePicker.
Btw this control is quite ugly and users complained because they wanted (as happening in Android) a calendar view to choose from.
So after a quick search, I came across a new functionality available from iOS 14 which allows to use a "calendar" style for the UIDatePicker.
This is accomplished by a custom renderer calling the PreferredDatePickerStyle with the Inline value:
public class CustomDatePickerRenderer : DatePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(14, 0))
{
UIDatePicker picker = (UIDatePicker)Control.InputView;
picker.PreferredDatePickerStyle = UIDatePickerStyle.Inline;
}
}
}
}
The result is fine on wider iPhones, but on iPhone 8 the effect is this:
The last calendar row is off screen and there's no way to show it (no scrolling)
Has anyone encountered and solved this situation ?
I can reproduce this issue. Not only for iPhone8 but also for 8 Plus, iPhone SE. All of these devices have physical Home Button. You could report an issue here: Xamarin.Forms Issues On Github. As an alternative, you could try using
UIDatePickerStyle.Compact or Automatic.
Related
I'm working on a NativeScript-Angular app for both Android and iOS but have hit a problem with standard back button navigation. I have resolved the issue for Android, but cannot find a solution for iOS.
The event is causing a problem when going back to a particular page where routing data is expected, resulting in the exception:
"Error: Currently in page back navigation - component should be reattached instead of activated".
My Android solution catches the back button event and cancels it, then calls the router to do the navigation.
ngOnInit() {
if (app.android) {
app.android.on(app.AndroidApplication.activityBackPressedEvent,
(args: any) => this.backEvent(args));
}
}
backEvent(args) {
args.cancel = true;
this.backToRegister(false);
}
backToRegister(accepted: boolean){
this.router.navigate(['/register',
this.registerParametersEntered.password,
this.registerParametersEntered.confirmPassword,
this.registerParametersEntered.code,
this.registerParametersEntered.email,
accepted]);
}
I want to do something similar with iOS, such as: -
if (app.ios) {
this.page.on('navigatingFrom', (data) => {
// TODO cancel the back button event
this.backToRegister(false);
})
}
I can't find a way of doing this for iOS - my research is leading me to the conclusion it is not possible to cancel the iOS back button - for example, see here.
Any ideas or alternative suggestions greatly appreciated!
You can't override the back button for iOS. See this SO question. You basically need to create a custom button, you can mimic the appearance of the back button on iOS and add your own event handler. That's how you'd do it in a native iOS app, and how you do it in NativeScript since the native controls are used via NativeScript.
The actionbar in nativescript can have a custom layout inside or you can just use an action-item and position it on the left for iOS, while also hiding the button on Android if you desire.
Another solution would be, instead of catching the back button event just to throw it away/disable it - to just clear the history after you are switching a page where there no "back" to go to.
this.router.navigate(['level1'], {
clearHistory: true
}
I have recently updated to ios 10 and all of my Xamarin pages and have been bumped up behind the title bar. Also the bottom of the page now does not touch the screen, it has also been bumped up.
This has happened not just for local projects, but also for an App I have already published in the App store!
The pages are bumped up around 200px or the height of the title bar.
Does anyone know of anything I can do for this???!?
To fix this issue, update to the latest version of the Xamarin Forms Nuget Package. To do this right click on your solution in Xamarin Studio and click Update Nuget Packages. This will update all of your NuGet Packages including the Xamarin.Forms nuget package, and will fix this issue.
Note that just installing the latest version of Xamarin Studio will not fix this, you must manually update the Nuget Packages!
Credit goes to #Scott for his help!!!
I had the same issue in my Xamarin.Forms app. What I had to do was set the NavigationBar translucent property to false through a custom renderer. If you're not using Forms, you can set this value in the ViewController itself.
var navBar = this.NavigationController?.NavigationBar;
if (navBar != null)
{
navBar.Translucent = false;
}
Again, if you're not using forms, try setting the navigation bar's translucent property to false in the ViewController, or Storyboard.
I will say though, that for Forms, this was only required on older versions of Xamarin.Forms, and the latest version fixes this itself.
Edit: Quick (untested) Content Page renderer that should resolve this issue
using TestApp.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly:ExportRenderer(typeof(ContentPage), typeof(ContentPageRenderer))]
namespace TestApp.iOS
{
public class ContentPageRenderer : PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var navBar = this.NavigationController?.NavigationBar;
if (navBar != null)
{
navBar.Translucent = false;
}
}
}
}
I want to add a field to the Phone Screen when a screen is received. I successfully made this using the following code:
public void callIncoming(int callId) {
PhoneScreen ps = new PhoneScreen(Call, UiApplication.getApplication());
PhoneScreenHorizontalManager manager = new PhoneScreenHorizontalManager();
LabelField label = new LabelField("Call Received");
manager.add(label);
ps.add(manager);
ps.setScreenBackground(Color.RED);
ps.sendDataToScreen();
}
I tried this code on the following devices:
BB Mini Curve, Bold 4, Bold 2 and Curve and this works like a charm with all the functionality I want. A background colored red is appearing in the area where I can draw fields
I tried it on these phones and the label field did not appear: Torch, Bold3
On these phones, When I add data to the screen, I guess that these fields are appearing below the ringer off notification. With these devices, no Background is appearing... So this is a main issue.
How to solve this and make the fields appear on these phones too?
Thanks in advance
I don't have the answer, but have started a thread here:
http://supportforums.blackberry.com/t5/Java-Development/PhoneScreenDemo-not-displaying-information-on-os6/m-p/1450769#M184811
I've opened a RIM ticket and will share info as I get it.
As far as I can see PhoneScreen has big issues and is not consistently supported across devices.
Using isSupported() will only determine if the device screen type supports the API, (SVG is required according to RIM Jira ticket), not if it will actually work.
I have a simple WebView that runs a web application on an Android. The problem is when I rotate the phone to change it to landscape the webview reloads and goes back to the beginning.
How can I prevent this action?
Ron
Beginning with Android 3.2 (API level 13), the "screen size" also
changes when the device switches between portrait and landscape
orientation. Thus, if you want to prevent runtime restarts due to
orientation change when developing for API level 13 or higher (as
declared by the minSdkVersion and targetSdkVersion attributes), you
must include the "screenSize" value in addition to the "orientation"
value. That is, you must decalare
<activity android:configChanges="orientation|screenSize">
Excerpt from Handle configuration changes (webarchive to original page)
This can be resolved by overriding onSaveInstanceState(Bundle outState) in your activity and calling saveState from the Webview:
This blog post may be of help to you.
Add the following to your AndroidManifest:
android:configChanges="orientation|keyboard|keyboardHidden"
So it should look something like this:
<activity android:name=".MyActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboard|keyboardHidden">
Obviously, if your WebView needs keyboard support then don't include the keyboard options.
Add this before the oncreate
#Override
protected void onSaveInstanceState(Bundle outState) {
webview.saveState(outState);
}
Write the oncreate this way. put final
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layoutname);
if (savedInstanceState != null)
{
((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
else
{
webview.loadUrl("http://www.playbuzz.org/");
}
}
In Androidmanifest insert under the activity
android:configChanges="keyboardHidden|orientation"
#Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
Add above method in your activity.. and
android:configChanges="keyboard|keyboardHidden|orientation"
in your manifest file
The problem with the above solution is that it renders the screen white for some time before the webview redraws the contents.
Try using
android:configChanges="orientation|keyboardHidden" inside your AndroidManifest.xml file for the activity that displays the webview. That should help.
Add in Activity
android:configChanges="keyboardHidden|orientation"
I have a application with a screen manager class that is causing me some problems.
The application makes requests to the server to perform searches and allows the user to view results.
The application has worked fine on all OS versions up to 4.5 where we are sudden having
problems viewing a screen under certain circumstances.
It occurs when the user has performed a search and they wait for the results.
While waiting for results, they press the trackball which displays a menu.
This is not needed to display the results, it just happened that the user decided to press it.
When the results come back from the server, the results screen should automatically be displayed. On OS 4.5, the code displays the results screen runs but then the application completely falls over. If the user doesn't press the trackball while waiting, the application works fine.
Looking at the logs, they show no exception being thrown and the only suspect line being
System data:VM:DPNAv=78,p
By adding in some more log lines I have discovered that the code is reaching the
UiApplication.getUiApplication().popScreen(screen);
line in the method hideScreen(Screen screen) but when called from hideCurrentScreen(). By adding in some more debugging I find that the active screen at this point is DefaultMenuScreen (as the menu button has been pressed)
So it seems the problem is that I am trying to pop one of my own screens from the display
stack when the DefaultMenuScreen one is the active one. I repeat that this code did work on OS previous to 4.5. By running the same code on the 8300 with OS 4.2.2 with the debugging statements, I can see that the same thing happens, the active screen is the DefaultScreen but removing my own screen does not cause the whole application to crash.
The one way round this I could see, was to change the hideCurrentScreen() to just remove the active screen but this does not seem like the correct way to do it.
Has anyone else had experience of this? Can anyone tell me why this is happening? What are we meant to do if we cannot remove our screens when a DefaultMenuScreen is the active one?
This occurs in both device and simulator for 8310 and 9700.
The screen manager code is as follows.
public class ScreenManager
{
private Hashtable screens;
private String currentScreenName;
public ScreenManager()
{
screens=new Hashtable();
}
/**
* Description of the Method
*
*#param sCardName Description of Parameter
*/
public boolean showScreen( String sScreenName )
{
boolean bSuccess=false;
if (sScreenName != null && sScreenName.length() > 0 )
{
MainScreen screen=(MainScreen)screens.get(sScreenName);
if (screen!=null)
{
// We have a new screen to display so pop the current screen off the stack
hideCurrentScreen();
// If the screen is on the stack then pop the screens until we get our target screen
// otherwise just push the screen onto the stack.
if (screen.isDisplayed())
{
Screen activeScreen=null;
synchronized(UiApplication.getEventLock())
{
activeScreen=UiApplication.getUiApplication().getActiveScreen();
}
while (screen!=activeScreen && activeScreen!=null)
{
activeScreen=hideScreen(activeScreen);
}
bSuccess=(screen==activeScreen);
}
else
{
synchronized(UiApplication.getEventLock())
{
UiApplication.getUiApplication().pushScreen(screen);
bSuccess=true;
}
}
}
}
if (bSuccess)
{
this.currentScreenName=sScreenName;
}
else
{
Logger.warning("ScreenManager: Failed to display screen ["+ sScreenName +"]");
}
return bSuccess;
}
private Screen hideCurrentScreen()
{
Screen activeScreen=null;
if(currentScreenName!=null)
{
MainScreen screen=(MainScreen)screens.get(currentScreenName);
activeScreen=hideScreen(screen);
}
return activeScreen;
}
private Screen hideScreen(Screen screen)
{
Screen activeScreen=null;
if (screen!=null && screen.isDisplayed())
{
Logger.finest("Hiding Screen ["+currentScreenName+"]");
synchronized(UiApplication.getEventLock())
{
UiApplication.getUiApplication().popScreen(screen);
activeScreen=UiApplication.getUiApplication().getActiveScreen();
}
Logger.finest("Hid Screen ["+currentScreenName+"]");
}
return activeScreen;
}
//Rest of code omitted
}
The only way round this I managed to find was what I mentioned in the question. When I want to remove the current screen. I need to check it is the same as the active screen. If it is not the same then I just remove the active screen until I reach the screen I am looking for. This would only happen if a menu or pop up was displayed. Also, I need to add checks to my custom pop-up code to make sure it does not try and remove a screen that has already been removed.
It seems a bit messy but could not find any other alternatives.
The way we pop screens in our app is to explicitly pop the screen you want off the stack, as opposed to just the top-most screen. This either requires keeping track of which screens you have on the stack, or some code to iterate through the screens on the stack and search for the particular screen you want to pop off.