Xamarin.Forms で Micorosft Band の移動距離値を取得する
今回は Xamarin.Forms で移動距離値を取得してみます
ソースコードの一式は下記にあります!
細かい実装などはこちらを参照ください
※ 順次改修していく予定なので、この記事の内容が現時点のソースより古い可能性があります
ほとんど手順は変わらず、まずはデータのいれものを作ります
/// <summary> /// iOS 用移動距離データ /// </summary> public class NativeBandDistanceReading : IBandDistanceReading { /// <summary> /// コンストラクタ /// </summary> /// <param name="data">センサーデータ</param> public NativeBandDistanceReading(Native.Sensors.BandSensorDistanceData data) { this.Timestamp = DateTime.Now; this.CurrentMotion = MotionType.Unknown; if (data.PedometerMode == Native.Sensors.PedometerMode.Idle) { this.CurrentMotion = MotionType.Idle; } if (data.PedometerMode == Native.Sensors.PedometerMode.Walking) { this.CurrentMotion = MotionType.Walking; } if (data.PedometerMode == Native.Sensors.PedometerMode.Jogging) { this.CurrentMotion = MotionType.Jogging; } if (data.PedometerMode == Native.Sensors.PedometerMode.Running) { this.CurrentMotion = MotionType.Running; } this.Pace = (double)data.Pace; this.Speed = (double)data.Speed; this.TotalDistance = (long)data.TotalDistance; } /// <summary> /// 検出日時 /// </summary> public DateTimeOffset Timestamp { get; private set; } /// <summary> /// 移動状態 /// </summary> public MotionType CurrentMotion { get; private set; } /// <summary> /// 移動ペース /// </summary> public double Pace { get; private set; } /// <summary> /// 移動速度 /// </summary> public double Speed { get; private set; } /// <summary> /// 移動距離合計 /// </summary> public long TotalDistance { get; private set; } }
プラットフォーム側の列挙型は switch だと分岐できない(Binding の仕方がまずいだけ?)ので、愚直に if 分岐させました まぁ、iOS も Android もほぼ同じなのは変わらず
次にセンサー制御クラス
/// <summary> /// iOS 用移動距離センサー /// </summary> public class NativeBandDistanceSensor : NativeBandSensorBase<IBandDistanceReading> { /// <summary> /// 加速度センサー /// </summary> private Native.Sensors.DistanceSensor sensor = null; /// <summary> /// センサー値変更イベント /// </summary> public override event EventHandler<BandSensorReadingEventArgs<IBandDistanceReading>> ReadingChanged; /// <summary> /// コンストラクタ /// </summary> /// <param name="manager">Band センサー管理クラス</param> public NativeBandDistanceSensor(Native.Sensors.IBandSensorManager manager) : base(manager) { this.sensor = Native.Sensors.BandSensorManagerExtensions.CreateDistanceSensor(manager); this.sensor.ReadingChanged += this.OnReadingChanged; } /// <summary> /// センサー値変更イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnReadingChanged(object sender, Native.Sensors.BandSensorDataEventArgs<Native.Sensors.BandSensorDistanceData> e) { if (this.ReadingChanged == null) { return; } this.ReadingChanged.Invoke( this, new BandSensorReadingEventArgs<IBandDistanceReading>(new NativeBandDistanceReading(e.SensorReading))); } /// <summary> /// センサー検知を開始する /// </summary> /// <returns>Task</returns> public override Task StartReadingsAsync() { return Task.Run(() => this.sensor.StartReadings()); } /// <summary> /// センサー検知を停止する /// </summary> /// <returns>Task</returns> public override Task StopReadingsAsync() { return Task.Run(() => this.sensor.StopReadings()); } }
こっちが iOS
/// <summary> /// Android 用移動距離センサー /// </summary> public class NativeBandDistanceSensor : NativeBandSensorBase<IBandDistanceReading> { /// <summary> /// 移動距離センサー /// </summary> private Native.Sensors.DistanceSensor sensor = null; /// <summary> /// センサー値変更イベント /// </summary> public override event EventHandler<BandSensorReadingEventArgs<IBandDistanceReading>> ReadingChanged; /// <summary> /// コンストラクタ /// </summary> /// <param name="manager">Band センサー管理クラス</param> public NativeBandDistanceSensor(Native.Sensors.IBandSensorManager manager) : base(manager) { this.sensor = Native.Sensors.BandSensorManagerExtensions.CreateDistanceSensor(manager); this.sensor.ReadingChanged += this.OnReadingChanged; } /// <summary> /// センサー値変更イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnReadingChanged(object sender, Native.Sensors.IBandSensorEventEventArgs<Native.Sensors.IBandDistanceEvent> e) { if (this.ReadingChanged == null) { return; } this.ReadingChanged.Invoke( this, new BandSensorReadingEventArgs<IBandDistanceReading>(new NativeBandDistanceReading(e.SensorReading))); } /// <summary> /// センサー検知を開始する /// </summary> /// <returns>Task</returns> public override Task StartReadingsAsync() { return this.sensor.StartReadingsTaskAsync(); } /// <summary> /// センサー検知を停止する /// </summary> /// <returns>Task</returns> public override Task StopReadingsAsync() { return this.sensor.StopReadingsTaskAsync(); } }
こっちが Android
かなり単純作業の連続になってきましたがこれらに合わせて ViewModel を改修
/// <summary> /// センサー情報 ViewModel /// </summary> public class SensorReadingViewModel : BindableBase { ~ 中略 ~ #region DistanceSensor /// <summary> /// 移動状態 /// </summary> private MotionType currentMotion = MotionType.Unknown; /// <summary> /// 移動状態 /// </summary> public MotionType CurrentMotion { get { return this.currentMotion; } set { this.SetProperty<MotionType>(ref this.currentMotion, value); } } /// <summary> /// 移動ペース /// </summary> private double pace = 0d; /// <summary> /// 移動ペース /// </summary> public double Pace { get { return this.pace; } set { this.SetProperty<double>(ref this.pace, value); } } /// <summary> /// 移動速度 /// </summary> private double speed = 0d; /// <summary> /// 移動速度 /// </summary> public double Speed { get { return this.speed; } set { this.SetProperty<double>(ref this.speed, value); } } /// <summary> /// 移動距離合計 /// </summary> private long totalDistance = 0L; /// <summary> /// 移動距離合計 /// </summary> public long TotalDistance { get { return this.totalDistance; } set { this.SetProperty<long>(ref this.totalDistance, value); } } #endregion //DistanceSensor ~ 中略 ~ /// <summary> /// センサー監視切替 /// </summary> /// <param name="detecting">センサー監視フラグ</param> /// <returns>Task</returns> private async Task ChangeDetectSensors(bool detecting) { if (detecting) { // 加速度センサーの検知開始 if (this.client.SensorManager.Accelerometer.IsSupported) { await this.client.SensorManager.Accelerometer.StartReadingsAsync(); this.client.SensorManager.Accelerometer.ReadingChanged += this.OnAccelerometerReadingChanged; } // ジャイロセンサーの検知開始 if (this.client.SensorManager.Gyroscope.IsSupported) { await this.client.SensorManager.Gyroscope.StartReadingsAsync(); this.client.SensorManager.Gyroscope.ReadingChanged += this.OnGyroscopeReadingChanged; } // 心拍数の検知開始 if (this.client.SensorManager.HeartRate.IsSupported) { await this.client.SensorManager.HeartRate.StartReadingsAsync(); this.client.SensorManager.HeartRate.ReadingChanged += this.OnHeartRateReadingChanged; } // 歩数の検知開始 if (this.client.SensorManager.Pedometer.IsSupported) { await this.client.SensorManager.Pedometer.StartReadingsAsync(); this.client.SensorManager.Pedometer.ReadingChanged += this.OnPedometerReadingChanged; } // 移動距離の検知開始 if (this.client.SensorManager.Distance.IsSupported) { await this.client.SensorManager.Distance.StartReadingsAsync(); this.client.SensorManager.Distance.ReadingChanged += this.OnDistanceReadingChanged; } } else { // 加速度センサーの検知終了 if (this.client.SensorManager.Accelerometer.IsSupported) { await this.client.SensorManager.Accelerometer.StopReadingsAsync(); this.client.SensorManager.Accelerometer.ReadingChanged -= this.OnAccelerometerReadingChanged; this.AccelerationX = 0d; this.AccelerationY = 0d; this.AccelerationZ = 0d; } // ジャイロセンサーの検知終了 if (this.client.SensorManager.Gyroscope.IsSupported) { await this.client.SensorManager.Gyroscope.StopReadingsAsync(); this.client.SensorManager.Gyroscope.ReadingChanged -= this.OnGyroscopeReadingChanged; this.AngularVelocityX = 0d; this.AngularVelocityY = 0d; this.AngularVelocityZ = 0d; this.GyroAccelerationX = 0d; this.GyroAccelerationY = 0d; this.GyroAccelerationZ = 0d; } // 心拍数の検知終了 if (this.client.SensorManager.HeartRate.IsSupported) { await this.client.SensorManager.HeartRate.StopReadingsAsync(); this.client.SensorManager.HeartRate.ReadingChanged -= this.OnHeartRateReadingChanged; this.HeartRate = 0; this.HeartRateQuality = HeartRateQuality.Acquiring; } // 歩数の検知終了 if (this.client.SensorManager.Pedometer.IsSupported) { await this.client.SensorManager.Pedometer.StopReadingsAsync(); this.client.SensorManager.Pedometer.ReadingChanged -= this.OnPedometerReadingChanged; this.TotalSteps = 0L; } // 移動距離の検知終了 if (this.client.SensorManager.Distance.IsSupported) { await this.client.SensorManager.Distance.StopReadingsAsync(); this.client.SensorManager.Distance.ReadingChanged -= this.OnDistanceReadingChanged; this.CurrentMotion = MotionType.Unknown; this.Pace = 0d; this.Speed = 0d; this.TotalDistance = 0L; } } } ~ 中略 ~ /// <summary> /// 移動距離変更イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnDistanceReadingChanged(object sender, BandSensorReadingEventArgs<IBandDistanceReading> e) { if (e == null) { return; } this.CurrentMotion = e.SensorReading.CurrentMotion; this.Pace = e.SensorReading.Pace; this.Speed = e.SensorReading.Speed; this.TotalDistance = e.SensorReading.TotalDistance; } }
最後に 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:cv="clr-namespace:XamarinBandSample.Converters;assembly=XamarinBandSample" xmlns:t="clr-namespace:XamarinBandSample.Triggers;assembly=XamarinBandSample" xmlns:prismmvvm="clr-namespace:Prism.Mvvm;assembly=XamarinBandSample" prismmvvm:ViewModelLocator.AutoWireViewModel="true" x:Class="XamarinBandSample.Views.TopPage"> ~ 中略 ~ <!-- Sensor Info Pain--> <ScrollView IsVisible="{Binding ShowSensors}" Orientation="Vertical"> <Grid Padding="10" RowSpacing="10" ColumnSpacing="10" BindingContext="{Binding SensorReading}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> ~ 中略 ~ <StackLayout Orientation="Horizontal" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="5" Spacing="5"> <Label Text="Distance:" FontSize="Medium"/> <StackLayout Orientation="Vertical" Padding="10,0,0,0" Spacing="10"> <Label Text="{Binding CurrentMotion, StringFormat='motion={0}'}" FontSize="Small"/> <Label Text="{Binding Pace, StringFormat='pace={0}'}" FontSize="Small"/> <Label Text="{Binding Speed, StringFormat='speed={0}'}" FontSize="Small"/> <Label Text="{Binding TotalDistance, StringFormat='distance={0}'}" FontSize="Small"/> </StackLayout> </StackLayout> </Grid> </ScrollView> </Grid> </ContentPage>
表示領域を追加してお試し実行
移動距離も合計値なので、時間による管理が必要・・・めんどくさい;