因为C# Maui还没有把GridSplitter加入到正式支持,但是这个也不是很重要,自己实现一个就行了。继承Border可实现多种样式。

GridSplitter.cs代码

using Microsoft.Maui.Controls.Shapes;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Shares.Utility
{
    public class GridSplitter : Border
    {
        private double positionX;
        private double positionY;

        public bool IsRowSplitter { get; set; }
        public double CornerRadius { get; set; }
        public GridSplitter()
        {
            // 添加拖拽手势识别器
            var panGesture = new PanGestureRecognizer();
            panGesture.PanUpdated += OnPanUpdated;
            GestureRecognizers.Add(panGesture);
            StrokeShape = new RoundRectangle { CornerRadius = CornerRadius };
        }
   
        private void OnPanUpdated(object? sender, PanUpdatedEventArgs e)
        {
            switch (e.StatusType)
            {
                case GestureStatus.Running:
                    var totalX = e.TotalX - positionX;
                    var totalY = e.TotalY - positionY;

                    UpdateGrid(totalX, totalY);

                    positionX = e.TotalX;
                    positionY = e.TotalY;
                    break;

                case GestureStatus.Started:
                case GestureStatus.Completed:
                case GestureStatus.Canceled:
                    break;
            }
        }

        public void UpdateGrid(double dragOffsetX, double dragOffsetY)
        {
            if (Parent as Grid == null)
            {
                return;
            }

            if (IsRowSplitter)
            {
                UpdateRow(dragOffsetY);
            }
            else
                UpdateColumn(dragOffsetX);
            (this.Parent as Grid)?.InvalidateMeasure(); // 触发重新布局
        }

        private void UpdateRow(double offsetY)
        {
            if (offsetY == 0)
            {
                return;
            }

            Grid? grid = Parent as Grid;
            var row = Grid.GetRow(this);
            int rowCount = grid!.RowDefinitions.Count();
            if (rowCount <= 1 ||
                row == 0 ||
                row == rowCount - 1 ||
                row + Grid.GetRowSpan(this) >= rowCount)
            {
                return;
            }

            RowDefinition rowAbove = grid.RowDefinitions[row - 1];
            double actualHeight = GetRowDefinitionActualHeight(rowAbove) + offsetY;
            if (actualHeight < 0)
            {
                actualHeight = 0;
            }

            rowAbove.Height = new GridLength(actualHeight);
        }

        private void UpdateColumn(double offsetX)
        {
            if (offsetX == 0)
            {
                return;
            }

            Grid? grid = Parent as Grid;
            int column = Grid.GetColumn(this);

            int columnCount = grid!.ColumnDefinitions.Count();
            if (columnCount <= 1 ||
                column == 0 ||
                column == columnCount - 1 ||
                column + Grid.GetColumnSpan(this) >= columnCount)
            {
                return;
            }

            ColumnDefinition columnLeft = grid.ColumnDefinitions[column - 1];

            double actualWidth = GetColumnDefinitionActualWidth(columnLeft) + offsetX;
            if (actualWidth < 0)
            {
                actualWidth = 0;
            }

            columnLeft.Width = new GridLength(actualWidth);
        }

        private double GetRowDefinitionActualHeight(RowDefinition row)
        {
            double actualHeight;

            if (row.Height.IsAbsolute)
            {
                actualHeight = row.Height.Value;
            }
            else
            {
                actualHeight = (double)row.GetType().GetRuntimeProperties().First((p) => p.Name == "ActualHeight").GetValue(row)!;
                if (actualHeight == 0)
                {
                    Grid? grid = Parent as Grid;
                    foreach (var child in grid!.Children)
                    {
                        if (grid.GetRow(child)<grid.GetRow(this) && grid.GetColumn(child) == 0 && child is View v)
                            actualHeight += v.Height;
                    }
                }
            }
            return actualHeight;
        }

        private double GetColumnDefinitionActualWidth(ColumnDefinition column)
        {
            double actualWidth;

            if (column.Width.IsAbsolute)
            {
                actualWidth = column.Width.Value;
            }
            else
            {
                actualWidth = (double)column.GetType().GetRuntimeProperties().First((p) => p.Name == "ActualWidth").GetValue(column)!;
                if (actualWidth == 0)
                {
                    Grid? grid = Parent as Grid;
                    foreach (var child in grid!.Children)
                    {
                        if (grid.GetColumn(child) < grid.GetColumn(this) && grid.GetRow(child) == 0 && child is View v)
                            actualWidth += v.Width;
                    }
                }
            }

            return actualWidth;
        }
    }
}

SplitWindow.xaml的代码如下

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Shares.Utility;assembly=Shares"
             x:Class="MauiViews.MauiDemos.Book._03.SplitWindow"
             Title="SplitWindow" HeightRequest="300" WidthRequest="300">
    <Grid RowDefinitions="*,auto, *" ColumnDefinitions="100,auto,100">
        <Button Margin="3" Text="Left"/>
        <Button Grid.Column="2" Margin="3" Text="Right"/>
        <Button Grid.Row="2" Grid.Column="0" Margin="3" Text="Left"/>
        <Button Grid.Row="2" Grid.Column="2" Margin="3" Text="Right"/>
        <local:GridSplitter Grid.Row="1" Grid.ColumnSpan="3" BackgroundColor="DarkGray"
                            CornerRadius="30" HeightRequest="6" IsRowSplitter="True"/>
    </Grid>
</ContentPage>

对应的cs代码是默认,运行效果。

 

posted on 2025-06-16 13:43  dalgleish  阅读(26)  评论(0)    收藏  举报