Delphiでお手軽プログラミング

Delphiでお手軽プログラミングメニュー

DelphiでAndroidの連絡帳(Address Book)から情報を取り出して表示するアプリケーションを作成する

DelphiでAndroidの連絡帳(Address Book)から情報を取り出して表示するアプリケーションを作成する。 アドレス帳からサムネイルを取り出してFMXのTImageListに画像登録し、TListViewに表示する。


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]ボタンをタップする確認ウィンドウが表示され、[はい]をタップすると連絡帳から消える。

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

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



Copyright 2021 Mam