Androidの連絡帳(Address Book)から情報を取り出して表示するアプリケーションを作成する ~Delphiでお手軽プログラミング
1.画面の設計
Delphiを起動して[ファイル]⇒[新規作成]⇒[マルチデバイス アプリケーション - Delphi]をクリックし、[空のアプリケーション]をクリックして、新規FMXプロジェクトを作成します。

ターゲットプラットフォームを[Android64ビット](Android32はGooglePlayに申請できない)に切り替え、スタイルを[Android]に切り替えます。

フォームにTToolbarを配置し、Toolbar1上にTSpeedButtonを配置します。
SpeedButton1の[Align]プロパティを「Left」に設定します。

フォームにTAddressBook、TImageListを配置します。
スタイルを設定したい場合は、TStyleBookを配置し、TForm1の[StyleBook]プロパティを[StyleBook1]に設定します。StyleBook1をダブルクリックして任意のスタイルファイルを開いて設定します。

フォームにTTabControlを配置し、[Align]プロパティを[Client]に設定します。
TabControl1を右クリックして、[TTabItemの追加]をクリックしてタブを追加します。
再度、TabControl1を右クリックして、[TTabItemの追加]をクリックしてタブを追加します。

フォームのTabItem1を選択して、TabItem1にTListViewを配置し、ListView1の[Align]プロパティを[Client]に設定します。

ListView1オブジェクトの[ItemAppearance.ItemAppearance]プロパティを ImageListItemBottomDetail に設定します。
ListView1オブジェクトの[Images]プロパティを ImageList1 に設定します。

TabItem2をクリックしてタブを切り替えます。
TabItem2にTLabelを3つ、TEditを2つ、TButtonを2つ配置します。

2.権限設定
[プロジェクト]⇒[オプション]の、左ペインの[使用する権限]から、
・アカウントの取得
・連絡先の書き込み
・連絡先の読み取り
が必要です。

3.ソースコードの記述
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.AddressBook.Types, FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base, FMX.ListView, System.ImageList, FMX.ImgList, FMX.AddressBook, FMX.TabControl, FMX.StdCtrls, FMX.Controls.Presentation, FMX.Edit; //必要な権限(AndroidManifest.xml) //●アカウントの取得 // <uses-permission android:name="android.permission.GET_ACCOUNTS" /> //●連絡先の読み取り // <uses-permission android:name="android.permission.READ_CONTACTS" /> //以下は連絡先の追加、編集、削除を行う場合に必要 //○連絡先の書き込み // <uses-permission android:name="android.permission.WRITE_CONTACTS" /> type TForm1 = class(TForm) ToolBar1: TToolBar; SpeedButton1: TSpeedButton; TabControl1: TTabControl; TabItem1: TTabItem; TabItem2: TTabItem; AddressBook1: TAddressBook; ImageList1: TImageList; ListView1: TListView; Label1: TLabel; Label2: TLabel; Label3: TLabel; Edit1: TEdit; Edit2: TEdit; StyleBook1: TStyleBook; Button1: TButton; Button2: TButton; procedure FormCreate(Sender: TObject); procedure ListView1Tap(Sender: TObject; const Point: TPointF); procedure ListView1DeletingItem(Sender: TObject; AIndex: Integer; var ACanDelete: Boolean); procedure SpeedButton1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); private { private 宣言 } //連絡先を削除するときの対象インデックスを保持するメンバ変数 DeleteIndex:Integer; //編集中の連絡先IDを入れる 新規の場合は-1 ContactID:Integer; //連絡帳から連絡先リストを取り出して表示するメンバ関数 procedure RefreshAddresBookList(); public { public 宣言 } end; //Deleteボタンが表示されたら非表示にする方法が無いので //Class Helperを使ってHideDeleteButton関数を呼び出すと //非表示にできるようにする TListViewHelper=class helper for TListViewBase public //Deleteボタンを非表示にする procedure HideDeleteButton; end; var Form1: TForm1; implementation {$R *.fmx} uses FMX.DialogService, FMX.MultiResBitmap, System.Threading; procedure TForm1.Button1Click(Sender: TObject); var Contact:TAddressBookContact; begin //OKボタン押下時 if ContactID=-1 then //新規登録 Contact := AddressBook1.CreateContact(AddressBook1.DefaultSource) else //編集完了 Contact:=AddressBook1.ContactByID(ContactID); try Contact.LastName:=Edit1.Text; Contact.FirstName:=Edit2.Text; AddressBook1.SaveContact(Contact); RefreshAddresBookList(); TabControl1.TabIndex:=0; finally Contact.Free; end; end; procedure TForm1.Button2Click(Sender: TObject); begin //Cancelボタン押下時 TabControl1.TabIndex:=0; end; procedure TForm1.FormCreate(Sender: TObject); begin //ListView1を詳細表示に切り替え ListView1.ItemAppearance.ItemAppearance:='ImageListItemBottomDetail'; ListView1.Images:=ImageList1; //TabControl1のタブのインデクスを0(一覧)を切り替える TabControl1.TabIndex:=0; //TabControl1のタブを非表示にする TabControl1.TabPosition:=TTabPosition.None; SpeedButton1.text:='新規登録'; Label1.Text:='姓'; Label2.Text:='名'; Label3.Text:='電話'; Button1.Text:='OK'; Button2.Text:='Cancel'; if AddressBook1.Supported then begin //権限を要求する AddressBook1.RequestPermission; //連絡帳から連絡先リストを取り出して表示する RefreshAddresBookList(); end else TDialogService.ShowMessage('このデバイスは連絡帳サービスが存在しません'); end; procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin if Key = vkHardwareBack then Key := 0; end; procedure TForm1.ListView1DeletingItem(Sender: TObject; AIndex: Integer; var ACanDelete: Boolean); var Contact:TAddressBookContact; begin //ListView1のリストを横にスワイプ後「Delete」ボタンを押した時の処理 //TForm1のメンバ変数DeleteIndexに //LisitView1の削除対象アイテムのインデックスを退避 DeleteIndex:=AIndex; //確認ダイアログの表示 TDialogService.MessageDialog( '削除します。よろしいですか?', TMsgDlgType.mtConfirmation,//表示アイコン設定(Windowsは表示される) mbYesNo, //「はい」「いいえ」のボタンを表示 TMsgDlgBtn.mbNo, //「いいえ」ボタンをデフォルトにする 0, //ヘルプコンテキスト 使わないから「0」 procedure(const AResult:TModalResult)//ボタン押下時実行する無名関数 begin if AResult=mrYes then begin //TForm1のメンバ変数DeleteIndexに削除対象アイテムのインデックスがあり //そのアイテムのTagプロパティには連絡先のIDを入れているので、 //削除対象の連絡先が取得できる Contact:=AddressBook1.ContactByID(ListView1.Items[DeleteIndex].Tag); try //連絡帳から指定の連絡先を削除する AddressBook1.RemoveContact(Contact); //LIstViewから指定のListItemを削除する ListView1.Items.Delete(DeleteIndex); finally Contact.Free; end; end; //Deleteボタンを非表示にする ListView1.HideDeleteButton; end ); //ここではListItemを削除しない ACanDelete:=False; end; procedure TForm1.ListView1Tap(Sender: TObject; const Point: TPointF); var Contact:TAddressBookContact; i,idx:integer; r:TRectF; pt:TPointF; begin //ListView1のアイテムをタップした時の処理 idx:=-1; //タップ座標をListViewでの座標に変換する pt:=ListView1.AbsoluteToLocal(point); //タップされたListView1のアイテムを探す for i := 0 to ListView1.Items.Count-1 do begin r:=Listview1.GetItemRect(i); if r.Contains(pt) then begin idx:=i; break; end; end; //タップされたアイテムがある場合 if idx>=0 then begin //編集する連絡先IDを取得 ContactID:=ListView1.Items[idx].Tag; //連絡先IDから連絡先を取得 Contact:=AddressBook1.ContactByID( ContactID); try //姓 Edit1.Text:=Contact.LastName; //名 Edit2.text:=Contact.FirstName; Label3.Text:='連絡先編集'; finally Contact.Free; end; TabControl1.TabIndex:=1; end; end; procedure TForm1.RefreshAddresBookList; var Contacts: TAddressBookContacts; LVItem:TListViewItem; Phones:string; CSItem:TCustomSourceItem; CDItem:TCustomDestinationItem; Layer:TLayer; begin SpeedButton1.Enabled:=False; ListView1.BeginUpdate(); ListView1.Visible:=False; TThread.CreateAnonymousThread( procedure var i,j: Integer; begin Contacts := TAddressBookContacts.Create; try //全ての連絡帳のリストを取得する AddressBook1.AllContacts(Contacts); //連絡帳のデフォルトの情報源のリストのみ取得する場合は以下 //AddressBook1.AllContacts(AddressBook1.DefaultSource, Contacts); try ListView1.Items.Clear; //TImageListの画像を全削除 ImageList1.Source.Clear; //TImageListの「最終的なアイテム」を全削除 ImageList1.Destination.Clear; for i := 0 to Contacts.Count-1 do begin LVItem:=ListView1.Items.Add(); //連絡帳の連絡先のIDをTagプロパティに保存する LVItem.Tag:=Contacts[i].ID; //連絡帳の連絡先の表示名をリストに表示する //LVItem.Text:=Contacts[i].DisplayName; LVItem.Text:=Contacts[i].LastName+' '+Contacts[i].FirstName; //連絡先に登録されている電話番号(0個や複数の場合がある)を //TListViewのリストの詳細に表示 Phones:=''; for j := 0 to Contacts[i].Phones.Count-1 do begin Phones:=Phones+Contacts[i].Phones[j].Number+' '; end; LVItem.Detail:=Phones; //サムネイルが登録されている場合に表示する if Assigned(Contacts[i].PhotoThumbnail) then begin //ImageList1に画像を追加する CSItem:=ImageList1.Source.Add(); //MultiResBitmapはItemsに複数の[スケールとBitmap]を持ち、 //デバイスの解像度に対応するスケールに近いBitmapを選択してくれる //が、今回はスケール=1の画像(Contacts[i].PhotoThumbnail)を1つ追加する //必要であれば、Contacts[i].Photoも追加してもよい CSItem.MultiResBitmap.TransparentColor:=TColorRec.Fuchsia; CSItem.MultiResBitmap.SizeKind:=TSizeKind.Source; CSItem.MultiResBitmap.Width:=Contacts[i].PhotoThumbnail.Width; CSItem.MultiResBitmap.Height:=Contacts[i].PhotoThumbnail.Height; CSItem.MultiResBitmap.ItemByScale(1,true,true); CSItem.MultiResBitmap.Add; CSItem.MultiResBitmap.Items[CSItem.MultiResBitmap.Count-1].Scale:=1; CSItem.MultiResBitmap.Items[CSItem.MultiResBitmap.Count-1]. Bitmap.Assign(Contacts[i].PhotoThumbnail); //ImageList1に最終的なアイテムを追加 CDItem:=ImageList1.Destination.Add; //ImageList1に追加した最終的なアイテムに、 //ImageList1.Sourceに追加した画像とその範囲を設定 Layer:=CDItem.Layers.Add; Layer.Name:=CSItem.Name;//画像を設定 Layer.SourceRect.Rect:= //画像の出力範囲(左上x,左上y,右下x,右下y)を設定 RectF( 0,0, CSItem.MultiResBitmap.Width,CSItem.MultiResBitmap.Height ); //ImageList1に最終的なアイテムのIndexを割り当てる LVItem.ImageIndex:=CDItem.Index; end; end; finally ListView1.EndUpdate(); ListView1.Visible:=True; end; finally Contacts.Free; SpeedButton1.Enabled:=True; end; end).Start; end; procedure TForm1.SpeedButton1Click(Sender: TObject); begin //新規登録ボタンを押したとき //編集中の連絡先IDを入れるが、新規は-1を入れる ContactID:=-1; Edit1.Text:=''; Edit2.Text:=''; Label3.text:='新規登録'; //タブを切り替える TabControl1.TabIndex:=1; end; { TListViewHelper } procedure TListViewHelper.HideDeleteButton; begin //Deleteボタンを非表示にする with self do SetDeleteButtonIndex(-1); end; end.
4.実行する

実行ボタンを押すと実行できます。

削除したい連絡先をフリック(タップしたまま右又は左に早くスライド)すると、[Delete]ボタンが表示されます。

[Delete]ボタンをタップする確認ウィンドウが表示され、[はい]をタップすると連絡帳から消える。

編集したい連絡先をタップすると編集画面に遷移する。

左上の新規登録ボタンをタップすると新規登録画面に遷移する。