How to present an iOS Modal View in MvvmCross - xamarin

How can I present a modal view on iOS using MvvmCross?
Using Xamarin Studio on iOS and the MvvmCross NuGet version 4.2.2, none of the MvxModalSupportTouchViewPresenter, MvxModalNavSupportTouchViewPresenter or IMvxModalTouchView are even available.
Does the ViewModel even need to know about the fact that a particular view is presented as a modal view on iOS?

MvvmCross is a strong Page navigation framework. Default navigation using ShowViewModel<AViewModel> will use the stack metaphor: one on top of another on Android, slide atop each other on iOS, and use < on either platform to go back.
You can tell the ViewPresenter that a given view is modal by giving it a hint, in the form of an interface marker, by adopting IMvxModalIosView.
At the View Level
Adopt the IMvxModalIosView protocol:
public partial class AView : MvxViewController, IMvxModalIosView
At the AppDelegate Level
Replace var setup = new Setup(this, Window) by:
var presenter = new MvxModalSupportIosViewPresenter(this, Window);
var setup = new Setup(this, presenter);
setup.Initialize();
At the ViewModel Level
No change required. The ViewModel is actually not made aware of the modal presentation. Invoke:
ShowViewModel<AViewModel> // May be modal on certain platforms
To close a Page and go back to the previous one, regardless of your presentation style, use Close(this) on that very ViewModel. This will close a modal dialog, or pop a pushed view. A complete, bindable ICommand may look like this:
public ICommand BackCommand {
get { return new MvxCommand(() => Close(this)); }
}
Notes: In MvvmCross 4.2.2, Touch has been renamed iOS, so IMvxModalTouchView is now IMvxModalIosView. The new using are:
using MvvmCross.iOS.Platform;
using MvvmCross.iOS.Views.Presenters;

Using MvvmCross 5.5.2 all I had to get a modal was to add the following MvxModalPresentation attribute to my iOS view:
[Register("ExampleModalView")]
[MvxModalPresentation(
ModalPresentationStyle = UIModalPresentationStyle.PageSheet,
ModalTransitionStyle = UIModalTransitionStyle.CoverVertical
)]
public class ExampleModalView : MvxViewController
{
public ExampleModalView() {
}
...
}
Launching the modal is simple with the IMvxNavigationService service
await _navigationService.Navigate<ExampleModalViewModel>();
ExampleModalViewModel just needs to be a plain MvvmCross view model inheriting from MvxViewModel.
A useful reference for this is ModalView.cs in the iOS playground project: https://github.com/MvvmCross/MvvmCross/blob/develop/TestProjects/Playground/Playground.iOS/Views/ModalView.cs#L12

Related

Shell BackButtonBehavior command binding not working in UWP

I am kind of new to Xamarin development. I tried to change the back button behavior with a binding command, but that didn't seem to work. This is the code for the view:
<Shell.BackButtonBehavior>
<BackButtonBehavior Command="{Binding GoBack}"/>
</Shell.BackButtonBehavior>
And this is the code for the view model:
public CreatePasswordVM()
{
_goBack = new Command(GoBackButton);
}
private ICommand _goBack;
public ICommand GoBack
{
get { return _goBack; }
}
public async void GoBackButton()
{
await Shell.Current.GoToAsync("../..");
}
When I pressed the back button, the method "GoBackButton" didn't call. I want to mention that on Android works.
Shell BackButtonBehavior command binding not working in UWP
Derive from Xamarin Form source code. BackButtonBehavior has not implemented for UWP platform, we could find Android and IOS implementation here and here. But for uwp there is not such tracker and there is not such value in the UWP ShellRenderer. For this scenario, we suggest your post new feature request in the Xamarin Forms github.

Show modal page on only a portion of the screen

I am developing an iPad app using Xamarin.Forms.
I would like my settingspage to be modal so it lay over the previous page like a popup.
I have been trying all solutions I could find and most of them seems to recommend me to call this from a button:
await Navigation.PushModalAsync(ModalSettingsPage);
What happens when I use it is that my settingspage comes in from below as a modal page but not as a popup, it covers the entire screen.
This is my current code:
//Setup button (action bar)
ToolbarItems.Add(new ToolbarItem
{
// Text = "Setup",
Icon = "settings1.png",
Order = ToolbarItemOrder.Default,
Command = new Command(() => Navigation.PushModalAsync(new ModalSettingsPage())) //Action to perfome on click , open modal view
});
Also, does anyone now if there is any good way to positions the ToolbarItems? I have two items and would like each one to be positioned at each side, but by default they are both positioned to the right.
With the evolution of Forms (currently 4.5.0), it has now become simple to push a modalpage which is not fullscreen. Use the following in your code-behind of your xaml contentpage:
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace YourAppWithAModalPage
{
public class ModalPage : ContentPage
{
public ModalPage()
{
// iOS Solution for a ModalPage (popup) which is not fullscreen
On<iOS>().SetModalPresentationStyle(UIModalPresentationStyle.FormSheet);
}
}
}
There is nothing pre-made in Forms to give you a popup like I think you want. Instead, you would have to create this or use a third-party solution. For example, here is a "popup" implementation that might work for you.

How to handle screen rotation/orientation in Xamarin Forms?

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.

Capture touch events in Xamarin.Forms for Android

I am creating an app that allows the user to drag and drop to put one image on top of another using Xamarin.Forms.
On iOS I managed to hack together a workable gesture recognizer renderer by creating a custom ContentView and a custom renderer for it, which then attaches native gesture recognizers to itself based on the GestureRecognizers elements. To do that I disable the default EventTracker and implement my own, with overridden GetNativeRecognizer method
in the custom renderer:
public InteractiveContentViewRenderer () : base ()
{
AutoTrack = false;
events = new InteractiveEventTracker (this);
}
in the custom event tracker:
public InteractiveEventTracker (IVisualElementRenderer renderer) : base (renderer)
{
this.Renderer = renderer;
}
protected override MonoTouch.UIKit.UIGestureRecognizer GetNativeRecognizer (Xamarin.Forms.IGestureRecognizer recognizer)
{
var gestureRecognizer = base.GetNativeRecognizer (recognizer);
if (gestureRecognizer == null) {
// here I find my own native recognizer and return it
}
}
On Android, however, so far I haven't figured out how to achieve the same thing. There's no EventTracker in Android, I think I'll have to implement some Android View for this to work but I haven't figured it out so far.
Has anyone managed to hack together touch events in Xamarin.Forms for Android? I'd like to know at least the basic structure of the hack?
Read this: http://blog.twintechs.com/cross-platform-compositional-gesture-advanced-xamarin-forms-techniques-for-flexible-and-performant-cross-platform-apps-part-4
There's a lot about custom gestures in Xamarin.Forms
The source is here: https://github.com/twintechs/TwinTechsFormsLib/tree/master/TwinTechsForms/TwinTechsForms.Droid/TwinTechs/Gestures

MvvmCross vnext: CheckBox CheckedChange event to a command with monodroid

I'm trying to bind CheckedChange from monodroid CheckBox to a command, but I get an error.
I want to unselect another item when a particular one is checked.
I think it is possible to do it with EventTrigger in wp7, but MvvmCross for android doesn't seem to support this feature.
Is MvvmCross limited to Button only ?
Thanks in advance for your help.
CheckedChanged is an EventHandler<CompoundButton.CheckedChangeEventArgs> so it isn't one of the delegate types that MvvmCross automatigically knows about.
However, there is a custom binding in place for this...
https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Binding.Droid/Target/MvxCompoundButtonCheckedTargetBinding.cs
And this custom binding should be registered using:
registry.RegisterFactory(new MvxSimplePropertyInfoTargetBindingFactory(typeof(MvxCompoundButtonCheckedTargetBinding), typeof(CompoundButton), "Checked"));
in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Binding.Droid/MvxAndroidBindingBuilder.cs
So if you have a ViewModel with a property IsSpecial
private bool _isSpecial;
public bool IsSpecial
{
get { return _isSpecial; }
set
{
_isSpecial = value;
RaisePropertyChanged(() => IsSpecial);
// your custom code here
}
}
then this binding should work:
'Checked':{'Path':'IsSpecial'}
And that should work for any CompoundButton - CheckBox, Switch, or your own compounds...

Resources