using Microsoft.Maui.Controls; using Microsoft.Maui.Graphics; using System; namespace NotesDataAnalyst { public partial class ResizableCanvasPage : ContentPage { private const double InitialWidth = 150; private const double InitialHeight = 100; private double startX, startY; public ResizableCanvasPage() { InitializeComponent(); } private void AddResizableObject(double x, double y) { // Создаем основной контейнер (Frame) для объекта и ручки var resizableFrame = new Frame { BackgroundColor = Colors.LightBlue, BorderColor = Colors.DarkBlue, CornerRadius = 8, WidthRequest = InitialWidth, HeightRequest = InitialHeight, Padding = 0, // Убираем внутренние отступы Content = new Grid() // Используем Grid для добавления содержимого и ручки }; // Создаем содержимое внутри фрейма var content = new StackLayout { BackgroundColor = Colors.LightBlue, Children = { new Label { Text = "Resizable Object", HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center } } }; var resizeHandle = new BoxView { BackgroundColor = Colors.Gray, WidthRequest = 20, HeightRequest = 20 }; // Создаем Grid внутри Frame var grid = (Grid)resizableFrame.Content; // Настроим сетку: добавим два столбца и две строки grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star }); grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); // для ручки grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star }); grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // для ручки // Добавляем содержимое в первую ячейку (столбец 0, строка 0) grid.Children.Add(content); // Без указания колонок/строк // Добавляем ручку в правый нижний угол (столбец 1, строка 1) grid.Children.Add(resizeHandle); // Без указания колонок/строк // Устанавливаем строку и колонку для ручки Grid.SetRow(resizeHandle, 1); Grid.SetColumn(resizeHandle, 1); // Добавляем панораму для перемещения объекта var panGesture = new PanGestureRecognizer(); panGesture.PanUpdated += (s, e) => OnDragPanUpdated(s, e, resizableFrame); resizableFrame.GestureRecognizers.Add(panGesture); // Добавляем панораму для изменения размера var resizePanGesture = new PanGestureRecognizer(); resizePanGesture.PanUpdated += (s, e) => OnResizePanUpdated(s, e, resizableFrame, resizeHandle); resizeHandle.GestureRecognizers.Add(resizePanGesture); // Устанавливаем позицию фрейма AbsoluteLayout.SetLayoutBounds(resizableFrame, new Rect(x, y, InitialWidth, InitialHeight)); CanvasLayout.Children.Add(resizableFrame); // Обновляем позицию ручки UpdateResizeHandlePosition(resizableFrame, resizeHandle); } private void OnDragPanUpdated(object sender, PanUpdatedEventArgs e, Frame frame) { if (e.StatusType == GestureStatus.Started) { startX = AbsoluteLayout.GetLayoutBounds(frame).X; startY = AbsoluteLayout.GetLayoutBounds(frame).Y; } else if (e.StatusType == GestureStatus.Running) { double x = startX + e.TotalX; double y = startY + e.TotalY; AbsoluteLayout.SetLayoutBounds(frame, new Rect(x, y, frame.WidthRequest, frame.HeightRequest)); // Обновляем позицию ручки var resizeHandle = (BoxView)((Grid)frame.Content).Children[1]; UpdateResizeHandlePosition(frame, resizeHandle); } } private void OnResizePanUpdated(object sender, PanUpdatedEventArgs e, Frame frame, BoxView resizeHandle) { if (e.StatusType == GestureStatus.Started) { startX = frame.WidthRequest; startY = frame.HeightRequest; } else if (e.StatusType == GestureStatus.Running) { double newWidth = Math.Max(50, startX + e.TotalX); double newHeight = Math.Max(50, startY + e.TotalY); frame.WidthRequest = newWidth; frame.HeightRequest = newHeight; // Обновляем позицию ручки после изменения размеров UpdateResizeHandlePosition(frame, resizeHandle); } } private void UpdateResizeHandlePosition(Frame frame, BoxView resizeHandle) { var frameBounds = AbsoluteLayout.GetLayoutBounds(frame); double x = frameBounds.X + frame.WidthRequest - resizeHandle.WidthRequest; double y = frameBounds.Y + frame.HeightRequest - resizeHandle.HeightRequest; AbsoluteLayout.SetLayoutBounds(resizeHandle, new Rect(x, y, resizeHandle.WidthRequest, resizeHandle.HeightRequest)); } protected override void OnAppearing() { base.OnAppearing(); AddResizableObject(100, 100); AddResizableObject(400, 200); AddResizableObject(700, 400); } } }