EventKit w środowisku Xamarin.iOS
System iOS ma wbudowane dwie aplikacje związane z kalendarzem: aplikację kalendarza i aplikację przypomnień. Wystarczy łatwo zrozumieć, jak aplikacja kalendarza zarządza danymi kalendarza, ale aplikacja przypomnień jest mniej oczywista. Przypomnienia mogą mieć skojarzone z nimi daty w zakresie czasu ich ukończenia, czasu ich ukończenia itp. W związku z tym system iOS przechowuje wszystkie dane kalendarza, niezależnie od tego, czy są to zdarzenia kalendarza, czy przypomnienia, w jednej lokalizacji nazywanej bazą danych kalendarza.
Struktura EventKit umożliwia uzyskiwanie dostępu do danych kalendarzy, zdarzeń kalendarza i przypomnień przechowywanych przez bazę danych kalendarza. Dostęp do kalendarzy i wydarzeń kalendarza jest dostępny od systemu iOS 4, ale dostęp do przypomnień jest nowy w systemie iOS 6.
W tym przewodniku omówimy następujące zagadnienia:
- EventKit Basics — spowoduje to wprowadzenie podstawowych elementów zestawu EventKit za pośrednictwem głównych klas i zrozumienie ich użycia. Ta sekcja jest wymagana przed zajęciem się następną częścią dokumentu.
- Typowe zadania — sekcja typowych zadań jest przeznaczona do szybkiego dokumentacji dotyczącej wykonywania typowych czynności, takich jak: wyliczanie kalendarzy, tworzenie, zapisywanie i pobieranie zdarzeń kalendarza oraz przypomnień, a także używanie wbudowanych kontrolerów do tworzenia i modyfikowania zdarzeń kalendarza. Ta sekcja nie musi być odczytywana z przodu do tyłu, ponieważ ma być odwołaniem do określonych zadań.
Wszystkie zadania w tym przewodniku są dostępne w przykładowej aplikacji towarzyszącej:
Wymagania
Zestaw EventKit został wprowadzony w systemie iOS 4.0, ale dostęp do danych Przypomnienia został wprowadzony w systemie iOS 6.0. W związku z tym w celu ogólnego opracowywania zestawu EventKit należy kierować do przypomnień co najmniej wersję 4.0 i 6.0.
Ponadto aplikacja Przypomnienia nie jest dostępna w symulatorze, co oznacza, że dane przypomnienia również nie będą dostępne, chyba że zostaną one dodane jako pierwsze. Ponadto żądania dostępu są wyświetlane tylko użytkownikowi na rzeczywistym urządzeniu. W związku z tym programowanie zestawu EventKit najlepiej sprawdza się na urządzeniu.
Event Kit Basics
Podczas pracy z zestawem EventKit ważne jest zrozumienie typowych klas i ich użycia. Wszystkie te klasy można znaleźć w polach EventKit
i EventKitUI
(dla elementu EKEventEditController
).
Magazyn zdarzeń
Klasa EventStore jest najważniejszą klasą w zestawie EventKit, ponieważ jest wymagana do wykonywania jakichkolwiek operacji w zestawie EventKit. Można go traktować jako magazyn trwały lub aparat bazy danych dla wszystkich danych zestawu EventKit. Z EventStore
poziomu dostępu do kalendarzy i zdarzeń kalendarza w aplikacji kalendarza oraz przypomnień w aplikacji Przypomnienia.
Ze względu EventStore
na to, że aparat bazy danych powinien być długotrwały, co oznacza, że należy go utworzyć i zniszczyć tak mało, jak to możliwe w okresie istnienia wystąpienia aplikacji. W rzeczywistości zaleca się, aby po utworzeniu jednego wystąpienia EventStore
w aplikacji zachować to odwołanie przez cały okres istnienia aplikacji, chyba że nie będziesz tego potrzebować ponownie. ponadto wszystkie wywołania powinny przejść do pojedynczego EventStore
wystąpienia. Z tego powodu zaleca się zachowanie dostępnego pojedynczego wystąpienia.
Tworzenie magazynu zdarzeń
Poniższy kod ilustruje wydajny sposób tworzenia pojedynczego EventStore
wystąpienia klasy i udostępniania go statycznie z poziomu aplikacji:
public class App
{
public static App Current {
get { return current; }
}
private static App current;
public EKEventStore EventStore {
get { return eventStore; }
}
protected EKEventStore eventStore;
static App ()
{
current = new App();
}
protected App ()
{
eventStore = new EKEventStore ( );
}
}
Powyższy kod używa wzorca Singleton do utworzenia wystąpienia podczas EventStore
ładowania aplikacji. Dostęp EventStore
do obiektu można uzyskać globalnie z poziomu aplikacji w następujący sposób:
App.Current.EventStore;
Zwróć uwagę, że wszystkie przykłady w tym miejscu używają tego wzorca, więc odwołują się do EventStore
elementu za pomocą metody App.Current.EventStore
.
Żądanie dostępu do danych kalendarza i przypomnienia
Przed zezwoleniem na dostęp do jakichkolwiek danych za pośrednictwem magazynu zdarzeń aplikacja musi najpierw zażądać dostępu do danych zdarzeń kalendarza lub danych przypomnień, w zależności od potrzeb. Aby to ułatwić, EventStore
uwidacznia metodę o nazwie RequestAccess
, która — po wywołaniu — wyświetli użytkownikowi widok alertu informujący o tym, że aplikacja żąda dostępu do danych kalendarza lub danych przypomnienia, w zależności od tego, które EKEntityType
dane są przekazywane do niego. Ponieważ zgłasza widok alertu, wywołanie jest asynchroniczne i wywoła procedurę obsługi uzupełniania przekazaną NSAction
jako element (lub lambda), który otrzyma dwa parametry; wartość logiczną określającą, czy udzielono dostępu, oraz NSError
parametr , który, jeśli nie ma wartości null, będzie zawierać jakiekolwiek informacje o błędzie w żądaniu. Na przykład następujące kodowane dane będą żądać dostępu do danych zdarzeń kalendarza i wyświetlać widok alertu, jeśli żądanie nie zostało przyznane.
App.Current.EventStore.RequestAccess (EKEntityType.Event,
(bool granted, NSError e) => {
if (granted)
//do something here
else
new UIAlertView ( "Access Denied",
"User Denied Access to Calendar Data", null,
"ok", null).Show ();
} );
Po udzieleniu żądania zostanie zapamiętany tak długo, jak aplikacja jest zainstalowana na urządzeniu i nie wyświetli alertu dla użytkownika. Jednak dostęp jest udzielany tylko dla typu zasobu, wydarzeń kalendarza lub przypomnień udzielonych. Jeśli aplikacja potrzebuje dostępu do obu tych elementów, powinna zażądać obu tych elementów.
Ponieważ uprawnienia są zapamiętywane, stosunkowo tanie jest wykonywanie żądania za każdym razem, dlatego warto zawsze żądać dostępu przed wykonaniem operacji.
Ponadto, ponieważ procedura obsługi uzupełniania jest wywoływana w osobnym wątku (innym niż interfejs użytkownika), wszystkie aktualizacje interfejsu użytkownika w procedurze obsługi uzupełniania powinny być wywoływane za pośrednictwem metody InvokeOnMainThread
, w przeciwnym razie zostanie zgłoszony wyjątek, a jeśli nie zostanie przechwycony, aplikacja ulegnie awarii.
Typ EKEntityType
EKEntityType
to wyliczenie opisujące typ EventKit
elementu lub danych. Ma dwie wartości: Event
i Reminder. Jest on używany w wielu metodach, w tym EventStore.RequestAccess
do określenia EventKit
, jakiego rodzaju dane mają uzyskać dostęp do lub pobrać.
EKCalendar
EKCalendar reprezentuje kalendarz, który zawiera grupę zdarzeń kalendarza. Kalendarze mogą być przechowywane w wielu różnych miejscach, takich jak lokalnie, w usłudze iCloud, w lokalizacji dostawcy innej firmy, takiej jak Exchange Server lub Google itp. Wiele razy EKCalendar
służy do określania EventKit
miejsca wyszukiwania zdarzeń lub miejsca ich zapisywania.
EKEventEditController
EKEventEditController można znaleźć w EventKitUI
przestrzeni nazw i jest wbudowanym kontrolerem, który może służyć do edytowania lub tworzenia zdarzeń kalendarza. Podobnie jak w przypadku wbudowanych kontrolerów kamer, EKEventEditController
bardzo duże obciążenie podczas wyświetlania interfejsu użytkownika i obsługi zapisywania.
EKEvent
EKEvent reprezentuje zdarzenie kalendarza. Zarówno EKEvent
, jak i EKReminder
dziedziczą z EKCalendarItem
pól, takich jak Title
, Notes
i tak dalej.
EKReminder
EKReminder reprezentuje element przypomnienia.
EKSpan
EKSpan to wyliczenie opisujące zakres zdarzeń podczas modyfikowania zdarzeń, które mogą się powtarzać, i ma dwie wartości: ThisEvent i FutureEvents. ThisEvent
oznacza, że wszelkie zmiany zostaną wprowadzone tylko do określonego zdarzenia w serii, do którego się odwołujesz, natomiast FutureEvents
wpłynie to na to zdarzenie i wszystkie przyszłe cykle.
Zadania
W celu ułatwienia użycia użycie zestawu EventKit zostało podzielone na typowe zadania opisane w poniższych sekcjach.
Wyliczanie kalendarzy
Aby wyliczyć kalendarze skonfigurowane przez użytkownika na urządzeniu, wywołaj metodę GetCalendars
EventStore
i przekaż typ kalendarzy (przypomnienia lub zdarzenia), które chcesz otrzymać:
EKCalendar[] calendars =
App.Current.EventStore.GetCalendars ( EKEntityType.Event );
Dodawanie lub modyfikowanie zdarzenia przy użyciu wbudowanego kontrolera
Kontroler EKEventEditViewController wykonuje wiele operacji podnoszenia, jeśli chcesz utworzyć lub edytować zdarzenie za pomocą tego samego interfejsu użytkownika, który jest prezentowany użytkownikowi podczas korzystania z aplikacji kalendarza:
Aby go użyć, należy zadeklarować ją jako zmienną na poziomie klasy, aby nie pobierała pamięci, jeśli jest zadeklarowana w metodzie:
public class HomeController : DialogViewController
{
protected CreateEventEditViewDelegate eventControllerDelegate;
...
}
Następnie, aby go uruchomić: utwórz wystąpienie, nadaj mu odwołanie do EventStore
, podłącz do niego delegata EKEventEditViewDelegate , a następnie wyświetl go przy użyciu polecenia PresentViewController
:
EventKitUI.EKEventEditViewController eventController =
new EventKitUI.EKEventEditViewController ();
// set the controller's event store - it needs to know where/how to save the event
eventController.EventStore = App.Current.EventStore;
// wire up a delegate to handle events from the controller
eventControllerDelegate = new CreateEventEditViewDelegate ( eventController );
eventController.EditViewDelegate = eventControllerDelegate;
// show the event controller
PresentViewController ( eventController, true, null );
Opcjonalnie, jeśli chcesz wstępnie wypełnić zdarzenie, możesz utworzyć nowe zdarzenie (jak pokazano poniżej) lub pobrać zapisane zdarzenie:
EKEvent newEvent = EKEvent.FromStore ( App.Current.EventStore );
// set the alarm for 10 minutes from now
newEvent.AddAlarm ( EKAlarm.FromDate ( DateTime.Now.AddMinutes ( 10 ) ) );
// make the event start 20 minutes from now and last 30 minutes
newEvent.StartDate = DateTime.Now.AddMinutes ( 20 );
newEvent.EndDate = DateTime.Now.AddMinutes ( 50 );
newEvent.Title = "Get outside and exercise!";
newEvent.Notes = "This is your reminder to go and exercise for 30 minutes.”;
Jeśli chcesz wstępnie wypełnić interfejs użytkownika, upewnij się, że właściwość Event na kontrolerze:
eventController.Event = newEvent;
Aby użyć istniejącego zdarzenia, zobacz sekcję Pobieranie zdarzenia według identyfikatora w dalszej części.
Delegat powinien zastąpić metodę Completed
, która jest wywoływana przez kontroler po zakończeniu pracy użytkownika z okna dialogowego:
protected class CreateEventEditViewDelegate : EventKitUI.EKEventEditViewDelegate
{
// we need to keep a reference to the controller so we can dismiss it
protected EventKitUI.EKEventEditViewController eventController;
public CreateEventEditViewDelegate (EventKitUI.EKEventEditViewController eventController)
{
// save our controller reference
this.eventController = eventController;
}
// completed is called when a user eith
public override void Completed (EventKitUI.EKEventEditViewController controller, EKEventEditViewAction action)
{
eventController.DismissViewController (true, null);
}
}
}
Opcjonalnie w delegu możesz sprawdzić akcję w metodzie Completed
, aby zmodyfikować zdarzenie i ponownie zapisać lub wykonać inne czynności, jeśli została anulowana, itpetera:
public override void Completed (EventKitUI.EKEventEditViewController controller, EKEventEditViewAction action)
{
eventController.DismissViewController (true, null);
switch ( action ) {
case EKEventEditViewAction.Canceled:
break;
case EKEventEditViewAction.Deleted:
break;
case EKEventEditViewAction.Saved:
// if you wanted to modify the event you could do so here,
// and then save:
//App.Current.EventStore.SaveEvent ( controller.Event, )
break;
}
}
Programowe tworzenie zdarzenia
Aby utworzyć zdarzenie w kodzie, użyj metody Fabryki FromStore w EKEvent
klasie i ustaw na nim dowolne dane:
EKEvent newEvent = EKEvent.FromStore ( App.Current.EventStore );
// set the alarm for 10 minutes from now
newEvent.AddAlarm ( EKAlarm.FromDate ( DateTime.Now.AddMinutes ( 10 ) ) );
// make the event start 20 minutes from now and last 30 minutes
newEvent.StartDate = DateTime.Now.AddMinutes ( 20 );
newEvent.EndDate = DateTime.Now.AddMinutes ( 50 );
newEvent.Title = "Get outside and do some exercise!";
newEvent.Notes = "This is your motivational event to go and do 30 minutes of exercise. Super important. Do this.";
Musisz ustawić kalendarz, w którym ma być zapisane zdarzenie, ale jeśli nie masz preferencji, możesz użyć wartości domyślnej:
newEvent.Calendar = App.Current.EventStore.DefaultCalendarForNewEvents;
Aby zapisać zdarzenie, wywołaj metodę SaveEvent w pliku EventStore
:
NSError e;
App.Current.EventStore.SaveEvent ( newEvent, EKSpan.ThisEvent, out e );
Po zapisaniu właściwość EventIdentifier zostanie zaktualizowana o unikatowy identyfikator, którego można użyć później do pobrania zdarzenia:
Console.WriteLine ("Event Saved, ID: " + newEvent.CalendarItemIdentifier);
EventIdentifier
jest ciągiem sformatowanym identyfikatorem GUID.
Programowe tworzenie przypomnienia
Tworzenie przypomnienia w kodzie jest takie samo jak tworzenie zdarzenia kalendarza:
EKReminder reminder = EKReminder.Create ( App.Current.EventStore );
reminder.Title = "Do something awesome!";
reminder.Calendar = App.Current.EventStore.DefaultCalendarForNewReminders;
Aby zapisać, wywołaj metodę SaveReminder w pliku EventStore
:
NSError e;
App.Current.EventStore.SaveReminder ( reminder, true, out e );
Pobieranie zdarzenia według identyfikatora
Aby pobrać zdarzenie według jego identyfikatora, użyj metody EventFromIdentifier w obiekcie EventStore
i przekaż zdarzenie EventIdentifier
, które zostało pobrane ze zdarzenia:
EKEvent mySavedEvent = App.Current.EventStore.EventFromIdentifier ( newEvent.EventIdentifier );
W przypadku zdarzeń istnieją dwie inne właściwości identyfikatora, ale EventIdentifier
jest jedyną, która działa w tym celu.
Pobieranie przypomnienia według identyfikatora
Aby pobrać przypomnienie, użyj metody GetCalendarItem w obiekcie EventStore
i przekaż ją do elementu CalendarItemIdentifier:
EKCalendarItem myReminder = App.Current.EventStore.GetCalendarItem ( reminder.CalendarItemIdentifier );
Ponieważ GetCalendarItem
zwraca element EKCalendarItem
, należy go rzutować, aby EKReminder
uzyskać dostęp do danych przypomnienia lub użyć wystąpienia jako późniejszego EKReminder
.
Nie używaj GetCalendarItem
w przypadku zdarzeń kalendarza, jak w momencie pisania, nie działa.
Usuwanie zdarzenia
Aby usunąć zdarzenie kalendarza, wywołaj metodę RemoveEvent na urządzeniu EventStore
i przekaż odwołanie do zdarzenia oraz odpowiednie polecenie EKSpan
:
NSError e;
App.Current.EventStore.RemoveEvent ( mySavedEvent, EKSpan.ThisEvent, true, out e);
Pamiętaj jednak, że po usunięciu zdarzenia odwołanie do zdarzenia będzie miało wartość null
.
Usuwanie przypomnienia
Aby usunąć przypomnienie, wywołaj metodę RemoveReminder na obiekcie EventStore
i przekaż odwołanie do przypomnienia:
NSError e;
App.Current.EventStore.RemoveReminder ( myReminder as EKReminder, true, out e);
Zwróć uwagę, że w powyższym kodzie istnieje rzutowanie do EKReminder
elementu , ponieważ GetCalendarItem
użyto go do pobrania
Wyszukiwanie zdarzeń
Aby wyszukać zdarzenia kalendarza, należy utworzyć obiekt NSPredicate za pomocą metody PredicateForEvents w pliku EventStore
. Obiekt NSPredicate
jest obiektem danych zapytania używanym przez system iOS do lokalizowania dopasowań:
DateTime startDate = DateTime.Now.AddDays ( -7 );
DateTime endDate = DateTime.Now;
// the third parameter is calendars we want to look in, to use all calendars, we pass null
NSPredicate query = App.Current.EventStore.PredicateForEvents ( startDate, endDate, null );
Po utworzeniu NSPredicate
metody użyj metody EventsMatching w pliku EventStore
:
// execute the query
EKCalendarItem[] events = App.Current.EventStore.EventsMatching ( query );
Należy pamiętać, że zapytania są synchroniczne (blokowanie) i mogą zająć dużo czasu, w zależności od zapytania, więc możesz chcieć uruchomić nowy wątek lub zadanie, aby to zrobić.
Wyszukiwanie przypomnień
Wyszukiwanie przypomnień jest podobne do zdarzeń; wymaga predykatu, ale wywołanie jest już asynchroniczne, więc nie musisz martwić się o blokowanie wątku:
// create our NSPredicate which we'll use for the query
NSPredicate query = App.Current.EventStore.PredicateForReminders ( null );
// execute the query
App.Current.EventStore.FetchReminders (
query, ( EKReminder[] items ) => {
// do someting with the items
} );
Podsumowanie
W tym dokumencie omówiono zarówno ważne elementy struktury EventKit, jak i szereg najbardziej typowych zadań. Jednak struktura EventKit jest bardzo duża i zaawansowana i zawiera funkcje, które nie zostały tu wprowadzone, takie jak: aktualizacje wsadowe, konfigurowanie alarmów, konfigurowanie cyklu zdarzeń, rejestrowanie i nasłuchiwanie zmian w bazie danych kalendarza, ustawianie geofencingów i nie tylko. Aby uzyskać więcej informacji, zobacz Kalendarz i przypomnienia firmy Apple — przewodnik programowania.