I need a combined date & time picker in a Xamarin.Forms project, so I used a custom View & Renderer which works great on my iPhone 8 Plus test device. Unfortunately on an iPhone XS or 11 Pro (physical devices, both on 13.3) the picker does not render correctly - all the dates are greyed out, and time is completely invisible yet present (I can feel the 'clicks' when swiping up/down in the area where it would be). Unsurprisingly, the simulator for both those devices renders correctly. Full sample project along with screenshots from both devices on GitHub. Here's the relevant code from the renderer in case anything jumps out:
protected override void OnElementChanged(ElementChangedEventArgs<MyDatePicker> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
_datePicker.ValueChanged -= DatePickerOnValueChanged;
}
if (e.NewElement != null)
{
if (Control == null)
{
_datePicker = new UIDatePicker(new CGRect(
e.NewElement.Bounds.X,
e.NewElement.Bounds.Y,
e.NewElement.Bounds.Width,
e.NewElement.Bounds.Height
));
_datePicker.Mode = UIDatePickerMode.DateAndTime;
_datePicker.Date = (NSDate) Element.Date;
_datePicker.MaximumDate = (NSDate) Element.Date.AddDays(1);
_datePicker.MinimumDate = (NSDate) Element.Date.Subtract(TimeSpan.FromDays(5));
_datePicker.MinuteInterval = 1;
SetNativeControl(_datePicker);
}
_datePicker.ValueChanged += DatePickerOnValueChanged;
}
}
This issue was solved by the extremely knowledgable ColeX over on the Xamarin Forums. ColeX should really get the points for this, but I'm posting the answer here so that if anyone else searches for this issue on SO they will see a solution.
The root cause is dark mode on iOS when the app is not setup to render itself differently for light/dark mode. As a result the OS thinks it is rendering a date picker on a dark background, which it was not, and so it was effectively invisible. There are a few solutions mentioned, but the one that worked for me was add the following to Info.plist in the iOS project:
<key>UIUserInterfaceStyle</key>
<string>Light</string>
Related
Following the Embarcadero docs at this link i'm testing notifications on iOS (in FMX app built with C++). I've done the follownig:
Added #include <System.Notification.hpp> to the header file
Set FMLocalNotificationPermission to true
Dropped TNotificationCenter component on the form
Then, i put the following code in a button click:
void __fastcall TForm1::ScheduleNotificationClick(TObject *Sender)
{
if (NotificationCenter1->Supported()) {
TNotification *myNotification = NotificationCenter1->CreateNotification();
__try {
myNotification->Name = "MyNotification";
myNotification->AlertBody = "C++ for your mobile device is here!";
// Fire in 10 seconds
myNotification->FireDate = Now() + EncodeTime(0, 0, 10, 0);
// Send notification to the notification center
NotificationCenter1->ScheduleNotification(myNotification);
}
__finally {
myNotification->DisposeOf();
}
}
}
Once in a while it works...but rarely and never more than once. Most of the time it doesn't at all (repeated deleting and reinstall of app).
Next, i tried the "Present the Notification Message Immediately" code they provide:
void __fastcall TForm1::PresentNotificationClick(TObject *Sender)
{
if (NotificationCenter1->Supported()) {
TNotification *myNotification = NotificationCenter1->CreateNotification();
__try {
myNotification->Name = "MyNotification";
myNotification->AlertBody = "C++ for your mobile device is here!";
// Set Icon Badge Number (for iOS) or message number (for Android) as well
myNotification->Number = 18;
myNotification->EnableSound = False;
// Send notification to the notification center
NotificationCenter1->PresentNotification(myNotification);
}
__finally {
myNotification->DisposeOf();
}
}
}
Nothing happens at all with this code. I've tried this from scratch several times and i'm as sure as i can be that i'm coding it per their examples. I'm using 10.3 (Embarcadero® C++Builder 10.3 Version 26.0.32429.4364). I would think my code has a problem except once in blue moon it works.
My target is iPhone running 12.1.4 and i've tried building with SDK11.4 and SDK12.0, no difference. When i first run app i get the "allow or don't allow" popup and my app subsequently shows up in the Notification settings - just doesn't work.
russ
UPDATE 3-25-2019: If I run that top block of code (from a button click on iPhone) it will now run everytime - but ONLY IF i immediately kill the app after clicking. 10 seconds later it fires the notification. Why won't the notification appear if i leave my app running??
Are you sure you are calling "PresentNotificationClick" from the TButton when you click it?
I'm following the maps example https://developer.xamarin.com/samples/xamarin-forms/customrenderers/map/circle/ to create custom renderer to overlay circles. It seems to be working fine for all 3 platforms except I am unable to find any click event for iOS.
I am building a xamarin forms app and able to find out the click event on both Android and UWP but iOS seems to be far fetched.
Is there any way to do it?
iOS doesn't provide the API which detects the click event.
As a alternative workaround, we can add UITapGestureRecognizer on the mapview and judge if the tap point locates inside the circle.
Solution
//xxx
nativeMap.AddOverlay(circleOverlay);
nativeMap.AddGestureRecognizer(new UITapGestureRecognizer(TapHandle));
void TapHandle(UITapGestureRecognizer tap)
{
MKMapView mapView = tap.View as MKMapView;
CGPoint tapPoint = tap.LocationInView(mapView);
CLLocationCoordinate2D tapCoordinate = mapView.ConvertPoint(tapPoint, tap.View);
MKMapPoint point = MKMapPoint.FromCoordinate(tapCoordinate);
foreach(IMKOverlay overlay in mapView.Overlays)
{
MKCircleRenderer render = GetOverlayRenderer(mapView, overlay) as MKCircleRenderer;
CGPoint datPoint = render.PointForMapPoint(point);
render.InvalidatePath();
if (render.Path.ContainsPoint(datPoint,false))
{
break;
}
}
}
I've been working on this Xamarin Forms mobile application and I've been loving it but it's a media player application and the native embedding for the platform specific video player doesn't work. After much debugging I was able to get the audio playing but no video would show up. I think this has to do with the views just not being swapped out appropriately. Unfortunately there isn't much material on how to effectively switch from a Xamarin Forms view to a native view (to see the video) through Xamarin Forms. Any help is appreciated thank you !
I was able to get iOS videos working by using the Xamarin Forms messaging service to Appdelegate class and built the AVPlayer class there. Works great.
playVideo.Clicked += (sender, e) =>
MessagingCenter.Send(this, "ShowVideoPlayer", new
ShowVideoPlayerArguments(videoUrl));
Appdelegate.cs
MessagingCenter.Subscribe<VideoDetailPage,
ShowVideoPlayerArguments>(this, "ShowVideoPlayer",
HandleShowVideoPlayerMessage);
//messaging center class
private void HandleShowVideoPlayerMessage(Page page,
ShowVideoPlayerArguments arguments)
{
var presentingViewController = GetMostPresentedViewController();
var url = NSUrl.FromString(arguments.Url);
var avp = new AVPlayer(url);
var avpvc = new AVPlayerViewController();
avpvc.Player = avp;
avp.Play();
presentingViewController.PresentViewController(avpvc, animated: true,
completionHandler: null);
}
private UIViewController GetMostPresentedViewController()
{
var viewController =
UIApplication.SharedApplication.KeyWindow.RootViewController;
while (viewController.PresentedViewController != null){
viewController = viewController.PresentedViewController;
}
return viewController;
}
However.. Getting this to work with Android is a whole different animal since I have to have deal with .axml layouts I believe.. Any help with this would be greatly appreciate.. Thanks so much guys.
So I figured out an implementation using Native Views, an alternative to Custom Renderers. Such a more stream lined process.
Is there a (half) generic way to handle rotation/orientation in Xamarin Forms for different views and platforms (Android, iOS, WinPhone)?
The UI does rotate, and that is nice enough, though it wreaks havoc to my layout (absolute layout right now). I suppose with a Stacklayout I could make it a litte more flexible, but would then hit a road block somewhere else when the layout is more intricate.
Can I somehow display different views for portrait and landscape, with the same ViewModel? (I am using XLABs based MVVM.)
Possible solutions I have found:
http://blog.rthand.com/post/2014/07/24/Different-XAML-layouts-for-different-device-orienations-in-XamarinForms.aspx is lacking iOS and I wonder if it will handle MVVM too well, seems good though and I am investigating it right now
http://www.jimbobbennett.io/orientation-with-xamarin-forms/ sounds promising but the sample is iOS only, the linked GIT repository has no documentation at all, it just says "Xamarin Helpers"
http://www.sellsbrothers.com/posts/Details/13740 might also be a possibility for programmatically created views. Though in my tests I did not get a size changed event (though I listened at a different code place) for ios simulator when rotating. (The solution is based on size changed to detect rotation.)
If you are already using XLabs then you could use IXFormsApp and property 'Orientation' and event handler 'Rotation'. You would have to add the native observers per platform and set IXFormsApp's 'Orientation' there which would cause the event handler to invoke.
For example on iOS:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
var xapp = new XFormsAppiOS();
xapp.Init(this);
var resolverContainer = new SimpleContainer();
resolverContainer.Register<IXFormsApp>(xapp);
Resolver.SetResolver(resolverContainer.GetResolver());
var a = new App();
LoadApplication(a);
UIDevice.Notifications.ObserveOrientationDidChange((s, e) =>
{
xapp.Orientation = ... // set orientation here
});
Now you can monitor orientation changes by resolving IXFormsApp:
xapp = Resolver.Resolve<IXFormsApp>();
if (xapp.Orientation == Orientation.Landscape) { ... } else { ... }
xapp.Rotation += (sender, args) =>
{
switch (args.Value)
{
case Orientation.LandscapeLeft:
break;
default:
// etc.
break;
}
};
As for layouts I would imagine RelativeLayout would be the most convenient choice as you could put the orientation inside the Constraint's. On rotation make the layout refresh itself.
What I wud like my app to ideally do is this, to show pivots with their contents in portrait mode and to show a graph when the phone is tilted and set to landscape mode.
I have used OnOrientationChanged() to detect the orientation changes.
Do i have to navigate to a new page if i have to show the graph? Or can i manage it in the same pivot page??
Again does windows phone have graphing tools? or have to rely on the 3rd party tools?
Alfah
Why not just draw both controls and in OrientationChanged adjust the visibilities to what you need? Remember to set your controls correctly for the initial state, too...
protected override void OnOrientationChanged(OrientationChangedEventArgs e)
{
if (e.Orientation == PageOrientation.Portrait)
{
MyPivot.Visibility = Visibility.Visible;
MyGraph.Visibility = Visibility.Collapsed;
}
else
{
MyPivot.Visibility = Visibility.Collapsed;
MyGraph.Visibility = Visibility.Visible;
}
}