Condividi tramite


Calendario Xamarin.Android

API Calendario

Un nuovo set di API di calendario introdotte in Android 4 supporta applicazioni progettate per leggere o scrivere dati nel provider di calendario. Queste API supportano un'ampia gamma di opzioni di interazione con i dati del calendario, tra cui la possibilità di leggere e scrivere eventi, partecipanti e promemoria. Usando il provider di calendario nell'applicazione, i dati aggiunti tramite l'API verranno visualizzati nell'app calendario predefinita fornita con Android 4.

Aggiunta di autorizzazioni

Quando si lavora con le nuove API del calendario nell'applicazione, la prima cosa da fare è aggiungere le autorizzazioni appropriate al manifesto Android. Le autorizzazioni da aggiungere sono android.permisson.READ_CALENDAR e android.permission.WRITE_CALENDAR, a seconda che si stia leggendo e/o scrivendo dati del calendario.

Utilizzo del contratto di calendario

Dopo aver impostato le autorizzazioni, è possibile interagire con i dati del calendario usando la CalendarContract classe . Questa classe fornisce un modello di dati che le applicazioni possono usare quando interagiscono con il provider di calendario. CalendarContract consente alle applicazioni di risolvere gli URI in entità di calendario, ad esempio calendari ed eventi. Offre anche un modo per interagire con vari campi in ogni entità, ad esempio il nome e l'ID di un calendario o la data di inizio e di fine di un evento.

Di seguito è riportato un esempio che usa l'API Calendario. In questo esempio si esaminerà come enumerare i calendari e i relativi eventi, nonché come aggiungere un nuovo evento a un calendario.

Elenco calendari

Prima di tutto, esaminiamo come enumerare i calendari registrati nell'app calendario. A tale scopo, è possibile creare un'istanza di .CursorLoader Introdotto in Android 3.0 (API 11), CursorLoader è il modo preferito per usare un oggetto ContentProvider. Come minimo, è necessario specificare l'URI del contenuto per i calendari e le colonne da restituire; questa specifica di colonna è nota come proiezione.

La chiamata al CursorLoader.LoadInBackground metodo consente di eseguire una query su un provider di contenuti per i dati, ad esempio il provider di calendario. LoadInBackground esegue l'operazione di caricamento effettiva e restituisce un oggetto Cursor con i risultati della query.

Ci CalendarContract aiuta a specificare sia il contenuto Uri che la proiezione. Per ottenere il contenuto Uri per l'esecuzione di query sui calendari, è sufficiente usare la CalendarContract.Calendars.ContentUri proprietà come segue:

var calendarsUri = CalendarContract.Calendars.ContentUri;

L'uso di CalendarContract per specificare le colonne del calendario desiderate è altrettanto semplice. È sufficiente aggiungere campi nella CalendarContract.Calendars.InterfaceConsts classe a una matrice. Ad esempio, il codice seguente include l'ID del calendario, il nome visualizzato e il nome dell'account:

string[] calendarsProjection = {
    CalendarContract.Calendars.InterfaceConsts.Id,
    CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
    CalendarContract.Calendars.InterfaceConsts.AccountName
};

È Id importante includere se si usa un SimpleCursorAdapter oggetto per associare i dati all'interfaccia utente, come si vedrà a breve. Con l'URI del contenuto e la proiezione sul posto, viene creata un'istanza del CursorLoader metodo e viene chiamato il CursorLoader.LoadInBackground metodo per restituire un cursore con i dati del calendario, come illustrato di seguito:

var loader = new CursorLoader(this, calendarsUri, calendarsProjection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();

L'interfaccia utente di questo esempio contiene un oggetto ListView, con ogni elemento nell'elenco che rappresenta un singolo calendario. Il codice XML seguente illustra il markup che include :ListView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
  <ListView
    android:id="@android:id/android:list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Inoltre, è necessario specificare l'interfaccia utente per ogni elemento di elenco, che viene inserito in un file XML separato come indicato di seguito:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
  <TextView android:id="@+id/calDisplayName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="16dip" />
  <TextView android:id="@+id/calAccountName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="12dip" />
</LinearLayout>

Da questo punto in poi, è solo normale codice Android per associare i dati dal cursore all'interfaccia utente. Verrà usato come SimpleCursorAdapter segue:

string[] sourceColumns = {
    CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
    CalendarContract.Calendars.InterfaceConsts.AccountName };

int[] targetResources = {
    Resource.Id.calDisplayName, Resource.Id.calAccountName };      

SimpleCursorAdapter adapter = new SimpleCursorAdapter (this,
    Resource.Layout.CalListItem, cursor, sourceColumns, targetResources);

ListAdapter = adapter;

Nel codice precedente, l'adattatore accetta le colonne specificate nella sourceColumns matrice e le scrive negli elementi dell'interfaccia utente nella matrice per ogni voce del targetResources calendario nel cursore. L'attività usata qui è una sottoclasse di ListActivity, che include la ListAdapter proprietà a cui è stato impostato l'adapter.

Ecco uno screenshot che mostra il risultato finale, con le informazioni sul calendario visualizzate in ListView:

CalendarDemo in esecuzione nell'emulatore, visualizzando due voci del calendario

Elenco di eventi del calendario

Verrà ora illustrato come enumerare gli eventi per un determinato calendario. Basandosi sull'esempio precedente, verrà presentato un elenco di eventi quando l'utente seleziona uno dei calendari. Sarà quindi necessario gestire la selezione dell'elemento nel codice precedente:

ListView.ItemClick += (sender, e) => {
    int i = (e as ItemEventArgs).Position;

    cursor.MoveToPosition(i);
    int calId =
        cursor.GetInt (cursor.GetColumnIndex (calendarsProjection [0]));

    var showEvents = new Intent(this, typeof(EventListActivity));
    showEvents.PutExtra("calId", calId);
    StartActivity(showEvents);
};

In questo codice viene creata una finalità per aprire un'attività di tipo EventListActivity, passando l'ID del calendario nella finalità. Sarà necessario l'ID per sapere quale calendario eseguire una query per gli eventi. EventListActivityNel metodo di OnCreate è possibile recuperare l'ID da Intent come illustrato di seguito:

_calId = Intent.GetIntExtra ("calId", -1);

Eseguire ora una query sugli eventi per questo ID calendario. Il processo di query per gli eventi è simile al modo in cui è stata eseguita una query per un elenco di calendari in precedenza, solo questa volta si userà la CalendarContract.Events classe . Il codice seguente crea una query per recuperare gli eventi:

var eventsUri = CalendarContract.Events.ContentUri;

string[] eventsProjection = {
    CalendarContract.Events.InterfaceConsts.Id,
    CalendarContract.Events.InterfaceConsts.Title,
    CalendarContract.Events.InterfaceConsts.Dtstart
};

var loader = new CursorLoader(this, eventsUri, eventsProjection,
                   String.Format ("calendar_id={0}", _calId), null, "dtstart ASC");
var cursor = (ICursor)loader.LoadInBackground();

In questo codice si ottiene prima di tutto il contenuto Uri per gli eventi dalla CalendarContract.Events.ContentUri proprietà . Specificare quindi le colonne evento da recuperare nella matrice eventsProjection. Infine, viene creata un'istanza di con CursorLoader queste informazioni e viene chiamato il metodo del LoadInBackground caricatore per restituire un Cursor oggetto con i dati dell'evento.

Per visualizzare i dati dell'evento nell'interfaccia utente, è possibile usare markup e codice come in precedenza per visualizzare l'elenco dei calendari. Anche in questo caso, viene usato SimpleCursorAdapter per associare i dati a un oggetto ListView come illustrato nel codice seguente:

string[] sourceColumns = {
    CalendarContract.Events.InterfaceConsts.Title,
    CalendarContract.Events.InterfaceConsts.Dtstart };

int[] targetResources = {
    Resource.Id.eventTitle,
    Resource.Id.eventStartDate };

var adapter = new SimpleCursorAdapter (this, Resource.Layout.EventListItem,
    cursor, sourceColumns, targetResources);

adapter.ViewBinder = new ViewBinder ();       
ListAdapter = adapter;

La differenza principale tra questo codice e il codice usato in precedenza per mostrare l'elenco di calendari è l'uso di un ViewBinderoggetto , impostato sulla riga:

adapter.ViewBinder = new ViewBinder ();

La ViewBinder classe consente di controllare ulteriormente il modo in cui si associano valori alle visualizzazioni. In questo caso, viene usato per convertire l'ora di inizio dell'evento da millisecondi a una stringa di data, come illustrato nell'implementazione seguente:

class ViewBinder : Java.Lang.Object, SimpleCursorAdapter.IViewBinder
{    
    public bool SetViewValue (View view, Android.Database.ICursor cursor,
        int columnIndex)
    {
        if (columnIndex == 2) {
            long ms = cursor.GetLong (columnIndex);

            DateTime date = new DateTime (1970, 1, 1, 0, 0, 0,
                DateTimeKind.Utc).AddMilliseconds (ms).ToLocalTime ();

            TextView textView = (TextView)view;
            textView.Text = date.ToLongDateString ();

            return true;
        }
        return false;
    }    
}

Viene visualizzato un elenco di eventi, come illustrato di seguito:

Screenshot dell'app di esempio che mostra tre eventi del calendario

Aggiunta di un evento di calendario

Si è visto come leggere i dati del calendario. Vediamo ora come aggiungere un evento a un calendario. Per il funzionamento, assicurarsi di includere l'autorizzazione android.permission.WRITE_CALENDAR menzionata in precedenza. Per aggiungere un evento a un calendario, si eseguirà quanto riportato di seguito:

  1. Creare un'istanza di ContentValues.
  2. Usare le chiavi della CalendarContract.Events.InterfaceConsts classe per popolare l'istanza ContentValues .
  3. Impostare i fusi orari per l'ora di inizio e di fine dell'evento.
  4. Utilizzare un ContentResolver oggetto per inserire i dati dell'evento nel calendario.

Il codice seguente illustra questi passaggi:

ContentValues eventValues = new ContentValues ();

eventValues.Put (CalendarContract.Events.InterfaceConsts.CalendarId,
    _calId);
eventValues.Put (CalendarContract.Events.InterfaceConsts.Title,
    "Test Event from M4A");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Description,
    "This is an event created from Xamarin.Android");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtstart,
    GetDateTimeMS (2011, 12, 15, 10, 0));
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtend,
    GetDateTimeMS (2011, 12, 15, 11, 0));

eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
    "UTC");
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone,
    "UTC");

var uri = ContentResolver.Insert (CalendarContract.Events.ContentUri,
    eventValues);

Si noti che se non si imposta il fuso orario, verrà generata un'eccezione di tipo Java.Lang.IllegalArgumentException . Poiché i valori dell'ora dell'evento devono essere espressi in millisecondi dall'epoca, viene creato un GetDateTimeMS metodo (in ) per convertire le specifiche di data in EventListActivityformato millisecondo:

long GetDateTimeMS (int yr, int month, int day, int hr, int min)
{
    Calendar c = Calendar.GetInstance (Java.Util.TimeZone.Default);

    c.Set (Java.Util.CalendarField.DayOfMonth, 15);
    c.Set (Java.Util.CalendarField.HourOfDay, hr);
    c.Set (Java.Util.CalendarField.Minute, min);
    c.Set (Java.Util.CalendarField.Month, Calendar.December);
    c.Set (Java.Util.CalendarField.Year, 2011);

    return c.TimeInMillis;
}

Se aggiungiamo un pulsante all'interfaccia utente dell'elenco eventi ed eseguiamo il codice precedente nel gestore eventi click del pulsante, l'evento viene aggiunto al calendario e aggiornato nell'elenco, come illustrato di seguito:

Screenshot dell'app di esempio con eventi del calendario seguiti dal pulsante Aggiungi evento di esempio

Se si apre l'app calendario, si noterà che l'evento viene scritto anche in questa posizione:

Screenshot dell'app calendario che mostra l'evento del calendario selezionato

Come si può notare, Android consente un accesso potente e semplice per recuperare e rendere persistenti i dati del calendario, consentendo alle applicazioni di integrare facilmente le funzionalità del calendario.