Постоянное вращение дуги окружности путем применения поворотов от 0 до 360 для имитации анимированного счетчика

У меня есть рисунок ниже, который представляет собой дугу окружности, и теперь я хотел бы применять повороты от 0 до 360 в цикле на неопределенный срок, чтобы имитировать анимированный спиннер. Что-то вроде здесь, вечно вращающейся дуги окружности.

<DrawingImage x:Key = "ico_spinnerDrawingImage">
  <DrawingImage.Drawing>
    <DrawingGroup ClipGeometry = "M0,0 V12 H12 V0 H0 Z">
      <DrawingGroup.Transform>
        <TranslateTransform X = "9.5367397534573684E-07" Y = "1.1465158453161615E-14" />
      </DrawingGroup.Transform>
      <GeometryDrawing Brush = "#FF00AA2B" Geometry = "F1 M12,12z M0,0z M12,12C12,10.4241 11.6896,8.86371 11.0866,7.4078 10.4835,5.95189 9.59958,4.62902 8.48528,3.51472 7.37098,2.40042 6.04811,1.5165 4.5922,0.913445 3.13629,0.310389 1.57586,-6.88831E-08 -9.53674E-07,0L0,3C1.1819,3 2.35222,3.23279 3.44415,3.68508 4.53608,4.13738 5.52823,4.80031 6.36396,5.63604 7.19969,6.47177 7.86262,7.46392 8.31492,8.55585 8.76721,9.64778 9,10.8181 9,12L12,12z" />
    </DrawingGroup>
  </DrawingImage.Drawing>
</DrawingImage>

Вышеупомянутое изображение рисунка заключено в словарь, который я импортирую в свое представление WPF, и я связываю его со свойством источника изображения WPF, делая это (я удалил не относящиеся к делу свойства):

    <Image Source = "{Binding Path=MySpinnerIcon}"/>

Теперь, как можно применить эту анимацию к рисунку, чтобы имитировать анимированный спиннер, постоянно вращающийся по кругу?

Вам нужно использовать RotateTransform, как показано в приведенном ниже ответе Клеменса.

BionicCode 17.11.2022 23:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
106
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете анимировать свойство Angle элемента RotateTransform, который используется в качестве RenderTransform элемента пользовательского интерфейса.

Сама анимация выполняется DoubleAnimation в StoryBoard, которая, например, может быть запущена EventTrigger в событии Loaded элемента пользовательского интерфейса.

В приведенном ниже примере вместо изображения используется простой элемент Path. Он рисует эллиптическую дугу шириной 20 единиц с закругленными концами и радиусом 90 в поле 200x200.

<Path Data = "M100,10 A90,90 0 0 1 190,100"
      Width = "200" Height = "200"
      Stroke = "Turquoise" StrokeThickness = "20"
      StrokeStartLineCap = "Round" StrokeEndLineCap = "Round"
      RenderTransformOrigin = "0.5,0.5">
    <Path.RenderTransform>
        <RotateTransform />
    </Path.RenderTransform>
    <Path.Triggers>
        <EventTrigger RoutedEvent = "Loaded">
            <BeginStoryboard>
                <Storyboard TargetProperty = "RenderTransform.Angle">
                    <DoubleAnimation By = "360" Duration = "0:0:1"
                                     RepeatBehavior = "Forever"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Path.Triggers>
</Path>

Пример:

<StackPanel>
    <FrameworkElement.Resources>
        <Pen x:Key = "сircle" Brush = "LightGray" Thickness = "5"/>
        <Pen x:Key = "arc" Brush = "LightGreen" Thickness = "5" EndLineCap = "Round" StartLineCap = "Round"/>
        <DrawingImage x:Key = "ico_spinnerDrawingImage">
            <DrawingImage.Drawing>
                <DrawingGroup>
                    <DrawingGroup.Transform>
                        <RotateTransform Angle = "0"/>
                    </DrawingGroup.Transform>
                    <GeometryDrawing Pen = "{StaticResource сircle}">
                        <GeometryDrawing.Geometry>
                            <EllipseGeometry Center = "0,0" RadiusX = "10" RadiusY = "10"/>
                        </GeometryDrawing.Geometry>
                    </GeometryDrawing>
                    <GeometryDrawing Geometry = "M10,0 A10,10 90 0 1 0,10"
                                        Pen = "{StaticResource arc}"/>
                </DrawingGroup>
            </DrawingImage.Drawing>
        </DrawingImage>
    </FrameworkElement.Resources>

    <Image Source = "{DynamicResource ico_spinnerDrawingImage}" Width = "100">
        <Image.Triggers>
            <EventTrigger RoutedEvent = "Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation From = "0" To = "360" Duration = "0:0:1"
                                            Storyboard.TargetProperty = "Source.Drawing.Transform.Angle"
                                            RepeatBehavior = "Forever"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Image.Triggers>
    </Image>
</StackPanel>

P.S. С таким пером, на мой взгляд, анимация будет смотреться лучше:

    <Pen x:Key = "arc" Thickness = "5" EndLineCap = "Round" StartLineCap = "Round">
        <Pen.Brush>
            <LinearGradientBrush EndPoint = "0.5,1" StartPoint = "0.5,0">
                <GradientStop Color = "Transparent"/>
                <GradientStop Color = "LawnGreen" Offset = "1"/>
            </LinearGradientBrush>
        </Pen.Brush>
    </Pen>

в моем случае нет серого круга, только дуга. Это был пример.

Willy 21.11.2022 16:50

@Rodri, DrawingImage создает рамку на основе фактической формы. Если убрать круг, изменится рамка и будет дергаться изображение. Если круг не нужен, то нужно задать ему прозрачную кисть: <Pen x:Key = "сircle" Brush = "Transparent" Thickness = "5"/>

EldHasp 21.11.2022 16:59

Мой Drawing.Image полностью отличается от вашего. Как я могу адаптировать свой к вашему? Мне нужно, чтобы все вещи в моем Drawing.Image соблюдались, я имею в виду значения для ClipGeometry, TranslateTransform и GeometryDrawing.

Willy 21.11.2022 17:14

@Rodri На самом деле тебе ничего этого не нужно. Достаточно Path с простой PathGeometry.

Clemens 21.11.2022 17:29

@Rodri, ваша геометрия и получение из нее изображения не будут работать правильно. Они создают обрезанную рамку неполного круга. Из-за этого при его вращении изображение будет дергаться, менять размер и масштаб. Как бы там ни было, нужно создать кадр, достаточный для полного круга. Для этого в DrawingGroup нужно разместить либо полный круг, как в моем примере, либо описывающий квадрат. Или нужно создать не DrawingImage, а Path, как в примере Клемента.

EldHasp 21.11.2022 17:38

Вы можете попробовать использовать фоновых рабочих.

В вашем xaml:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width = "*"/>
    </Grid.ColumnDefinitions>
    <ed:Arc Grid.Column = "0" x:Name = "Arc1" ArcThickness = "5" Height = "32" Width = "32" StartAngle = "0" EndAngle = "360" Stretch = "None" Fill = "Gray"/>
    <ed:Arc Grid.Column = "0" x:Name = "Arc2" ArcThickness = "5" Height = "32" Width = "32" StartAngle = "0" EndAngle = "45"  Stretch = "None" Fill = "DeepSkyBlue"/>
</Grid>

Цвета и размеры могут быть изменены по вашему желанию.

Добавьте Microsoft.Expression.Drawing DLL в свой проект.

В вашем xaml.cs:

Добавлять

using System.Drawing;
using System.Threading;
using System.Threading.Tasks;

Объявите глобальную переменную bool runProcess = true;

Затем добавьте событие, которое заставит ваш счетчик начать движение.

private void EventName (object sender, RoutedEventArgs e)
    {
    runProcess = true;
    BackgroundWorker worker = new BackgroundWorker();
    worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
    worker.WorkerReportsProgress = true;
    worker.DoWork += Worker_DoWork;
    worker.ProgressChanged += Worker_ProgressChanged;
    worker.RunWorkerAsync();
    //Function you want to call while the spinner rotates
    }

Добавьте следующие две функции, чтобы заставить счетчик двигаться

private void Worker_DoWork (object sender, DoWorkEventArgs e)
    {
    BackgroundWorker worker = sender as BackgroundWorker;
    while ( runProcess )
        {
        Thread.Sleep(50);    //Any value <60 will give you a smooth movement
        worker.ReportProgress(0 /*Dummy value*/);
        }
    }
private void Worker_ProgressChanged (object sender, ProgressChangedEventArgs e)
    {
    Arc2.StartAngle += 10;    //Any value can be chosen for this
    Arc2.EndAngle += 10;      //Just keep the same value for both
    }

Добавьте эту функцию, чтобы делать все, что нужно, когда счетчик останавливается.

private void Worker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
    {
    //Whatever you want to do after the spinner stops
    }

Затем добавьте функцию, которую вы хотите запускать, пока ваш счетчик движется.

ReturnType FunctionName(InputParameters)
    {
    //Whatever your function is supposed to do
    runProcess = false;
    }

Thread.Sleep в BackgroundWorker.DoWork. Кажется, вы заново изобрели таймер. Также обратите внимание, что BackgroundWorker устарел уже десять лет. Кроме того, вы, безусловно, будете использовать анимацию на основе таймера только тогда, когда встроенная анимация не будет работать для вашего конкретного сценария. Это определенно не тот случай здесь.

Clemens 18.11.2022 10:02

Я понимаю. Я новичок в программировании, поэтому не знал, что это устарело. То, что я использовал здесь, было принято на работе, поэтому я разместил это здесь. Не могли бы вы сказать мне, почему это было прекращено?

New Guy 18.11.2022 13:27

Другие вопросы по теме