Хрен знает
This commit is contained in:
parent
1303209095
commit
af9466c0a6
3 changed files with 110 additions and 245 deletions
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<!-- Главная страница приложения -->
|
<!-- Главная страница приложения -->
|
||||||
<FlyoutItem Title="Главная" Icon="add.png">
|
<FlyoutItem Title="Главная" Icon="add.png">
|
||||||
<ShellContent ContentTemplate="{DataTemplate local:ResizableCanvasPage}" />
|
<ShellContent ContentTemplate="{DataTemplate local:GraphPage}" />
|
||||||
</FlyoutItem>
|
</FlyoutItem>
|
||||||
|
|
||||||
<!-- Выпадающий список категорий -->
|
<!-- Выпадающий список категорий -->
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace NotesDataAnalyst
|
namespace NotesDataAnalyst
|
||||||
{
|
{
|
||||||
|
|
||||||
public partial class GraphPage : ContentPage
|
public partial class GraphPage : ContentPage
|
||||||
{
|
{
|
||||||
|
private PointF _initialNodePosition;
|
||||||
private PointF _initialNodePosition; // Õðàíèò íà÷àëüíóþ ïîçèöèþ íîäû
|
private PointF _initialTouchPosition;
|
||||||
private PointF _initialTouchPosition; // Õðàíèò íà÷àëüíóþ ïîçèöèþ êàñàíèÿ
|
private SizeF _initialNodeSize;
|
||||||
private SizeF _initialNodeSize; // Õðàíèò íà÷àëüíûé ðàçìåð íîäû
|
|
||||||
private DateTime tapStartTime;
|
|
||||||
private const int longPressDuration = 3000; // 3 ñåêóíäû â ìèëëèñåêóíäàõ
|
|
||||||
|
|
||||||
private readonly List<GraphNode> _nodes = new();
|
private readonly List<GraphNode> _nodes = new();
|
||||||
private readonly List<GraphConnection> _connections = new();
|
private readonly List<GraphConnection> _connections = new();
|
||||||
private GraphNode _selectedNode;
|
private GraphNode _selectedNode;
|
||||||
|
|
@ -22,13 +17,9 @@ namespace NotesDataAnalyst
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Íàñòðàèâàåì Drawable äëÿ îòðèñîâêè óçëîâ è ñâÿçåé
|
|
||||||
var graphDrawable = new GraphDrawable(_nodes, _connections);
|
var graphDrawable = new GraphDrawable(_nodes, _connections);
|
||||||
canvasView.Drawable = graphDrawable;
|
canvasView.Drawable = graphDrawable;
|
||||||
|
|
||||||
// Äîáàâëÿåì æåñòû
|
|
||||||
var panGesture = new PanGestureRecognizer();
|
var panGesture = new PanGestureRecognizer();
|
||||||
panGesture.PanUpdated += OnPanUpdated;
|
panGesture.PanUpdated += OnPanUpdated;
|
||||||
canvasView.GestureRecognizers.Add(panGesture);
|
canvasView.GestureRecognizers.Add(panGesture);
|
||||||
|
|
@ -36,73 +27,6 @@ namespace NotesDataAnalyst
|
||||||
var tapGesture = new TapGestureRecognizer();
|
var tapGesture = new TapGestureRecognizer();
|
||||||
tapGesture.Tapped += OnCanvasTapped;
|
tapGesture.Tapped += OnCanvasTapped;
|
||||||
canvasView.GestureRecognizers.Add(tapGesture);
|
canvasView.GestureRecognizers.Add(tapGesture);
|
||||||
|
|
||||||
var tapGestureRecognizer = new TapGestureRecognizer();
|
|
||||||
tapGestureRecognizer.Tapped += OnTapped;
|
|
||||||
canvasView.GestureRecognizers.Add(tapGestureRecognizer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void OnTapped(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
tapStartTime = DateTime.Now;
|
|
||||||
|
|
||||||
Device.StartTimer(TimeSpan.FromMilliseconds(longPressDuration), () =>
|
|
||||||
{
|
|
||||||
if ((DateTime.Now - tapStartTime).TotalMilliseconds >= longPressDuration)
|
|
||||||
{
|
|
||||||
// Çäåñü âûïîëíÿåòñÿ äåéñòâèå ïðè äëèòåëüíîì íàæàòèè
|
|
||||||
// OnNodeLongPressed();
|
|
||||||
}
|
|
||||||
return false; // Îñòàíàâëèâàåì òàéìåð
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
private void OnNodeLongPressed()
|
|
||||||
{
|
|
||||||
if (_selectedNode != null)
|
|
||||||
{
|
|
||||||
// Äîáàâëÿåì äî÷åðíþþ íîäó ðÿäîì ñ àêòèâíîé
|
|
||||||
var childNode = new GraphNode
|
|
||||||
{
|
|
||||||
Text = "Äî÷åðíÿÿ íîäà",
|
|
||||||
Position = new Point(_selectedNode.Position.X + 50, _selectedNode.Position.Y + 50),
|
|
||||||
Size = new Size(150, 100)
|
|
||||||
};
|
|
||||||
|
|
||||||
_nodes.Add(childNode);
|
|
||||||
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = childNode });
|
|
||||||
|
|
||||||
canvasView.Invalidate(); // Ïåðåðèñîâûâàåì
|
|
||||||
}
|
|
||||||
|
|
||||||
// Çäåñü ðåàëèçóéòå äåéñòâèå ïðè äëèòåëüíîì íàæàòèè
|
|
||||||
// DisplayAlert("Äëèòåëüíîå íàæàòèå", "Âû íàæàëè è óäåðæèâàëè ýëåìåíò", "ÎÊ");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private void OnNodeTapped(object sender, TappedEventArgs e)
|
|
||||||
{
|
|
||||||
var node = _selectedNode;
|
|
||||||
|
|
||||||
Debug.WriteLine("Íàæàòà íîäà - {node}");
|
|
||||||
}
|
|
||||||
private void OnChildClicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (_selectedNode != null)
|
|
||||||
{
|
|
||||||
var child = new GraphNode
|
|
||||||
{
|
|
||||||
Text = "Child Node",
|
|
||||||
Position = new Point(_selectedNode.Position.X + 5, _selectedNode.Position.Y + 5),
|
|
||||||
Size = _selectedNode.Size,
|
|
||||||
BackgroundColor = Colors.Gray,
|
|
||||||
};
|
|
||||||
_nodes.Add(child);
|
|
||||||
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = child });
|
|
||||||
canvasView.Invalidate();
|
|
||||||
|
|
||||||
}
|
|
||||||
else { Debug.WriteLine("Ñíà÷àëà âûáèðèòå íîäó"); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnAddNodeClicked(object sender, EventArgs e)
|
private async void OnAddNodeClicked(object sender, EventArgs e)
|
||||||
|
|
@ -110,7 +34,7 @@ namespace NotesDataAnalyst
|
||||||
|
|
||||||
var newNode = new GraphNode
|
var newNode = new GraphNode
|
||||||
{
|
{
|
||||||
Text = "Íîâàÿ íîäà",
|
Text = "Íîâàÿ íîäà",
|
||||||
Position = new Point(300, 200),
|
Position = new Point(300, 200),
|
||||||
Size = new Size(200, 200),
|
Size = new Size(200, 200),
|
||||||
|
|
||||||
|
|
@ -120,8 +44,28 @@ namespace NotesDataAnalyst
|
||||||
canvasView.Invalidate();
|
canvasView.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Îáðàáîò÷èê äëÿ âûáîðà óçëà
|
private void OnChildClicked(object sender, EventArgs e)
|
||||||
// Îáðàáîò÷èê äëÿ âûáîðà óçëà
|
{
|
||||||
|
if (_selectedNode != null)
|
||||||
|
{
|
||||||
|
var childNode = new GraphNode
|
||||||
|
{
|
||||||
|
Text = "Child Node",
|
||||||
|
Position = new Point(_selectedNode.Position.X + 100, _selectedNode.Position.Y + 70),
|
||||||
|
Size = _selectedNode.Size,
|
||||||
|
BackgroundColor = Colors.Gray,
|
||||||
|
};
|
||||||
|
_nodes.Add(childNode);
|
||||||
|
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = childNode });
|
||||||
|
canvasView.Invalidate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Сначала выберите ноду");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnCanvasTapped(object sender, TappedEventArgs e)
|
private void OnCanvasTapped(object sender, TappedEventArgs e)
|
||||||
{
|
{
|
||||||
var tapPosition = e.GetPosition((View)sender);
|
var tapPosition = e.GetPosition((View)sender);
|
||||||
|
|
@ -132,37 +76,27 @@ namespace NotesDataAnalyst
|
||||||
var touchPoint = new PointF((float)tapPosition.Value.X, (float)tapPosition.Value.Y);
|
var touchPoint = new PointF((float)tapPosition.Value.X, (float)tapPosition.Value.Y);
|
||||||
_selectedNode = _nodes.FirstOrDefault(node => IsPointInsideNode(touchPoint, node));
|
_selectedNode = _nodes.FirstOrDefault(node => IsPointInsideNode(touchPoint, node));
|
||||||
|
|
||||||
// Ñáðîñ àêòèâíîñòè äëÿ âñåõ óçëîâ, êðîìå âûáðàííîãî
|
|
||||||
foreach (var node in _nodes)
|
foreach (var node in _nodes)
|
||||||
node.IsActive = node == _selectedNode;
|
node.IsActive = node == _selectedNode;
|
||||||
|
|
||||||
// Îáíîâëÿåì ýêðàí ïîñëå èçìåíåíèÿ ñîñòîÿíèÿ óçëîâ
|
|
||||||
canvasView.Invalidate();
|
canvasView.Invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
|
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_selectedNode == null) return;
|
if (_selectedNode == null) return;
|
||||||
|
|
||||||
if (e.StatusType == GestureStatus.Started)
|
if (e.StatusType == GestureStatus.Started)
|
||||||
{
|
{
|
||||||
// Ñîõðàíÿåì íà÷àëüíóþ ïîçèöèþ íîäû è ðàçìåð
|
|
||||||
_initialNodePosition = _selectedNode.Position;
|
_initialNodePosition = _selectedNode.Position;
|
||||||
_initialTouchPosition = new PointF((float)e.TotalX, (float)e.TotalY);
|
_initialTouchPosition = new PointF((float)e.TotalX, (float)e.TotalY);
|
||||||
_initialNodeSize = _selectedNode.Size; // Ñîõðàíÿåì íà÷àëüíûé ðàçìåð
|
_initialNodeSize = _selectedNode.Size;
|
||||||
|
|
||||||
// Ïðîâåðÿåì, íàõîäèìñÿ ëè ìû íà ðó÷êå èçìåíåíèÿ ðàçìåðà
|
|
||||||
_isResizing = IsOnRightResizeHandle(_selectedNode, _initialTouchPosition) ||
|
|
||||||
IsOnLeftResizeHandle(_selectedNode, _initialTouchPosition) ||
|
|
||||||
IsOnTopResizeHandle(_selectedNode, _initialTouchPosition) ||
|
|
||||||
IsOnBottomResizeHandle(_selectedNode, _initialTouchPosition);
|
|
||||||
|
|
||||||
|
_isResizing = IsOnResizeHandle(_selectedNode, _initialTouchPosition);
|
||||||
}
|
}
|
||||||
else if (e.StatusType == GestureStatus.Running)
|
else if (e.StatusType == GestureStatus.Running)
|
||||||
{
|
{
|
||||||
// Âû÷èñëÿåì ñìåùåíèå îò íà÷àëüíîé ïîçèöèè êàñàíèÿ
|
|
||||||
var deltaX = (float)e.TotalX - _initialTouchPosition.X;
|
var deltaX = (float)e.TotalX - _initialTouchPosition.X;
|
||||||
var deltaY = (float)e.TotalY - _initialTouchPosition.Y;
|
var deltaY = (float)e.TotalY - _initialTouchPosition.Y;
|
||||||
|
|
||||||
|
|
@ -172,7 +106,6 @@ namespace NotesDataAnalyst
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Ïåðåìåùåíèå
|
|
||||||
_selectedNode.Position = new PointF(
|
_selectedNode.Position = new PointF(
|
||||||
_initialNodePosition.X + deltaX,
|
_initialNodePosition.X + deltaX,
|
||||||
_initialNodePosition.Y + deltaY
|
_initialNodePosition.Y + deltaY
|
||||||
|
|
@ -187,86 +120,32 @@ namespace NotesDataAnalyst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Èçìåíåíèå ðàçìåðà óçëà
|
|
||||||
private void ResizeNode(GraphNode node, double deltaX, double deltaY)
|
private void ResizeNode(GraphNode node, double deltaX, double deltaY)
|
||||||
{
|
{
|
||||||
const float minSize = 50f; // Óáèðàåì "f" äëÿ double
|
const double minSize = 50.0;
|
||||||
|
|
||||||
// Óâåëè÷èâàåì èëè óìåíüøàåì ðàçìåð â çàâèñèìîñòè îò íàïðàâëåíèÿ
|
|
||||||
if (_isResizing)
|
if (_isResizing)
|
||||||
{
|
|
||||||
// Åñëè ìû òÿíåì ïðàâóþ "ðó÷êó", óâåëè÷èâàåì øèðèíó
|
|
||||||
if (IsOnRightResizeHandle(node, _initialTouchPosition))
|
|
||||||
{
|
{
|
||||||
_selectedNode.Size = new Size(
|
_selectedNode.Size = new Size(
|
||||||
Math.Max(minSize, node.Size.Width + deltaX), // double
|
Math.Max(minSize, _initialNodeSize.Width + deltaX),
|
||||||
_selectedNode.Size.Height // double
|
Math.Max(minSize, _initialNodeSize.Height + deltaY)
|
||||||
);
|
|
||||||
}
|
|
||||||
// Åñëè ìû òÿíåì ëåâóþ "ðó÷êó", óìåíüøàåì øèðèíó
|
|
||||||
else if (IsOnLeftResizeHandle(node, _initialTouchPosition))
|
|
||||||
{
|
|
||||||
_selectedNode.Size = new Size(
|
|
||||||
Math.Max(minSize, _selectedNode.Size.Width - deltaX), // double
|
|
||||||
_selectedNode.Size.Height // double
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ïåðåìåùàåì íîäó âëåâî, ÷òîáû ñîõðàíèòü åå ïîçèöèþ
|
|
||||||
_selectedNode.Position = new Point(_selectedNode.Position.X + deltaX, _selectedNode.Position.Y); // double
|
|
||||||
}
|
|
||||||
// Åñëè ìû òÿíåì âåðõíþþ "ðó÷êó", óìåíüøàåì âûñîòó
|
|
||||||
else if (IsOnTopResizeHandle(node, _initialTouchPosition))
|
|
||||||
{
|
|
||||||
_selectedNode.Size = new Size(
|
|
||||||
_selectedNode.Size.Width, // double
|
|
||||||
Math.Max(minSize, _selectedNode.Size.Height - deltaY) // double
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ïåðåìåùàåì íîäó ââåðõ, ÷òîáû ñîõðàíèòü åå ïîçèöèþ
|
|
||||||
_selectedNode.Position = new Point(_selectedNode.Position.X, _selectedNode.Position.Y + deltaY); // double
|
|
||||||
}
|
|
||||||
// Åñëè ìû òÿíåì íèæíþþ "ðó÷êó", óâåëè÷èâàåì âûñîòó
|
|
||||||
else if (IsOnBottomResizeHandle(node, _initialTouchPosition))
|
|
||||||
{
|
|
||||||
_selectedNode.Size = new Size(
|
|
||||||
_selectedNode.Size.Width, // double
|
|
||||||
Math.Max(minSize, _selectedNode.Size.Height + deltaY) // double
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsOnResizeHandle(GraphNode node, PointF point)
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private bool IsOnRightResizeHandle(GraphNode node, PointF point)
|
|
||||||
{
|
{
|
||||||
const float handleSize = 10;
|
const float handleSize = 20f;
|
||||||
return Math.Abs(point.X - (node.Position.X + node.Size.Width - 1)) <= handleSize;
|
|
||||||
|
var resizeHandleRect = new RectF(
|
||||||
|
(float)(node.Position.X + node.Size.Width - handleSize),
|
||||||
|
(float)(node.Position.Y + node.Size.Height - handleSize),
|
||||||
|
handleSize, handleSize
|
||||||
|
);
|
||||||
|
|
||||||
|
return resizeHandleRect.Contains(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsOnLeftResizeHandle(GraphNode node, PointF point)
|
|
||||||
{
|
|
||||||
const float handleSize = 10;
|
|
||||||
return Math.Abs(point.X - node.Position.X) <= handleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsOnTopResizeHandle(GraphNode node, PointF point)
|
|
||||||
{
|
|
||||||
const float handleSize = 10;
|
|
||||||
return Math.Abs(point.Y - node.Position.Y) <= handleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsOnBottomResizeHandle(GraphNode node, PointF point)
|
|
||||||
{
|
|
||||||
const float handleSize = 10;
|
|
||||||
return Math.Abs(point.Y - (node.Position.Y + node.Size.Height)) <= handleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Ìåòîä äëÿ ïðîâåðêè, íàõîäèòñÿ ëè òî÷êà âíóòðè óçëà
|
|
||||||
private bool IsPointInsideNode(PointF point, GraphNode node)
|
private bool IsPointInsideNode(PointF point, GraphNode node)
|
||||||
{
|
{
|
||||||
return point.X >= node.Position.X &&
|
return point.X >= node.Position.X &&
|
||||||
|
|
@ -274,42 +153,5 @@ namespace NotesDataAnalyst
|
||||||
point.Y >= node.Position.Y &&
|
point.Y >= node.Position.Y &&
|
||||||
point.Y <= node.Position.Y + node.Size.Height;
|
point.Y <= node.Position.Y + node.Size.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ïðîâåðêà, íàõîäèòñÿ ëè òî÷êà íà "ðó÷êå" èçìåíåíèÿ ðàçìåðà
|
|
||||||
private bool IsOnResizeHandle(GraphNode node, PointF point)
|
|
||||||
{
|
|
||||||
const float handleSize = 20f; // Ðàçìåð ðó÷êè èçìåíåíèÿ ðàçìåðà
|
|
||||||
|
|
||||||
// Îïðåäåëÿåì ïðÿìîóãîëüíèêè äëÿ êàæäîé ðó÷êè
|
|
||||||
var rightHandleRect = new RectF(
|
|
||||||
(float)(node.Position.X + node.Size.Width - handleSize),
|
|
||||||
(float)(node.Position.Y + node.Size.Height - handleSize),
|
|
||||||
handleSize, handleSize);
|
|
||||||
|
|
||||||
var leftHandleRect = new RectF(
|
|
||||||
(float)(node.Position.X),
|
|
||||||
(float)(node.Position.Y + node.Size.Height - handleSize),
|
|
||||||
handleSize, handleSize);
|
|
||||||
|
|
||||||
var topHandleRect = new RectF(
|
|
||||||
(float)(node.Position.X + (node.Size.Width / 2) - (handleSize / 2)),
|
|
||||||
(float)(node.Position.Y),
|
|
||||||
handleSize, handleSize);
|
|
||||||
|
|
||||||
var bottomHandleRect = new RectF(
|
|
||||||
(float)(node.Position.X + (node.Size.Width / 2) - (handleSize / 2)),
|
|
||||||
(float)(node.Position.Y + node.Size.Height - handleSize),
|
|
||||||
handleSize, handleSize);
|
|
||||||
|
|
||||||
// Ïðîâåðÿåì, íàõîäèòñÿ ëè êóðñîð íà îäíîé èç ðó÷åê
|
|
||||||
return rightHandleRect.Contains(point) ||
|
|
||||||
leftHandleRect.Contains(point) ||
|
|
||||||
topHandleRect.Contains(point) ||
|
|
||||||
bottomHandleRect.Contains(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui.Graphics;
|
using Microsoft.Maui.Graphics;
|
||||||
|
using Microsoft.Maui.Layouts;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace NotesDataAnalyst
|
namespace NotesDataAnalyst
|
||||||
|
|
@ -9,98 +10,120 @@ namespace NotesDataAnalyst
|
||||||
private const double InitialWidth = 150;
|
private const double InitialWidth = 150;
|
||||||
private const double InitialHeight = 100;
|
private const double InitialHeight = 100;
|
||||||
private double startX, startY;
|
private double startX, startY;
|
||||||
|
private bool isResizing;
|
||||||
|
|
||||||
public ResizableCanvasPage()
|
public ResizableCanvasPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ìåòîä äëÿ äîáàâëåíèÿ îáúåêòà íà õîëñò
|
|
||||||
private void AddResizableObject(double x, double y)
|
private void AddResizableObject(double x, double y)
|
||||||
{
|
{
|
||||||
// Ñîçäàíèå Frame äëÿ ãðàôè÷åñêîãî îáúåêòà
|
// Ñîçäàåì îñíîâíîé êîíòåéíåð (Frame) äëÿ îáúåêòà è ðó÷êè
|
||||||
var resizableFrame = new Frame
|
var resizableFrame = new Frame
|
||||||
{
|
{
|
||||||
BackgroundColor = Colors.LightBlue,
|
BackgroundColor = Colors.LightBlue,
|
||||||
BorderColor = Colors.DarkBlue,
|
BorderColor = Colors.DarkBlue,
|
||||||
CornerRadius = 8,
|
CornerRadius = 8,
|
||||||
WidthRequest = InitialWidth,
|
WidthRequest = InitialWidth,
|
||||||
HeightRequest = InitialHeight
|
HeightRequest = InitialHeight,
|
||||||
|
Padding = 0,
|
||||||
|
HasShadow = true
|
||||||
};
|
};
|
||||||
|
|
||||||
// Îáðàáîòêà ïåðåìåùåíèÿ îáúåêòà
|
var content = new Label
|
||||||
var panGesture = new PanGestureRecognizer();
|
{
|
||||||
panGesture.PanUpdated += (s, e) => OnDragPanUpdated(s, e, resizableFrame);
|
Text = "Resizable Object",
|
||||||
resizableFrame.GestureRecognizers.Add(panGesture);
|
HorizontalOptions = LayoutOptions.Center,
|
||||||
|
VerticalOptions = LayoutOptions.Center
|
||||||
|
};
|
||||||
|
|
||||||
// Ñîçäàíèå ðó÷êè äëÿ èçìåíåíèÿ ðàçìåðà
|
resizableFrame.Content = content;
|
||||||
|
|
||||||
|
// Ñîçäàåì ðó÷êó äëÿ èçìåíåíèÿ ðàçìåðà
|
||||||
var resizeHandle = new BoxView
|
var resizeHandle = new BoxView
|
||||||
{
|
{
|
||||||
BackgroundColor = Colors.Gray,
|
BackgroundColor = Colors.Gray,
|
||||||
WidthRequest = 20,
|
WidthRequest = 20,
|
||||||
HeightRequest = 20
|
HeightRequest = 20,
|
||||||
|
HorizontalOptions = LayoutOptions.End,
|
||||||
|
VerticalOptions = LayoutOptions.End
|
||||||
};
|
};
|
||||||
|
|
||||||
// Îáðàáîòêà èçìåíåíèÿ ðàçìåðà îáúåêòà
|
// Ñîçäàåì ñëîé AbsoluteLayout äëÿ ðó÷êè è ôðåéìà
|
||||||
|
var layout = new AbsoluteLayout();
|
||||||
|
AbsoluteLayout.SetLayoutBounds(resizableFrame, new Rect(0, 0, InitialWidth, InitialHeight));
|
||||||
|
layout.Children.Add(resizableFrame);
|
||||||
|
|
||||||
|
// Ïîçèöèîíèðóåì ðó÷êó
|
||||||
|
AbsoluteLayout.SetLayoutFlags(resizeHandle, AbsoluteLayoutFlags.PositionProportional);
|
||||||
|
AbsoluteLayout.SetLayoutBounds(resizeHandle, new Rect(1, 1, 20, 20));
|
||||||
|
layout.Children.Add(resizeHandle);
|
||||||
|
|
||||||
|
// Äîáàâëÿåì îáðàáîò÷èê ïåðåìåùåíèÿ
|
||||||
|
var panGesture = new PanGestureRecognizer();
|
||||||
|
panGesture.PanUpdated += (s, e) => OnDragPanUpdated(s, e, layout);
|
||||||
|
resizableFrame.GestureRecognizers.Add(panGesture);
|
||||||
|
|
||||||
|
// Äîáàâëÿåì îáðàáîò÷èê äëÿ èçìåíåíèÿ ðàçìåðà
|
||||||
var resizePanGesture = new PanGestureRecognizer();
|
var resizePanGesture = new PanGestureRecognizer();
|
||||||
resizePanGesture.PanUpdated += (s, e) => OnResizePanUpdated(s, e, resizableFrame, resizeHandle);
|
resizePanGesture.PanUpdated += (s, e) => OnResizePanUpdated(s, e, layout);
|
||||||
resizeHandle.GestureRecognizers.Add(resizePanGesture);
|
resizeHandle.GestureRecognizers.Add(resizePanGesture);
|
||||||
|
|
||||||
// Ïîçèöèîíèðîâàíèå îáúåêòà è ðó÷êè
|
// Óñòàíàâëèâàåì íà÷àëüíóþ ïîçèöèþ
|
||||||
AbsoluteLayout.SetLayoutBounds(resizableFrame, new Rect(x, y, InitialWidth, InitialHeight));
|
AbsoluteLayout.SetLayoutBounds(layout, new Rect(x, y, InitialWidth, InitialHeight));
|
||||||
CanvasLayout.Children.Add(resizableFrame);
|
CanvasLayout.Children.Add(layout);
|
||||||
CanvasLayout.Children.Add(resizeHandle);
|
|
||||||
|
|
||||||
UpdateResizeHandlePosition(resizableFrame, resizeHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Îáðàáîòêà ïåðåìåùåíèÿ îáúåêòà
|
// Ëîãèêà ïåðåìåùåíèÿ
|
||||||
private void OnDragPanUpdated(object sender, PanUpdatedEventArgs e, Frame frame)
|
private void OnDragPanUpdated(object sender, PanUpdatedEventArgs e, AbsoluteLayout layout)
|
||||||
{
|
{
|
||||||
|
if (isResizing) return;
|
||||||
|
|
||||||
if (e.StatusType == GestureStatus.Started)
|
if (e.StatusType == GestureStatus.Started)
|
||||||
{
|
{
|
||||||
startX = AbsoluteLayout.GetLayoutBounds(frame).X;
|
startX = AbsoluteLayout.GetLayoutBounds(layout).X;
|
||||||
startY = AbsoluteLayout.GetLayoutBounds(frame).Y;
|
startY = AbsoluteLayout.GetLayoutBounds(layout).Y;
|
||||||
}
|
}
|
||||||
else if (e.StatusType == GestureStatus.Running)
|
else if (e.StatusType == GestureStatus.Running)
|
||||||
{
|
{
|
||||||
double x = startX + e.TotalX;
|
double x = startX + e.TotalX;
|
||||||
double y = startY + e.TotalY;
|
double y = startY + e.TotalY;
|
||||||
AbsoluteLayout.SetLayoutBounds(frame, new Rect(x, y, frame.WidthRequest, frame.HeightRequest));
|
|
||||||
UpdateResizeHandlePosition(frame, CanvasLayout.Children[CanvasLayout.Children.IndexOf(frame) + 1] as BoxView);
|
// Îáíîâëåíèå UI ÷åðåç Dispatcher
|
||||||
|
Dispatcher.Dispatch(() =>
|
||||||
|
{
|
||||||
|
AbsoluteLayout.SetLayoutBounds(layout, new Rect(x, y, layout.WidthRequest, layout.HeightRequest));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Îáðàáîòêà èçìåíåíèÿ ðàçìåðà îáúåêòà
|
// Ëîãèêà èçìåíåíèÿ ðàçìåðà
|
||||||
private void OnResizePanUpdated(object sender, PanUpdatedEventArgs e, Frame frame, BoxView resizeHandle)
|
private void OnResizePanUpdated(object sender, PanUpdatedEventArgs e, AbsoluteLayout layout)
|
||||||
{
|
{
|
||||||
|
isResizing = true;
|
||||||
if (e.StatusType == GestureStatus.Started)
|
if (e.StatusType == GestureStatus.Started)
|
||||||
{
|
{
|
||||||
startX = frame.WidthRequest;
|
startX = layout.WidthRequest;
|
||||||
startY = frame.HeightRequest;
|
startY = layout.HeightRequest;
|
||||||
}
|
}
|
||||||
else if (e.StatusType == GestureStatus.Running)
|
else if (e.StatusType == GestureStatus.Running)
|
||||||
{
|
{
|
||||||
double newWidth = Math.Max(50, startX + e.TotalX);
|
double newWidth = Math.Max(50, startX + e.TotalX);
|
||||||
double newHeight = Math.Max(50, startY + e.TotalY);
|
double newHeight = Math.Max(50, startY + e.TotalY);
|
||||||
frame.WidthRequest = newWidth;
|
|
||||||
frame.HeightRequest = newHeight;
|
|
||||||
|
|
||||||
UpdateResizeHandlePosition(frame, resizeHandle);
|
Dispatcher.Dispatch(() =>
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ìåòîä äëÿ ôèêñàöèè ïîçèöèè ðó÷êè â óãëó îáúåêòà
|
|
||||||
private void UpdateResizeHandlePosition(Frame frame, BoxView resizeHandle)
|
|
||||||
{
|
{
|
||||||
var frameBounds = AbsoluteLayout.GetLayoutBounds(frame);
|
layout.WidthRequest = newWidth;
|
||||||
double x = frameBounds.X + frame.WidthRequest - resizeHandle.WidthRequest / 2;
|
layout.HeightRequest = newHeight;
|
||||||
double y = frameBounds.Y + frame.HeightRequest - resizeHandle.HeightRequest / 2;
|
});
|
||||||
|
}
|
||||||
AbsoluteLayout.SetLayoutBounds(resizeHandle, new Rect(x, y, resizeHandle.WidthRequest, resizeHandle.HeightRequest));
|
else if (e.StatusType == GestureStatus.Completed || e.StatusType == GestureStatus.Canceled)
|
||||||
|
{
|
||||||
|
isResizing = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Äîáàâëåíèå îáúåêòîâ íà õîëñò ïðè çàïóñêå
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue