すでにわんくまとか Qiita で公開しちゃってるのでバレバレですが、Xamarin の BoxView のアナログ時計サンプル を XAML × MVVM に移植しようとしてハマったのが、Xamarin.iOS だけ AnchorX や AnchorY が正しく解釈されない問題です;
<?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:prismmvvm="clr-namespace:Prism.Mvvm;assembly=Prism.Mvvm.Xamarin" xmlns:local="clr-namespace:XamarinUnityInjection.Views;assembly=XamarinUnityInjection" xmlns:cv="clr-namespace:XamarinUnityInjection.Converters;assembly=XamarinUnityInjection" xmlns:vm="clr-namespace:XamarinUnityInjection.ViewModels;assembly=XamarinUnityInjection" prismmvvm:ViewModelLocator.AutoWireViewModel="true" local:PageStateDetect.DetectState="true" x:Class="XamarinUnityInjection.Views.TopPage"> <ContentPage.Resources> <ResourceDictionary> <cv:RectangleConverter x:Key="RectangleConverter"/> </ResourceDictionary> </ContentPage.Resources> <AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> <!-- 目盛り描画 --> <local:AbsoluteItemsControl HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" x:TypeArguments="vm:TickItemViewModel" ItemsSource="{Binding TickItems}"> <local:AbsoluteItemsControl.ItemTemplate> <DataTemplate> <BoxView Color="#2C267F" AbsoluteLayout.LayoutBounds="{Binding LayoutBounds, Converter={StaticResource RectangleConverter}}" AbsoluteLayout.LayoutFlags="None" AnchorX="0.5" AnchorY="0.5" Rotation="{Binding Rotation}"/> </DataTemplate> </local:AbsoluteItemsControl.ItemTemplate> </local:AbsoluteItemsControl> <!-- 秒針描画 --> <BoxView Color="#1000FF" Opacity="0.5" AbsoluteLayout.LayoutBounds="237.34, 182.04, 4.32, 237.6" AbsoluteLayout.LayoutFlags="None" AnchorX="0.5" AnchorY="0.9" Rotation="90"/> </AbsoluteLayout> </ContentPage>
上記のような XAML で秒針を描画しようとしたのですが、Windows Phone と iOS で描画結果が変わってしまいました
期待する表示となったのは Windows Phone で
左が AnchorX=0.5、Anchor=0.9、Rotation=0 の表示で、右が Rotation=90 だけ変えた場合です
この XAML コードをそのまま iOS でデバッグすると・・・
なぜかこんな惨事に・・・どういう座標計算でこうなったのはちょっとわかりませんが、回転変換で中心点の座標位置を表すはずの Anchor 指定が正しく解釈されていないようです
うまく解釈されないのならば自力で座標計算するしかありません・・・
DateTime dateTime = DateTime.Now; var radius = Math.Min(this.width, this.height); double radians = ((dateTime.Hour % 12) * 60 + dateTime.Minute + 360) * 2 * Math.PI / 720; this.hourHand.Width = 0.125 * 0.45 * radius; this.hourHand.Height = 0.65 * 0.45 * radius; this.hourHand.Left = this.centerX - 0.5 * this.hourHand.Width - 0.4 * this.hourHand.Height * Math.Sin(radians); this.hourHand.Top = this.centerY - 0.5 * this.hourHand.Height + 0.4 * this.hourHand.Height * Math.Cos(radians); this.hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute; radians = (dateTime.Minute * 60 + dateTime.Second + 1800) * 2 * Math.PI / 3600; this.minuteHand.Width = 0.05 * 0.45 * radius; this.minuteHand.Height = 0.8 * 0.45 * radius; this.minuteHand.Left = this.centerX - 0.5 * this.minuteHand.Width - 0.4 * this.minuteHand.Height * Math.Sin(radians); this.minuteHand.Top = this.centerY - 0.5 * this.minuteHand.Height + 0.4 * this.minuteHand.Height * Math.Cos(radians); this.minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second; radians = (dateTime.Second + 30) * 2 * Math.PI / 60; this.secondHand.Width = 0.02 * 0.45 * radius; this.secondHand.Height = 1.1 * 0.45 * radius; this.secondHand.Left = this.centerX - 0.5 * this.secondHand.Width - 0.35 * this.secondHand.Height * Math.Sin(radians); this.secondHand.Top = this.centerY - 0.5 * this.secondHand.Height + 0.35 * this.secondHand.Height * Math.Cos(radians); this.secondHand.Rotation = 6 * dateTime.Second;
時計の針の座標位置は上記のような感じで自力で計算するようにしました・・・トホホ
これで何とか思い通りの表示に・・・早く Xamarin の中の人が直してくれないかなぁ~チラッチラッ!