FC2ブログ

記事一覧

AlertDialogでテキストボックスやチェックボックスを表示して入力結果を取得する方法 | Xamarin.Forms

 
今回はXamarin.Formsでアラートダイアログを表示するには標準でDisplayAlertというメッセージ関数が用意されていますが、文字を入力する為のテキストボックスやチェックボックスなどは表示できません。そこでiOSとAndroidの双方でネイティブコードを記述することにより表示することができました。


iOS10
xamarin_entry_alert_03.png
Android7.0
xamarin_entry_alert_01.png



前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.795 (NuGet Xamarin.Forms 2.3.4.270)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.6.0.10



1.PCLの記述方法

PCLプロジェクトにDependencySerivceから呼び出せるようにインターフェースを実装します。

IEntryAlertService.cs
using System.Threading.Tasks;
namespace AppName.Services
{
//DependencyServiceから利用する
public interface IEntryAlertService
{
Task<EntryAlertResult> Show(string title, string message, string defaultInputText,
string accepte, string cancel,
bool isPassword = false,
string checkboxMessage = "");
}
//戻り値取得用
public class EntryAlertResult
{
public string PressedButtonTitle { get; set; }
public string InputText { get; set; }
public bool IsChecked { get; set; }
}
}



2.Androidの実装方法

Androidプロジェクト内に以下のファイルを記述します。
Android標準でチェックボックスもありますので、簡単に実装が可能です。

EntryAlertService.cs
using System;
using System.Threading.Tasks;
using Android.App;
using Android.Widget;
using Xamarin.Forms;
[assembly: Dependency(typeof(EntryAlertService))]
namespace AppName.Droid.Model.Services
{
public class EntryAlertService : IEntryAlertService
{
public Task<EntryAlertResult> Show(string title,
string message,
string defaultInputText,
string accept,
string cancel,
bool isPassword = false,
string checkboxMessage = "")
{
var tcs = new TaskCompletionSource<EntryAlertResult>();

//テキストボックス
var editText = new EditText(Forms.Context);
if (isPassword)
{
editText.InputType = global::Android.Text.InputTypes.TextVariationPassword
| global::Android.Text.InputTypes.ClassText;
}
else
{
editText.Text = defaultInputText;
}

//入力項目を格納するレイアウト
LinearLayout linearLayout = new LinearLayout(Forms.Context);
linearLayout.Orientation = Orientation.Vertical;
linearLayout.AddView(editText);

//チェックボックス
CheckBox chkbox = null;
if (!String.IsNullOrEmpty(checkboxMessage))
{
chkbox = new CheckBox(Forms.Context);
chkbox.Text = checkboxMessage;
chkbox.TextAlignment = Android.Views.TextAlignment.TextStart;
chkbox.Checked = true;
linearLayout.AddView(chkbox);
}

var alert = new AlertDialog.Builder(Forms.Context);
alert.SetTitle(title);
alert.SetMessage(message);
alert.SetView(linearLayout);
alert.SetNegativeButton(cancel, (o, e) => tcs.SetResult(new EntryAlertResult
{
PressedButtonTitle = cancel,
InputText = editText.Text,
IsChecked = false
}));
alert.SetPositiveButton(accept, (o, e) => tcs.SetResult(new EntryAlertResult
{
PressedButtonTitle = accept,
InputText = editText.Text,
IsChecked = this.IsChecked(chkbox),
}));

alert.Show();

return tcs.Task;
}

private bool IsChecked(CheckBox chkbox)
{
if (chkbox != null)
{
return chkbox.Checked;
}
else
{
return false;
}
}
}
}



3.iOSの実装方法

iOSプロジェクト内に以下のファイルを記述します。
iOSにはチェックボックスが存在しないため、ボタンで代用し、画像ファイルを切り替えます。また、UIAlertControllerの縦幅の変更が難しく、表示後に位置を補正している関係上、少しちらつきますので、暫定版とさせていただければと思います。どなたか良い案があればお教えください。

EntryAlertService.cs
using System;
using System.Threading.Tasks;
using UIKit;
using CoreGraphics;
using Xamarin.Forms;
[assembly: Dependency(typeof(EntryAlertService))]
namespace AppName.iOS.Model.Services
{
public class EntryAlertService : IEntryAlertService
{
UIAlertController _alert = null;
UIButton _checkBox = null;
public Task<EntryAlertResult> Show(string title,
string message,
string defaultInputText,
string accept,
string cancel,
bool isPassword = false,
string checkboxMessage = "")
{
var tcs = new TaskCompletionSource<EntryAlertResult>();

UIApplication.SharedApplication.InvokeOnMainThread(() =>
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
_alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert);
//標準のOKキャンセルボタンの場合は以下
//alert.AddAction(UIAlertAction.Create(accepte, UIAlertActionStyle.Cancel, null));

//テキストボックスを表示
_alert.AddTextField((textBox) => {
textBox.Placeholder = @"Input Text";
textBox.Text = defaultInputText;
textBox.AutocorrectionType = UITextAutocorrectionType.No;
textBox.KeyboardType = UIKeyboardType.Default;
textBox.ReturnKeyType = UIReturnKeyType.Done;
textBox.ClearButtonMode = UITextFieldViewMode.WhileEditing;
if (isPassword)
{
textBox.SecureTextEntry = true;
}
else
{
textBox.SecureTextEntry = false;
}
});

UIView subView = null;
if (!String.IsNullOrEmpty(checkboxMessage))
{
//チェックボックスとラベルを表示
var label = new UILabel(new CGRect(x: 50, y: 235, width: 200, height: 28));
label.Text = checkboxMessage;
label.Font = UIFont.SystemFontOfSize(11);
var btnImage = UIImage.FromFile("checked_bk.png");
_checkBox = new UIButton(new CGRect(x: 15, y: 235, width: 28, height: 28));
_checkBox.Selected = true;
_checkBox.SetBackgroundImage(btnImage, UIControlState.Selected);
_checkBox.AddTarget(CheckBoxAction, UIControlEvent.TouchDown);

//タイトルとメッセージとテキストボックスが属するSubViewを取得し、同じ階層にチェックボックスを表示させます
subView = _alert.View.Subviews[0].Subviews[0].Subviews[0].Subviews[0];
subView.AddSubview(_checkBox);
subView.AddSubview(label);
}

//OKボタンを追加
_alert.AddAction(UIAlertAction.Create(accept, UIAlertActionStyle.Default, (actionOK) => {
tcs.SetResult(new EntryAlertResult
{
PressedButtonTitle = accept,
InputText = _alert.TextFields[0].Text,
IsChecked = _checkBox.Selected,
});
_alert.DismissViewController(true, null);
_alert.Dispose();
_alert = null;
}));

//キャンセルボタンを追加
_alert.AddAction(UIAlertAction.Create(cancel, UIAlertActionStyle.Cancel, (actionCancel) => {
tcs.SetResult(new EntryAlertResult
{
PressedButtonTitle = cancel,
InputText = String.Empty,
IsChecked = false,
});
_alert.DismissViewController(true, null);
_alert.Dispose();
_alert = null;
}));

//アラートダイアログを表示する
UINavigationController controller = NavigationUtility.FindNavigationController();
if (controller != null)
{
controller.PresentViewController(_alert, true, () =>
{
if (!String.IsNullOrEmpty(checkboxMessage))
{
//ダイアログを表示後に高さを変更します
if (subView != null &&
subView.Subviews.Length > 1)
{
var viewHeight = subView.Subviews[0].Bounds.Height;

subView.AddConstraint(
NSLayoutConstraint.Create(subView,
NSLayoutAttribute.Height,
NSLayoutRelation.Equal,
null,
NSLayoutAttribute.NoAttribute,
1,
viewHeight + 30)
);
//表示位置を変更する
label.Frame = new CGRect(x: 50, y: viewHeight - 5, width: 200, height: 28);
_checkBox.Frame = new CGRect(x: 15, y: viewHeight - 5, width: 28, height: 28);
}
}
});
}
}
});
return tcs.Task;
}

//チェックボックスの状態を切り替えます。
void CheckBoxAction(object sender, EventArgs e)
{
if (((UIButton)sender).Selected)
{
((UIButton)sender).Selected = false;
var btnImage = new UIImage("unchecked_bk.png");
((UIButton)sender).SetBackgroundImage(btnImage, UIControlState.Normal);
}
else
{
((UIButton)sender).Selected = true;
var btnImage = new UIImage("checked_bk.png");
((UIButton)sender).SetBackgroundImage(btnImage, UIControlState.Selected);
}
}

}
}

※FindNavigationController関数は以前の記事「UIActivityを使用して画像やファイルを共有する方法」をご参考ください。
※チェックボックスのPNG画像につきましては自作するか以前の記事「iOS用のチェックボックスを作成する方法」にてダウンロード可能です。iOSプロジェクト/Resourcesフォルダに保存してください。(ビルドアクション:BundleResource)



4.使用方法

PCLプロジェクトの中の任意のページに記述します。
iOSのPresentViewControllerがコンストラクタ内だと動作しないため、OnAppearingイベント内にて記述しています。

TestPage.xaml.cs
using AppName.Services;
using Xamarin.Forms;
public class TestPage : ContentPage
{
protected override void OnAppearing()
{
base.OnAppearing();

    EntryAlertResult result = await DependencyService.Get<IEntryAlertService>().Show(
"Title",
"Message",
"DefaultText",
"OK", "Cancel",
false,
"チェックラベルの文字列");
if (!result.PressedButtonTitle.Equals(AppResources.OK) ||
String.IsNullOrEmpty(result.InputText))
{
//入力がない場合は終了する。
return;
}
//結果を取得します
string text = result.InputText;
bool checked = result.IsChecked;
}
}





最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。