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 CursorLoader
arquivo . Introduzido no Android 3.0 (API 11), CursorLoader
é a maneira preferida de consumir um ContentProvider
arquivo . 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
:
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. EventListActivity
No 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:
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:
- Crie uma instância de
ContentValues
. - Use chaves da
CalendarContract.Events.InterfaceConsts
classe para preencher aContentValues
instância. - Defina os fusos horários para as horas de início e término do evento.
- 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:
Se abrirmos o aplicativo de calendário, veremos que o evento está escrito lá também:
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.