.NET MAUIでGridをAbsoluteLayoutへ

Xamarin時代

例えば、XAMLで画面全体にGridを配置してmainGridって名前をつけてるとする。
そこに、hogeList、hogeViw、hogeButtonの3要素があったとして、それをコードからこんな感じで修正してたとする。

mainGrid.RowDefinitions.Clear();
mainGrid.ColumnDefinitions.Clear();

// Y軸
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(400, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(28, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(2, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });

// X軸
mainGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
mainGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(160, GridUnitType.Absolute) });
mainGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(100, GridUnitType.Absolute) });
mainGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(100, GridUnitType.Absolute) });
mainGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });

mainGrid.Children.Remove(hogeList);
mainGrid.Children.Remove(hogeView);
mainGrid.Children.Remove(hogeButton);

mainGrid.Children.Add(hogeList, 0, 5, 0, 2);
mainGrid.Children.Add(hogeView, 0, 5, 3, 5);
mainGrid.Children.Add(hogeButton, 2, 3, 5, 7);

.NET MAUI

GridをAbsoluteLayoutに置き換える

今現在の.NET MAUIの不具合で直るかもしれないけど、列や行の高さをプログラムから変更するコードを書くと、Debug版では動くのに、Release版ではアプリが吹っ飛んだから。
それでなくても、絶対座標を指定するならAbsoluteLayoutを使えってことなので、大人しくmainGridをmainAbsoluteLayoutに置き換えて、XAML上のGrid表記を直しておく。

でもHeight = 1,*とか使いたいじゃん

とりあえず、先頭と終端に反映するならこんな感じ。
もっと臨機応変に設定したいなら、頑張れ。

internal class LayoutControlh
{
    /// <summary>
    /// 先頭と末端に比率でサイズを調整する
    /// </summary>
    /// <param name="all">全体のサイズ</param>
    /// <param name="items">各パーツのサイズ</param>
    /// <param name="topStar">先端に適用する比率</param>
    /// <param name="bottomStar">末端に適用する比率</param>
    internal static void UpdateTopAndBottom(double all, ref List<double> items, int topStar, int bottomStar)
    {
        // 念の為、引数のチェック
        if (items == null || items.Count == 0) return;

        // 未使用の範囲を求める
        double useRange = all;
        for (int i = 1; i < items.Count - 1; i++)
        {
            useRange -= items[i];
        }

        // 未使用が残っているか
        if (0 < useRange)
        {
            double oneStar = useRange / (topStar + bottomStar);
            items[0] = oneStar * topStar;
            items[items.Count - 1] = useRange - items[0];
        }

    }
    
    /// <summary>
    /// 開始位置を取得
    /// </summary>
    /// <param name="item">各パーツのサイズ</param>
    /// <param name="idx">配置場所</param>
    /// <returns>指定した配置場所の座標を求める</returns>
    internal static double GetPosition(List<double> item, int idx)
    {
        double ret = 0;
        for(int i = 0; i < idx; i++)
        {
            ret += item[i];
        }
        return ret;
    }
}

レイアウトを指定していく

Grid.Children.Add(item, left, right, top, bottom)はそれぞれ、

  • Column = left
  • ColumnSpan = right – left
  • Row = top
  • RowSpan = bottom – top

なので、それを念頭において x, y, width, height を計算していく。

List<double> row = new List<double>();
List<double> col = new List<double>();

// Y軸
row = new List<double>() { 1, 400, 100, 100, 28, 2, 0 };

// X軸
col = new List<double>() { 0, 160, 100, 101, 0 };
LayoutControl.UpdateTopAndBottom(width, ref col, 1, 1);

double x, y, itemWidth, itemHeigt;

x = 0; y = 0;
itemWidth = width;
itemHeigt = row[0] + row[1];
AbsoluteLayout.SetLayoutBounds(hogeLabel, new Rect(x, y, itemWidth, itemHeigt));

// 例えばPadding = 8とか指定してたら、ここで指定しないといけない
x = 8;
y = LayoutControl.GetPosition(row, 3) + 8;
itemWidth = width - 16;
itemHeigt = row[3] + row[4] - 16;
AbsoluteLayout.SetLayoutBounds(hogeView, new Rect(x, y, itemWidth, itemHeigt));

x = LayoutControl.GetPosition(col, 2);
y = LayoutControl.GetPosition(row, 5);
itemWidth = col[2];
itemHeigt = row[5] + row[6];
AbsoluteLayout.SetLayoutBounds(hogeButton, new Rect(x, y, itemWidth, itemHeigt));

ぬああああ、面倒くさい!
もっと簡単な方法ないもんか!
でも、画面の縦横の比率でレイアウトを変えたいとか要望があるときは分岐しないといけないので、XAMLだけでなんとかはならんだろうな。


他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)