ぴーさんログ

だいたいXamarin.Formsのブログ

【Xamarin.Forms】 AbsoluteLayoutでプロポーショナルレイアウト

AbsoluteLayout を使うと画像の上にボタンやラベルといったコントロールを重ねることができます。さらに、Xamarin.FormsのAbsoluteLayoutは「LayoutFlags」と「LayoutBounds」を駆使することでとても柔軟なレイアウトが可能となっています。

自分で絶対座標を計算しなくても良いのは素敵ですね。

LayoutFlags と LayoutBounds

LayoutFlags、LayoutBoundsを適切に設定することで親要素(AbsoluteLayout)に対する位置、サイズを比率で指定することができます。

LayoutFlagsは AbsoluteLayoutFlags 列挙型として定義されています。

public enum AbsoluteLayoutFlags
{
    None = 0,
    XProportional = 1,
    YProportional = 2,
    WidthProportional = 4,
    HeightProportional = 8,
    PositionProportional = 3,
    SizeProportional = 12,
    All = -1
}

AbsoluteLayoutFlags の指定によって Rectangleの解釈が変わり、「〜Proportional」に対応する部分は絶対値ではなく、座標やサイズを0〜1の比率で指定したものとして扱われます。例えば、 WidthProportional が指定されている場合に Rectangle.Width を 1 に設定すると、子要素の幅は親要素(AbsoluteLayout)に対する100%(親要素の幅と同じ)となります。

Rectangle.WidthRectangle.Height には絶対値の代わりに AbsoluteLayout.AutoSize を指定することができます。(XAMLの場合は AutoSize ) これにより、要素の動的なサイズ変化にも対応してくれます。

LayoutFlags、LayoutBoundsの指定はC#で書くとこうなります。

AbsoluteLayout.SetLayoutFlags (
    label, 
    AbsoluteLayoutFlags.PositionProportional
);
 
AbsoluteLayout.SetLayoutBounds (
    label, 
    new Rectangle (
        0.5,                       // X
        0.5,                       // Y
        AbsoluteLayout.AutoSize,    // Width
        AbsoluteLayout.AutoSize)    // Height
);

同じことをXAMLで書くとこうなります。

<Label Text="中心に配置" 
       AbsoluteLayout.LayoutFlags="PositionProportional"
       AbsoluteLayout.LayoutBounds="0.5, 0.5, AutoSize, AutoSize"/>

LayoutFlagsの複数指定

AbsoluteLayoutFlags は組み合わせることができます。例えば、 PositionProportional を指定するのは XProportionalYProportional を同時に指定するのと等しく、 SizeProportional を指定するのは WidthProportionalHeightProportional を同時に指定するのと等しくなります。

C#で書く場合は論理和を使います。

AbsoluteLayout.SetLayoutFlags (
    label, 
    AbsoluteLayoutFlags.XProportional | 
    AbsoluteLayoutFlags.YProportional);
AbsoluteLayout.SetLayoutBounds (label, new Rectangle (0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

XAMLで書く場合はカンマ(,)で区切ります。

<Label Text="中心に配置"
         AbsoluteLayout.LayoutFlags="XProportional, YProportional"
         AbsoluteLayout.LayoutBounds="0.5, 0.5, AutoSize, AutoSize"/>

サンプル:帯状に配置

AbsoluteLayout の上下左右の領域に配置するサンプル。メニューやキャプションを置く場所として使うイメージ。うまく調整すれば四角いフレームなんかも作れそうですね。

こんな感じ。

f:id:ticktack623:20150924184809j:plain

上付き

C#

AbsoluteLayout.SetLayoutFlags (boxView, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds (boxView, new Rectangle (0.5, 0, 1, 0.25));

XAML

<BoxView Color="#88D3381C"
         AbsoluteLayout.LayoutFlags="All"
         AbsoluteLayout.LayoutBounds="0.5, 0, 1, 0.25"/>

下付き

C#

AbsoluteLayout.SetLayoutFlags (boxView, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds (boxView, new Rectangle (0.5, 1, 1, 0.25));

XAML

<BoxView Color="#88AACF53"
         AbsoluteLayout.LayoutFlags="All"
         AbsoluteLayout.LayoutBounds="0.5, 1, 1, 0.25"/>

左付き

C#

AbsoluteLayout.SetLayoutFlags (boxView, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds (boxView, new Rectangle (0, 0.5, 0.25, 1));

XAML

<BoxView Color="#881E50A2"
         AbsoluteLayout.LayoutFlags="All"
         AbsoluteLayout.LayoutBounds="0, 0.5, 0.25, 1"/>

右付き

C#

AbsoluteLayout.SetLayoutFlags (boxView, AbsoluteLayoutFlags.All);
AbsoluteLayout.SetLayoutBounds (boxView, new Rectangle (1, 0.5, 0.25, 1));

XAML

<BoxView Color="#88EBD842"
         AbsoluteLayout.LayoutFlags="All"
         AbsoluteLayout.LayoutBounds="1, 0.5, 0.25, 1"/>

サンプル:隅に配置

AbsoluteLayout の中央と四隅に配置するサンプル。幅、高さに AbsoluteLayout.AutoSize を指定することで要素のサイズ変化にも対応してくれます。例えば、右下の要素が大きくなった場合でも画面外にはみ出ることなく、収まるように再配置してくれます。

こんな感じ。

f:id:ticktack623:20150924184814j:plain

中心に配置

C#

AbsoluteLayout.SetLayoutFlags (label, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds (label, new Rectangle (0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

XAML

<Label Text="中心に配置" 
       AbsoluteLayout.LayoutFlags="PositionProportional"
       AbsoluteLayout.LayoutBounds="0.5, 0.5, AutoSize, AutoSize"/>

左上に配置

C#

AbsoluteLayout.SetLayoutFlags (label, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds (label, new Rectangle (0, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

XAML

<Label Text="左上に配置" 
       AbsoluteLayout.LayoutFlags="PositionProportional"
       AbsoluteLayout.LayoutBounds="0, 0, AutoSize, AutoSize"/>

右上に配置

C#

AbsoluteLayout.SetLayoutFlags (label, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds (label, new Rectangle (1, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

XAML

<Label Text="右上に配置" 
       AbsoluteLayout.LayoutFlags="PositionProportional"
       AbsoluteLayout.LayoutBounds="1, 0, AutoSize, AutoSize"/>

右下に配置

C#

AbsoluteLayout.SetLayoutFlags (label, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds (label, new Rectangle (1, 1, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

XAML

<Label Text="右下に配置" 
       AbsoluteLayout.LayoutFlags="PositionProportional"
       AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize"/>

左下に配置

C#

AbsoluteLayout.SetLayoutFlags (label, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds (label, new Rectangle (0, 1, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

XAML

<Label Text="左下に配置" 
       AbsoluteLayout.LayoutFlags="PositionProportional"
       AbsoluteLayout.LayoutBounds="0, 1, AutoSize, AutoSize"/>

参考

Xamarin.Forms AbsoluteLayout Recipe

Demystifying Xamarin Forms AbsoluteLayout and RelativeLayout positioning. | Adventures in Xamarin Forms