Partilhar via


Xamarin.Android Calendário

API de calendário

Um novo conjunto de APIs de calendário introduzido no Android 4 oferece suporte a aplicativos projetados para ler ou gravar dados no provedor de calendário. Essas APIs oferecem suporte a uma variedade de opções de interação com dados de calendário, incluindo a capacidade de ler e gravar eventos, participantes e lembretes. Usando o provedor de calendário em seu aplicativo, os dados adicionados por meio da API aparecerão no aplicativo de calendário interno que vem com o Android 4.

Adicionando permissões

Ao trabalhar com as novas APIs de calendário em seu aplicativo, a primeira coisa que você precisa fazer é adicionar as permissões apropriadas ao manifesto do Android. As permissões que você precisa adicionar são android.permisson.READ_CALENDAR e android.permission.WRITE_CALENDAR, dependendo se você estiver lendo e/ou gravando dados de calendário.

Usando o contrato de calendário

Depois de definir as permissões, você pode interagir com os dados do calendário usando a CalendarContract classe. Essa classe fornece um modelo de dados que os aplicativos podem usar quando interagem com o provedor de calendário. O CalendarContract permite que os aplicativos resolvam o Uris para entidades de calendário, como calendários e eventos. Ele também fornece uma maneira de interagir com vários campos em cada entidade, como o nome e a ID de um calendário ou a data de início e término de um evento.

Vejamos um exemplo que usa a API do Calendário. Neste exemplo, examinaremos como enumerar calendários e seus eventos, bem como adicionar um novo evento a um calendário.

Listando calendários

Primeiro, vamos examinar como enumerar os calendários que foram registrados no aplicativo de calendário. Para fazer isso, podemos instanciar um CursorLoaderarquivo . Introduzido no Android 3.0 (API 11), CursorLoader é a maneira preferida de consumir um ContentProviderarquivo . No mínimo, precisaremos especificar o Uri de conteúdo para calendários e as colunas que queremos retornar; Essa especificação de coluna é conhecida como projeção.

Chamar o CursorLoader.LoadInBackground método nos permite consultar um provedor de conteúdo para obter dados, como o provedor de calendário. LoadInBackground Executa a operação de carregamento real e retorna um Cursor com os resultados da consulta.

O CalendarContract nos auxilia na especificação tanto do conteúdo Uri quanto da projeção. Para obter o conteúdo Uri para consultar calendários, podemos simplesmente usar a CalendarContract.Calendars.ContentUri propriedade assim:

var calendarsUri = CalendarContract.Calendars.ContentUri;

Usar o para especificar quais colunas de CalendarContract calendário queremos é igualmente simples. Apenas adicionamos campos na CalendarContract.Calendars.InterfaceConsts classe a uma matriz. Por exemplo, o código a seguir inclui a ID do calendário, o nome para exibição e o nome da conta:

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

O Id é importante incluir se você estiver usando um SimpleCursorAdapter para vincular os dados à interface do usuário, como veremos em breve. Com o Uri de conteúdo e a projeção no lugar, instanciamos o CursorLoader método e chamamos para CursorLoader.LoadInBackground retornar um cursor com os dados do calendário, conforme mostrado abaixo:

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

A interface do usuário deste exemplo contém um ListView, com cada item na lista representando um único calendário. O XML a seguir mostra a marcação que inclui o 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>

Além disso, precisamos especificar a interface do usuário para cada item de lista, que colocamos em um arquivo XML separado da seguinte maneira:

<?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>

A partir deste ponto, é apenas código normal do Android vincular os dados do cursor à interface do usuário. Usaremos um SimpleCursorAdapter da seguinte maneira:

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;

No código acima, o adaptador pega sourceColumns as colunas especificadas na matriz e as grava nos elementos da interface do usuário na targetResources matriz para cada entrada de calendário no cursor. A Atividade usada aqui é uma subclasse de ListActivity, ela inclui a propriedade para a ListAdapter qual definimos o adaptador.

Aqui está uma captura de tela mostrando o resultado final, com as informações do calendário exibidas no ListView:

CalendarDemo em execução no emulador, exibindo duas entradas de calendário

Listando eventos do calendário

Em seguida, veremos como enumerar os eventos de um determinado calendário. Com base no exemplo acima, apresentaremos uma lista de eventos quando o usuário selecionar um dos calendários. Portanto, precisaremos manipular a seleção de itens no código anterior:

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);
};

Neste código, estamos criando uma Intenção para abrir uma Atividade do tipo EventListActivity, passando a ID do calendário na Intenção. Precisaremos do ID para saber qual calendário consultar para eventos. EventListActivityNo método 'sOnCreate, podemos recuperar o Intent ID do como mostrado abaixo:

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

Agora vamos consultar eventos para essa ID de calendário. O processo para consultar eventos é semelhante à maneira como consultamos uma lista de calendários anteriormente, só que desta vez trabalharemos com a CalendarContract.Events classe. O código a seguir cria uma consulta para recuperar eventos:

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();

Neste código, primeiro obtemos o conteúdo Uri para eventos da CalendarContract.Events.ContentUri propriedade. Em seguida, especificamos as colunas de eventos que queremos recuperar na matriz eventsProjection. Finalmente, instanciamos um CursorLoader com essas informações e chamamos o método do carregador LoadInBackground para retornar um Cursor com os dados do evento.

Para exibir os dados do evento na interface do usuário, podemos usar marcação e código como fizemos antes para exibir a lista de calendários. Novamente, usamos SimpleCursorAdapter para vincular os dados a um ListView conforme mostrado no código a seguir:

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;

A principal diferença entre esse código e o código que usamos anteriormente para mostrar a lista de calendário é o uso de um ViewBinder, que é definido na linha:

adapter.ViewBinder = new ViewBinder ();

A ViewBinder classe nos permite controlar ainda mais como vinculamos valores a modos de exibição. Nesse caso, nós o usamos para converter a hora de início do evento de milissegundos em uma cadeia de caracteres de data, conforme mostrado na implementação a seguir:

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;
    }    
}

Isso exibe uma lista de eventos, conforme mostrado abaixo:

Captura de tela do aplicativo de exemplo exibindo três eventos de calendário

Adicionando um evento do calendário

Vimos como ler dados de calendário. Agora vamos ver como adicionar um evento a um calendário. Para que isso funcione, certifique-se de incluir a android.permission.WRITE_CALENDAR permissão que mencionamos anteriormente. Para adicionar um evento a um calendário, iremos:

  1. Crie uma instância de ContentValues.
  2. Use chaves da CalendarContract.Events.InterfaceConsts classe para preencher a ContentValues instância.
  3. Defina os fusos horários para as horas de início e término do evento.
  4. Use um ContentResolver para inserir os dados do evento no calendário.

O código abaixo ilustra essas etapas:

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);

Observe que, se não definirmos o fuso horário, uma exceção do tipo Java.Lang.IllegalArgumentException será lançada. Como os valores de tempo de evento devem ser expressos em milissegundos desde a época, criamos um método (em EventListActivity) para converter nossas especificações de GetDateTimeMS data em formato de milissegundos:

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 adicionarmos um botão à interface do usuário da lista de eventos e executarmos o código acima no manipulador de eventos click do botão, o evento será adicionado ao calendário e atualizado em nossa lista conforme mostrado abaixo:

Captura de tela do aplicativo de exemplo com eventos de calendário seguidos pelo botão Adicionar Evento de Amostra

Se abrirmos o aplicativo de calendário, veremos que o evento está escrito lá também:

Captura de tela do aplicativo de calendário exibindo o evento de calendário selecionado

Como você pode ver, o Android permite acesso poderoso e fácil para recuperar e persistir dados de calendário, permitindo que os aplicativos integrem perfeitamente os recursos de calendário.