しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin.iOS の Anchor プロパティが正しく解釈されない件

すでにわんくまとか 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 で

f:id:matatabi_ux:20141204230904p:plain

左が AnchorX=0.5、Anchor=0.9、Rotation=0 の表示で、右が Rotation=90 だけ変えた場合です

この XAML コードをそのまま iOSデバッグすると・・・

f:id:matatabi_ux:20141204231034p:plain

なぜかこんな惨事に・・・どういう座標計算でこうなったのはちょっとわかりませんが、回転変換で中心点の座標位置を表すはずの 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;

時計の針の座標位置は上記のような感じで自力で計算するようにしました・・・トホホ

f:id:matatabi_ux:20141204231938p:plain

これで何とか思い通りの表示に・・・早く Xamarin の中の人が直してくれないかなぁ~チラッチラッ!