How to show iOS add contact screen from Xamarin Fo

2019-04-02 21:50发布

问题:

I'm trying to show the iOS add contact screen using Xamarin Forms. From what I can see Xamarin Forms does not support this out of the box but Xamarin iOS does. Unfortunately I can't get them to work together. What I mean by "together" is that I need get access to NavigationController from Xamarin Forms Page.

Can this be done?

I have a sample solution that demonstrates the problem here: https://github.com/pawelpabich/XamarinFormsContacts. I also put the most important code below.

public void ShowContact(NavigationPage page)
{
    var newPersonController = new ABNewPersonViewController();
    var person = new ABPerson();
    person.FirstName = "John";
    person.LastName = "Doe";

    newPersonController.DisplayedPerson = person;
    var controller = page.CreateViewController();

    //!!!!---> controller.NavigationController is null !!!!!<----
    controller.NavigationController.PushViewController(newPersonController, true);
}

I updated the repo and it now contains code that works.

回答1:

There is a UINavigationController when using Xamarin.Forms (when using a NavigationPage), but you have to search for it. This was the only way I could get a hold of it. Those other methods, CreateViewController and RendererFactory actually create a new ViewController which isn't what you wanted.

public void ShowContact(NavigationPage page)
{
    var newPersonController = new ABNewPersonViewController();
    var person = new ABPerson();
    person.FirstName = "John";
    person.LastName = "Doe";
    newPersonController.Title = "This is a test";

    newPersonController.DisplayedPerson = person;

    UINavigationController nav = null;
    foreach (var vc in 
      UIApplication.SharedApplication.Windows[0].RootViewController.ChildViewControllers) 
    {
        if (vc is UINavigationController)
            nav = (UINavigationController)vc;
    }

    nav.PresentModalViewController(new UINavigationController (newPersonController), true);
}

I also attempted to Create a PersonPage and PersonPageRenderer, as that would be the cleanest solution, but I couldn't get it working. This could work if you spent some time.

[assembly: ExportRenderer(typeof(PersonPage), typeof(PersonPageRenderer))] 

public class PersonPageRenderer : ABNewPersonViewController, IVisualElementRenderer, IDisposable, IRegisterable 


回答2:

Pawel, the problem is that when you use Xamarin.Forms no NavigationController is created (as I know at least in X.F 1.3+, maybe Michael will prove me wrong). If you want to create new address boo element you can use this approach - How do you add contacts to the iPhone Address book with monotouch?



回答3:

Because iOS Add Contact screen is a Native iOS API and your application logic is in a PCL you need to use a DependancyService.

1) To do this in the PCL create a Interface which provides the functionality, like

public interface ILocalAddContact 
{   
    void DisplayContactScreen(Contact contact) 
}

2) Implement the Interface in the Native Applications:

public class LocalAddContactiOS : ILocalAddContact
{
    public void DisplayContactScreen(Contact contact)
    {
        //... do iOS Magic
    }
}

3) Register the Dependancy in the Top of the Native File

[assembly: Xamarin.Forms.Dependency(typeof(LocalAddContactiOS))]

4) Obtain the Dependancy from the iOS Project from the

var addContact = DependencyService.Get<ILocalAddContact> ();
addContact.DisplayContactScreen (contact);

If you take a look at this sample application on github, it's very similar (but is used for CreateCalendar).



回答4:

Ok, this is how I finally implemented. I created UINavigationController manually and use it for navigations outside Xamarin.Forms.

using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using UIKit;
using Xamarin.Forms;
using AddressBookUI;
using AddressBook;

namespace TestContacts.iOS
{
    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        UIWindow window;
        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init ();
            window = new UIWindow(UIScreen.MainScreen.Bounds);

            var nav = 
                new UINavigationController(new App ().MainPage.CreateViewController());
            ContactsShared.Instance = new TouchContacts (nav);
            window.RootViewController = nav;

            window.MakeKeyAndVisible();

            return true;
        }
    }

    public class TouchContacts : IContactsShared {
        UINavigationController nav;
        public TouchContacts(UINavigationController nav){
            this.nav = nav;
        }
        public void Show() {

            var newPersonController = new ABNewPersonViewController();
            newPersonController.NewPersonComplete += 
               (object sender, ABNewPersonCompleteEventArgs e) => 
            {    
                nav.PopViewController(true);
            };
            var person = new ABPerson();
            person.FirstName = "John";
            person.LastName = "Doe";


            newPersonController.DisplayedPerson = person;
            nav.PushViewController(newPersonController, true); 
        }
    }
}