先日Cognitive Serviceを使った笑顔判定機を作りました。
こいつですが、Web上のAPIを呼び出して回線状況に応じては、そこそこ時間がかかるにも関わらず、処理中を示すUIが表示されていませんでした。
Xamarin.Formsでは、ActivityIndicator
クラスを使うことで、簡単にインジケーターを出すことができます。
写真はおっさんの顔になってしまうので省きますが…
使い方は簡単です。画面の全体を覆うようにGridを置いて、そこにメインコンテンツとActivityIndicator
を置くだけです。そして、ActivityIndicator
のIsRunning
プロパティにTrueかFalseを設定することで表示・非表示を切り替えます。XAML的には以下のような感じ。
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms" prism:ViewModelLocator.AutowireViewModel="True" x:Class="SmileXamarinApp.Views.MainPage" Title="MainPage"> <ContentPage.ToolbarItems> <ToolbarItem Text="写真" Command="{Binding TakePhotoCommand}" /> </ContentPage.ToolbarItems> <Grid> <StackLayout HorizontalOptions="Center" VerticalOptions="Center"> <Image Source="{Binding ImageSource}" /> </StackLayout> <ActivityIndicator IsRunning="{Binding IsBusy}" /> </Grid> </ContentPage>
IsBusy
がVMに追加したプロパティでAPI呼び出し中だけTrueになるように制御しておきます。
using Microsoft.ProjectOxford.Face; using Plugin.Media; using Prism.Commands; using Prism.Mvvm; using Prism.Navigation; using Prism.Services; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Xamarin.Forms; namespace SmileXamarinApp.ViewModels { public class MainPageViewModel : BindableBase, INavigationAware { private ImageSource imageSource; public ImageSource ImageSource { get { return this.imageSource; } set { this.SetProperty(ref this.imageSource, value); } } private IPageDialogService PageDialogService { get; } public DelegateCommand TakePhotoCommand { get; } private bool isBusy; public bool IsBusy { get { return this.isBusy; } set { this.SetProperty(ref this.isBusy, value); } } public MainPageViewModel(IPageDialogService pageDialogService) { this.PageDialogService = pageDialogService; this.TakePhotoCommand = new DelegateCommand(async() => await this.TakePhotoAsync()); } private async Task TakePhotoAsync() { var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions { DefaultCamera = Plugin.Media.Abstractions.CameraDevice.Front, AllowCropping = false, }); if (file == null) { return; } this.ImageSource = ImageSource.FromStream(() => file.GetStream()); try { this.IsBusy = true; var client = new FaceServiceClient("Your API Key"); var result = await client.DetectAsync(file.GetStream(), returnFaceAttributes: new[] { FaceAttributeType.Smile, }); if (!result.Any()) { return; } await this.PageDialogService.DisplayAlertAsync("Smile point", $"Your smile point is {result.First().FaceAttributes.Smile * 100}", "OK"); } finally { this.IsBusy = false; } } public void OnNavigatedFrom(NavigationParameters parameters) { } public void OnNavigatedTo(NavigationParameters parameters) { } } }
これで、処理中なのかなどうなのかな?という疑問を持たなくてすむようになりました。コードは同じくGitHubのリポジトリにあげています。