Kontakty i interfejs ContactsUI na platformie Xamarin.iOS
W tym artykule opisano pracę z nowymi strukturami interfejsu użytkownika Kontakty i kontakty w aplikacji platformy Xamarin.iOS. Te struktury zastępują istniejącą książkę adresową i interfejs użytkownika książki adresowej używany w poprzednich wersjach systemu iOS.
Wraz z wprowadzeniem systemu iOS 9 firma Apple wydała dwie nowe struktury i Contacts
ContactsUI
, które zastępują istniejące struktury interfejsu użytkownika książki adresowej i książki adresowej używane przez system iOS 8 i starsze.
Dwie nowe struktury zawierają następujące funkcje:
Kontakty — zapewnia dostęp do danych listy kontaktów użytkownika. Ponieważ większość aplikacji wymaga tylko dostępu tylko do odczytu, ta struktura została zoptymalizowana pod kątem bezpiecznego wątkowego dostępu tylko do odczytu.
ContactsUI — udostępnia elementy interfejsu użytkownika platformy Xamarin.iOS do wyświetlania, edytowania, wybierania i tworzenia kontaktów na urządzeniach z systemem iOS.
Ważne
Istniejące AddressBook
platformy i AddressBookUI
używane przez system iOS 8 (i wcześniejsze) zostały uznane za przestarzałe w systemie iOS 9 i powinny zostać zastąpione nowymi Contacts
ContactsUI
strukturami tak szybko, jak to możliwe dla dowolnej istniejącej aplikacji platformy Xamarin.iOS. Nowe aplikacje powinny być zapisywane w nowych strukturach.
W poniższych sekcjach przyjrzymy się tym nowym strukturom i sposobom ich implementowania w aplikacji platformy Xamarin.iOS.
Struktura kontaktów
Platforma Kontaktów zapewnia dostęp platformy Xamarin.iOS do informacji kontaktowych użytkownika. Ponieważ większość aplikacji wymaga tylko dostępu tylko do odczytu, ta struktura została zoptymalizowana pod kątem bezpiecznego wątkowego dostępu tylko do odczytu.
Obiekty kontaktu
Klasa CNContact
zapewnia bezpieczny wątkowo dostęp tylko do odczytu do właściwości kontaktu, takich jak Nazwa, Adres lub Numery Telefon. CNContact
funkcje takie jak i NSDictionary
zawierają wiele kolekcji właściwości tylko do odczytu (takich jak adresy lub numery telefonów):
W przypadku każdej właściwości, która może mieć wiele wartości (takich jak adres e-mail lub numery telefonów), będą one reprezentowane jako tablica NSLabeledValue
obiektów. NSLabeledValue
to bezpieczna krotka wątkowa składająca się z zestawu etykiet i wartości tylko do odczytu, w których etykieta definiuje wartość użytkownikowi (na przykład wiadomość e-mail home lub work). Platforma Kontakty udostępnia wybór wstępnie zdefiniowanych etykiet (za pośrednictwem CNLabelKey
klas statycznych i CNLabelPhoneNumberKey
), których można używać w aplikacji lub istnieje możliwość definiowania etykiet niestandardowych dla Twoich potrzeb.
W przypadku dowolnej aplikacji platformy Xamarin.iOS, która musi dostosować wartości istniejącego kontaktu (lub utworzyć nowe), użyj NSMutableContact
wersji klasy i jej klas podrzędnych (takich jak CNMutablePostalAddress
).
Na przykład poniższy kod utworzy nowy kontakt i doda go do kolekcji kontaktów użytkownika:
// Create a new Mutable Contact (read/write)
var contact = new CNMutableContact();
// Set standard properties
contact.GivenName = "John";
contact.FamilyName = "Appleseed";
// Add email addresses
var homeEmail = new CNLabeledValue<NSString>(CNLabelKey.Home, new NSString("john.appleseed@mac.com"));
var workEmail = new CNLabeledValue<NSString>(CNLabelKey.Work, new NSString("john.appleseed@apple.com"));
contact.EmailAddresses = new CNLabeledValue<NSString>[] { homeEmail, workEmail };
// Add phone numbers
var cellPhone = new CNLabeledValue<CNPhoneNumber>(CNLabelPhoneNumberKey.iPhone, new CNPhoneNumber("713-555-1212"));
var workPhone = new CNLabeledValue<CNPhoneNumber>("Work", new CNPhoneNumber("408-555-1212"));
contact.PhoneNumbers = new CNLabeledValue<CNPhoneNumber>[] { cellPhone, workPhone };
// Add work address
var workAddress = new CNMutablePostalAddress()
{
Street = "1 Infinite Loop",
City = "Cupertino",
State = "CA",
PostalCode = "95014"
};
contact.PostalAddresses = new CNLabeledValue<CNPostalAddress>[] { new CNLabeledValue<CNPostalAddress>(CNLabelKey.Work, workAddress) };
// Add birthday
var birthday = new NSDateComponents()
{
Day = 1,
Month = 4,
Year = 1984
};
contact.Birthday = birthday;
// Save new contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, store.DefaultContainerIdentifier);
// Attempt to save changes
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error))
{
Console.WriteLine("New contact saved");
}
else
{
Console.WriteLine("Save error: {0}", error);
}
Jeśli ten kod zostanie uruchomiony na urządzeniu z systemem iOS 9, do kolekcji użytkownika zostanie dodany nowy kontakt. Na przykład:
Formatowanie i lokalizacja kontaktu
Platforma Kontakty zawiera kilka obiektów i metod, które mogą ułatwić formatowanie i lokalizowanie zawartości do wyświetlania użytkownikowi. Na przykład następujący kod poprawnie sformatowałby nazwę kontaktów i adres wysyłkowy do wyświetlenia:
Console.WriteLine(CNContactFormatter.GetStringFrom(contact, CNContactFormatterStyle.FullName));
Console.WriteLine(CNPostalAddressFormatter.GetStringFrom(workAddress, CNPostalAddressFormatterStyle.MailingAddress));
W przypadku etykiet właściwości, które będą wyświetlane w interfejsie użytkownika aplikacji, platforma Contact zawiera również metody lokalizowania tych ciągów. Ponownie jest to oparte na bieżących ustawieniach regionalnych urządzenia z systemem iOS, na których jest uruchamiana aplikacja. Na przykład:
// Localized properties
Console.WriteLine(CNContact.LocalizeProperty(CNContactOptions.Nickname));
Console.WriteLine(CNLabeledValue<NSString>.LocalizeLabel(CNLabelKey.Home));
Pobieranie istniejących kontaktów
Korzystając z wystąpienia CNContactStore
klasy, można pobrać informacje kontaktowe z bazy danych kontaktów użytkownika. Zawiera CNContactStore
wszystkie metody wymagane do pobierania lub aktualizowania kontaktów i grup z bazy danych. Ponieważ te metody są synchroniczne, zaleca się uruchomienie ich w wątku w tle, aby uniemożliwić blokowanie interfejsu użytkownika.
Używając predykatów (utworzonych na podstawie CNContact
klasy), można filtrować wyniki zwracane podczas pobierania kontaktów z bazy danych. Aby pobrać tylko kontakty zawierające ciąg Appleseed
, użyj następującego kodu:
// Create predicate to locate requested contact
var predicate = CNContact.GetPredicateForContacts("Appleseed");
Ważne
Predykaty ogólne i złożone nie są obsługiwane przez platformę Kontakty.
Aby na przykład ograniczyć pobieranie tylko do właściwości GivenName i FamilyName kontaktu, użyj następującego kodu:
// Define fields to be searched
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName};
Na koniec, aby przeszukać bazę danych i zwrócić wyniki, użyj następującego kodu:
// Grab matching contacts
var store = new CNContactStore();
NSError error;
var contacts = store.GetUnifiedContacts(predicate, fetchKeys, out error);
Jeśli ten kod został uruchomiony po przykładzie utworzonym w powyższej sekcji Obiekt kontaktów, zwróci on właśnie utworzony kontakt "John Appleseed".
Prywatność dostępu do kontaktów
Ponieważ użytkownicy końcowi mogą udzielać lub odmawiać dostępu do informacji kontaktowych na podstawie poszczególnych aplikacji, po raz pierwszy wykonasz połączenie z CNContactStore
usługą , zostanie wyświetlone okno dialogowe z prośbą o zezwolenie na dostęp do aplikacji.
Żądanie uprawnień zostanie wyświetlone tylko raz, przy pierwszym uruchomieniu aplikacji, a kolejne uruchomienia lub wywołania do obiektu będą używać CNContactStore
uprawnienia wybranego w tym czasie przez użytkownika.
Należy zaprojektować aplikację tak, aby bezpiecznie obsługiwała użytkownika odmawiającego dostępu do bazy danych kontaktów.
Pobieranie częściowych kontaktów
Kontakt częściowy to kontakt, dla którego pobrano tylko niektóre z dostępnych właściwości z magazynu kontaktów. Jeśli spróbujesz uzyskać dostęp do właściwości, która nie została wcześniej pobrana, spowoduje to wyjątek.
Możesz łatwo sprawdzić, czy dany kontakt ma żądaną właściwość przy użyciu IsKeyAvailable
metod CNContact
lub AreKeysAvailable
wystąpienia. Na przykład:
// Does the contact contain the requested key?
if (!contact.IsKeyAvailable(CNContactOption.PostalAddresses)) {
// No, re-request to pull required info
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.PostalAddresses};
var store = new CNContactStore();
NSError error;
contact = store.GetUnifiedContact(contact.Identifier, fetchKeys, out error);
}
Ważne
Metody GetUnifiedContact
CNContactStore
i GetUnifiedContacts
klasy zwracają tylko częściowy kontakt ograniczony do właściwości żądanych z podanych kluczy pobierania.
Ujednolicone kontakty
Użytkownik może mieć różne źródła informacji kontaktowych dla jednej osoby w bazie danych kontaktów (takich jak iCloud, Facebook lub Google Mail). W aplikacjach dla systemów iOS i OS X te informacje kontaktowe będą automatycznie połączone i wyświetlane użytkownikowi jako pojedynczy, Ujednolicony kontakt:
Ten ujednolicony kontakt to tymczasowy, w pamięci widok informacji kontaktowych linku, który otrzyma własny unikatowy identyfikator (który powinien zostać użyty do ponownego pobrania kontaktu, jeśli jest to wymagane). Domyślnie platforma Kontakty zwróci ujednolicony kontakt zawsze, gdy jest to możliwe.
Tworzenie i aktualizowanie kontaktów
Jak pokazano w powyższej sekcji Obiekty kontaktu, należy użyć CNContactStore
klasy i , CNMutableContact
aby utworzyć nowe kontakty, które są następnie zapisywane w bazie danych kontaktów użytkownika przy użyciu elementu CNSaveRequest
:
// Create a new Mutable Contact (read/write)
var contact = new CNMutableContact();
// Set standard properties
contact.GivenName = "John";
contact.FamilyName = "Appleseed";
// Save new contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, store.DefaultContainerIdentifier);
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error)) {
Console.WriteLine("New contact saved");
} else {
Console.WriteLine("Save error: {0}", error);
}
Element CNSaveRequest
może również służyć do buforowania wielu zmian kontaktów i grup w jednej operacji i dzielenia tych modyfikacji na .CNContactStore
Aby zaktualizować niemodalny kontakt uzyskany z operacji pobierania, należy najpierw zażądać kopii modyfikowalnej, którą następnie zmodyfikujesz i zapiszesz z powrotem w magazynie kontaktów. Na przykład:
// Get mutable copy of contact
var mutable = contact.MutableCopy() as CNMutableContact;
var newEmail = new CNLabeledValue<NSString>(CNLabelKey.Home, new NSString("john.appleseed@xamarin.com"));
// Append new email
var emails = new NSObject[mutable.EmailAddresses.Length+1];
mutable.EmailAddresses.CopyTo(emails,0);
emails[mutable.EmailAddresses.Length+1] = newEmail;
mutable.EmailAddresses = emails;
// Update contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.UpdateContact(mutable);
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error)) {
Console.WriteLine("Contact updated.");
} else {
Console.WriteLine("Update error: {0}", error);
}
Powiadomienia o zmianie kontaktu
Za każdym razem, gdy kontakt zostanie zmodyfikowany, sklep kontaktowy opublikuje element w CNContactStoreDidChangeNotification
domyślnym Centrum powiadomień. Jeśli masz buforowane lub aktualnie wyświetlasz jakiekolwiek kontakty, musisz odświeżyć te obiekty ze sklepu kontaktowego (CNContactStore
).
Kontenery i grupy
Kontakty użytkownika mogą istnieć lokalnie na urządzeniu użytkownika lub jako kontakty synchronizowane z urządzeniem z co najmniej jednego konta serwera (na przykład Facebook lub Google). Każda pula kontaktów ma własny kontener , a dany kontakt może istnieć tylko w jednym kontenerze.
Niektóre kontenery umożliwiają rozmieszczenie kontaktów w co najmniej jednej grupie lub podgrupach. To zachowanie zależy od magazynu kopii zapasowych dla danego kontenera. Na przykład usługa iCloud ma tylko jeden kontener, ale może mieć wiele grup (ale bez podgrup). Z drugiej strony program Microsoft Exchange nie obsługuje grup, ale może mieć wiele kontenerów (po jednym dla każdego folderu programu Exchange).
Struktura ContactsUI
W sytuacjach, w których aplikacja nie musi prezentować niestandardowego interfejsu użytkownika, możesz użyć struktury ContactsUI do prezentowania elementów interfejsu użytkownika do wyświetlania, edytowania, wybierania i tworzenia kontaktów w aplikacji platformy Xamarin.iOS.
Korzystając z wbudowanych kontrolek firmy Apple, nie tylko zmniejszasz ilość kodu, który musisz utworzyć, aby obsługiwać kontakty w aplikacji platformy Xamarin.iOS, ale prezentujesz spójny interfejs użytkownikom aplikacji.
Kontroler widoku selektora kontaktów
Kontroler widoku selektora kontaktów (CNContactPickerViewController
) zarządza standardowym widokiem selektora kontaktów, który umożliwia użytkownikowi wybranie właściwości Kontakt lub Kontakt z bazy danych kontaktów użytkownika. Użytkownik może wybrać co najmniej jeden kontakt (na podstawie jego użycia), a kontroler widoku selektora kontaktów nie wyświetla monitu o uprawnienie przed wyświetleniem selektora.
Przed wywołaniem CNContactPickerViewController
klasy należy zdefiniować właściwości, które użytkownik może wybrać i zdefiniować predykaty w celu kontrolowania wyświetlania i wybierania właściwości kontaktu.
Użyj wystąpienia klasy dziedziczonej z CNContactPickerDelegate
, aby reagować na interakcję użytkownika z selektorem. Na przykład:
using System;
using System.Linq;
using UIKit;
using Foundation;
using Contacts;
using ContactsUI;
namespace iOS9Contacts
{
public class ContactPickerDelegate: CNContactPickerDelegate
{
#region Constructors
public ContactPickerDelegate ()
{
}
public ContactPickerDelegate (IntPtr handle) : base (handle)
{
}
#endregion
#region Override Methods
public override void ContactPickerDidCancel (CNContactPickerViewController picker)
{
Console.WriteLine ("User canceled picker");
}
public override void DidSelectContact (CNContactPickerViewController picker, CNContact contact)
{
Console.WriteLine ("Selected: {0}", contact);
}
public override void DidSelectContactProperty (CNContactPickerViewController picker, CNContactProperty contactProperty)
{
Console.WriteLine ("Selected Property: {0}", contactProperty);
}
#endregion
}
}
Aby zezwolić użytkownikowi na wybranie adresu e-mail z kontaktów w bazie danych, możesz użyć następującego kodu:
// Create a new picker
var picker = new CNContactPickerViewController();
// Select property to pick
picker.DisplayedPropertyKeys = new NSString[] {CNContactKey.EmailAddresses};
picker.PredicateForEnablingContact = NSPredicate.FromFormat("emailAddresses.@count > 0");
picker.PredicateForSelectionOfContact = NSPredicate.FromFormat("emailAddresses.@count == 1");
// Respond to selection
picker.Delegate = new ContactPickerDelegate();
// Display picker
PresentViewController(picker,true,null);
Kontroler widoku kontaktu
Klasa Kontroler widoku kontaktu (CNContactViewController
) udostępnia kontroler do prezentowania użytkownikowi końcowemu standardowego widoku kontaktu. Widok Kontakt może wyświetlać nowe kontakty Nowe, Nieznane lub Istniejące, a typ musi zostać określony przed wyświetleniem widoku przez wywołanie poprawnego konstruktora statycznego (FromNewContact
, FromUnknownContact
, FromContact
). Na przykład:
// Create a new contact view
var view = CNContactViewController.FromContact(contact);
// Display the view
PresentViewController(view, true, null);
Podsumowanie
W tym artykule szczegółowo przedstawiono pracę ze strukturami interfejsu użytkownika kontaktów i kontaktów w aplikacji platformy Xamarin.iOS. Po pierwsze omówił różne typy obiektów zapewnianych przez platformę Kontakt oraz sposób ich używania do tworzenia nowych lub uzyskiwania dostępu do istniejących kontaktów. Przeanalizowała również strukturę interfejsu użytkownika kontaktów, aby wybrać istniejące kontakty i wyświetlić informacje kontaktowe.