Форум программистов, компьютерный форум, киберфорум
Hugonavy
Войти
Регистрация
Восстановить пароль
Рейтинг: 1.00. Голосов: 1.

WPF.MaterialDesign - Transitions и анимация элементов GUI

Запись от Hugonavy размещена 03.08.2021 в 13:25

Всем доброго дня!

Сегодня хочу описать довольно мощный функционал библиотеки MaterialDesign, позволяющий добавить динамики графическому интерфейсу приложения. И одним из весомых плюсов является относительная простота его внедрения и использования.

Transitions (или с англ. "переходы") позволяет анимировать элементы при их появлении и/или исчезновении. Т.о. мы можем анимировать переход между UC основного окна, или же в окне разместить контейнер, который будет подставлять туда, скажем, UC с графиками или изображениями, и, нажимая на навигационные кнопки, они буду красиво сменять друг друга. Можно анимировать появление элементов ListBox или различных элементов страницы при ее загрузке. Об этом и поговорим далее.

Не по теме:

Дальнейшее повествование рассчитано на то, что читатель имеет представление о MVVM в WPF



Первым делом, естественно, подключаем библиотеку в шапке нашего xaml строкой:
XML
1
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
Анимация UserControl

Начнем с анимации контролов. Основным элементом, который осуществляет эти манипуляции, является materialDesign:Transitioner. Это контейнер, в котором будут показываться страницы. Выглядит это примерно так:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
             <materialDesign:Transitioner SelectedIndex="{Binding SelectedIndex}" 
                                         AutoApplyTransitionOrigins="True">
                
                <materialDesign:TransitionerSlide Content="{Binding FirstControl}">
                    <materialDesign:TransitionerSlide.BackwardWipe>
                        <materialDesign:FadeWipe Duration="0:0:0.8" />
                    </materialDesign:TransitionerSlide.BackwardWipe>
                    <materialDesign:TransitionerSlide.ForwardWipe>
                        <materialDesign:FadeWipe Duration="0:0:0.8" />
                    </materialDesign:TransitionerSlide.ForwardWipe>
                </materialDesign:TransitionerSlide>
 
                <materialDesign:TransitionerSlide Content="{Binding SecondControl}">
                    <materialDesign:TransitionerSlide.BackwardWipe>
                        <materialDesign:FadeWipe Duration="0:0:0.8" />
                    </materialDesign:TransitionerSlide.BackwardWipe>
                    <materialDesign:TransitionerSlide.ForwardWipe>
                        <materialDesign:FadeWipe Duration="0:0:0.8" />
                    </materialDesign:TransitionerSlide.ForwardWipe>
                </materialDesign:TransitionerSlide>
 
                <materialDesign:TransitionerSlide Content="{Binding ThirdControl}">
                    <materialDesign:TransitionerSlide.BackwardWipe>
                        <materialDesign:FadeWipe Duration="0:0:0.8" />
                    </materialDesign:TransitionerSlide.BackwardWipe>
                    <materialDesign:TransitionerSlide.ForwardWipe>
                        <materialDesign:FadeWipe Duration="0:0:0.8" />
                    </materialDesign:TransitionerSlide.ForwardWipe>
                </materialDesign:TransitionerSlide>
            </materialDesign:Transitioner>
SelectedIndex отвечает за смену элементов контейнера, отсчитывается от 0. Т.о. при SelectedIndex = 1 будет показан SecondControl.

Очевидно, что элемент materialDesign:TransitionerSlide должен быть создан для каждого предполагаемого элемента.

У TransitionerSlide есть элементы шаблонов анимации (как я понял) BackwardWipe и ForwardWipe, отвечающие за анимацию перехода к элементу и от него, соответственно.

Далее приведу эти шаблоны анимации (пробую описать словами, но для понимания все-таки рекомендую опробовать в тестовом приложении):
1) FadeWipe - затухание. Элемент исчезает и появляется (изменяется прозрачность) с интенсивностью, задаваемой свойством Duration
2) CircleWipe - интересный эффект. В центре элемента появляется расширяющийся круг. Внутри круга будет следующий слайд, за границей круга - предшествующий. Когда круг займет весь экран, один слайд заменит другой.

Не по теме:

Со свойствами изменения скорости анимации я пока не разбирался


3) SlideWipe - также обладает свойством Duration (задает время анимации). Помимо этого есть свойство Direction (Down, Left, Right, Up), задающее направление смещения слайда. Текущий слайд сдвигается в сторону (в соответствии с Direction) и плавно исчезает, а сзади него плавно появляется следующий
4) SlideOutWipe - каких-то доп. свойств у этого типа тоже нет. Срабатывает довольно быстро, новый слайд выскакивает снизу и заменяет предыдущий

Однако у TransitionerSlide есть еще OpeningEffects (и множество других элементов, с которыми я пока не разбирался), который позволяет задать свою анимацию, например вот так:
XML
1
2
3
4
<materialDesign:TransitionerSlide.OpeningEffects>
    <materialDesign:TransitionEffect Kind="SlideInFromLeft" Duration="0:0:0.8" />
    <materialDesign:TransitionEffect Kind="SlideInFromBottom" Duration="0:0:0.8" OffsetTime="0:0:0.15" />
</materialDesign:TransitionerSlide.OpeningEffects>
Ну и простенькая VM:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class VM : OnPropertyChangedClass
    {
        public int SelectedIndex
        {
            get => _selectedIndex;
            set { _selectedIndex = value; OnPropertyChanged(); }
        }
        private int _selectedIndex;
 
        public UserControl FirstControl
        {
            get { return _firstControl; }
            set
            {
                _firstControl = value;
                OnPropertyChanged();
            }
        }
        private UserControl _firstControl;
        public UserControl SecondControl
        {
            get { return _secondControl; }
            set
            {
                _secondControl = value;
                OnPropertyChanged();
            }
        }
        private UserControl _secondControl;
        public UserControl ThirdControl
        {
            get { return _thirdControl; }
            set
            {
                _thirdControl = value;
                OnPropertyChanged();
            }
        }
        private UserControl _thirdControl;
 
        public VM()
        {
            ChangeList(0);
        }
 
        private void ChangeList(int Index)
        {
            switch (Index)
            {
                case 0:
                    FirstControl = new FirstUC();
                    break;
                case 1:
                    SecondControl = new SecondUC();
                    break;
                case 2:
                    ThirdControl = new ThirdUC();
                    break;
                default:
                    FirstControl = new FirstUC();
                    break;
            }
            SelectedIndex = Index;
        }
 
    }
Далее цепляем к команде метод ChangeList с нужным индексом и получаем красивую навигацию

Анимация элементов страницы

За анимацию элементов графического интерфейса отвечает materialDesign:TransitioningContent. Ниже простенький пример выдвижной панельки:
XML
1
2
3
4
5
6
7
8
9
10
        <materialDesign:TransitioningContent OpeningEffectsOffset="0:0:0"
                        OpeningEffect="{materialDesign:TransitionEffect SlideInFromLeft, Duration=0:0:1.0}">
            <materialDesign:Card Background="{StaticResource MaterialDesignCardBackground}"
                                 VerticalAlignment="Top"
                                 Margin="10" Height="235"
                                 materialDesign:ShadowAssist.ShadowDepth="Depth3">
 
                <TextBlock Text="Панелька" Margin="10" TextAlignment="Center"/>
            </materialDesign:Card>
        </materialDesign:TransitioningContent>
Панелька выдвигается при загрузке окна (или UC) слева, анимация длится 1 сек.

Элементов на странице может быть много и для того, чтобы при загрузке все это не начало двигаться, создавая хаос и безвкусицу, есть свойство OpeningEffectsOffset, отвечающее за задержку запуска анимации (в примере выше задана нулевая задержка). Таким образом можно организовать плавное появление элементов в нужной последовательности.

materialDesign:TransitionEffect имеет следующие варианты анимации (описывать не буду, все очевидно из названия):
- ExpandIn
- FadeIn
- SlideInFromBottom
- SlideInFromLeft
- SlideInFromRight
- SlideInFromTop

Анимация списочных элементов

Помимо всего вышесказанного, с помощью Transitions можно преобразить появление списков. Сама анимация задается аналогично, приведу лишь пример:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
            <ListBox ItemsSource="{Binding ListSource}" HorizontalContentAlignment="Stretch"
                     Margin="10 0 10 10">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <materialDesign:TransitioningContent 
                                    OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplierExtension 0:0:0.05}"
                                    Opacity="0"
                                    RunHint="Loaded">
                            <materialDesign:TransitioningContent.OpeningEffects>
                                <materialDesign:TransitionEffect Kind="SlideInFromRight" />
                                <materialDesign:TransitionEffect Kind="FadeIn" />
                            </materialDesign:TransitioningContent.OpeningEffects>
 
                            <materialDesign:ColorZone>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition/>
                                        <ColumnDefinition/>
                                        <ColumnDefinition/>
                                    </Grid.ColumnDefinitions>
 
                                    <TextBlock Text="{Binding Column0}" Margin="4" FontWeight="DemiBold"/>
                                    <Border Grid.Column="1" 
                                            BorderThickness="1 0 0 0" 
                                            BorderBrush="{DynamicResource MaterialDesignBodyLight}">
                                        <TextBlock Text="{Binding Column1}"
                                                   TextAlignment="Center"  Margin="4"/>
                                    </Border>
                                    <Border Grid.Column="2" 
                                            BorderThickness="1 0 0 0" 
                                            BorderBrush="{DynamicResource MaterialDesignBodyLight}">
                                        <TextBlock Text="{Binding Column2}"
                                                   TextAlignment="Center"  Margin="4"/>
                                    </Border>
                                    
                                </Grid>
                            </materialDesign:ColorZone>
                        </materialDesign:TransitioningContent>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
Благодаря свойству OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMulti plierExtension 0:0:0.05}" строки будут появляться с задержкой в пол секунды.

Еще один вариант из примера на GitHub.

Спасибо за внимание!
Размещено в Без категории
Показов 1196 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.