Ответ 1
Я написал какой-то код, делающий что-то близкое к тому, что вы описали.
Я не уверен, чтобы понять, как вы хотите, чтобы круг появился, поэтому я просто позволяю его части всегда видеть. И я не получил часть мобильного мобильного кольца.
Создание и размещение окна
XAML очень прост, ему просто нужна сетка для размещения фрагментов кругов, а также некоторые атрибуты для удаления окон и значков на панели задач:
<Window x:Class="circle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Circle"
Width="250"
Height="250"
AllowsTransparency="True"
Background="Transparent"
MouseDown="WindowClicked"
ShowInTaskbar="False"
WindowStyle="None">
<Grid Name="Container"/>
</Window>
Чтобы поместить окно в нижнем правом углу, вы можете использовать SystemParameters.WorkArea в конструкторе:
public MainWindow()
{
InitializeComponent();
var desktopDim = SystemParameters.WorkArea;
Left = desktopDim.Right - Width;
Top = desktopDim.Bottom - Height;
}
Создание формы
Я создаю круг как кучу круговых фигур, которые я генерирую из кода:
private Path CreateCirclePart()
{
var circle = new CombinedGeometry
{
GeometryCombineMode = GeometryCombineMode.Exclude,
Geometry1 = new EllipseGeometry { Center = _center, RadiusX = _r2, RadiusY = _r2 },
Geometry2 = new EllipseGeometry { Center = _center, RadiusX = _r1, RadiusY = _r1 }
};
var sideLength = _r2 / Math.Cos((Math.PI/180) * (ItemAngle / 2.0));
var x = _center.X - Math.Abs(sideLength * Math.Cos(ItemAngle * Math.PI / 180));
var y = _center.Y - Math.Abs(sideLength * Math.Sin(ItemAngle * Math.PI / 180));
var triangle = new PathGeometry(
new PathFigureCollection(new List<PathFigure>{
new PathFigure(
_center,
new List<PathSegment>
{
new LineSegment(new Point(_center.X - Math.Abs(sideLength),_center.Y), true),
new LineSegment(new Point(x,y), true)
},
true)
}));
var path = new Path
{
Fill = new SolidColorBrush(Colors.Cyan),
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 1,
RenderTransformOrigin = new Point(1, 1),
RenderTransform = new RotateTransform(0),
Data = new CombinedGeometry
{
GeometryCombineMode = GeometryCombineMode.Intersect,
Geometry1 = circle,
Geometry2 = triangle
}
};
return path;
}
Первый шаг - построить два концентрических круга и объединить их в CombinedGeometry с CombineMode, установленным для исключения. Затем я создаю треугольник, достаточно высокий, чтобы содержать участок кольца, который я хочу, и я сохраняю пересечение этих фигур.
Увидев это со вторым параметром CombineMode, установленным в xor, можно уточнить:
Построение круга
В приведенном выше коде используются некоторые поля экземпляров, которые делают его общим: вы можете изменить количество частей в круге или их радиус; он всегда будет заполнять угол.
Затем я заполняю список с нужным количеством фигур и добавляю их в сетку:
private const double MenuWidth = 80;
private const int ItemCount = 6;
private const double AnimationDelayInSeconds = 0.3;
private readonly Point _center;
private readonly double _r1, _r2;
private const double ItemSpacingAngle = 2;
private const double ItemAngle = (90.0 - (ItemCount - 1) * ItemSpacingAngle) / ItemCount;
private readonly List<Path> _parts = new List<Path>();
private bool _isOpen;
public MainWindow()
{
InitializeComponent();
// window in the lower right desktop corner
var desktopDim = SystemParameters.WorkArea;
Left = desktopDim.Right - Width;
Top = desktopDim.Bottom - Height;
_center = new Point(Width, Height);
_r2 = Width;
_r1 = _r2 - MenuWidth;
Loaded += (s, e) => CreateMenu();
}
private void CreateMenu()
{
for (var i = 0; i < ItemCount; ++i)
{
var part = CreateCirclePart();
_parts.Add(part);
Container.Children.Add(part);
}
}
ItemSpacingAngle определяет пробел между двумя последовательными фрагментами.
Анимация круга
Последний шаг - развернуть круг. Использование rotateAnimation по пути rendertransform облегчает задачу. Помните эту часть функции CreateCirclePart:
RenderTransformOrigin = new Point(1, 1),
RenderTransform = new RotateTransform(0),
RenderTransform сообщает, что анимация, которую мы хотим выполнить, - это вращение, а RenderTransformOrigin задает начало вращения в правом нижнем углу формы (единица процента). Теперь мы можем анимировать его при событии click:
private void WindowClicked(object sender, MouseButtonEventArgs e)
{
for (var i = 0; i < ItemCount; ++i)
{
if (!_isOpen)
UnfoldPart(_parts[i], i);
else
FoldPart(_parts[i], i);
}
_isOpen = !_isOpen;
}
private void UnfoldPart(Path part, int pos)
{
var newAngle = pos * (ItemAngle + ItemSpacingAngle);
var rotateAnimation = new DoubleAnimation(newAngle, TimeSpan.FromSeconds(AnimationDelayInSeconds));
var tranform = (RotateTransform)part.RenderTransform;
tranform.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);
}
private void FoldPart(Path part, int pos)
{
var rotateAnimation = new DoubleAnimation(0, TimeSpan.FromSeconds(AnimationDelayInSeconds));
var tranform = (RotateTransform)part.RenderTransform;
tranform.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);
}