Сворачиваемый заголовок страницы UWP

Я пытаюсь реализовать складной заголовок страницы. Основная идея заключается в том, что я должен изменить высоту заголовка страницы (минимальная высота 60 и максимальная 160) в зависимости от изменений в файле scrollviewer.

Вот результат, которого я хочу добиться.

Исходное состояние заголовка страницы

Основной макет

Заголовок страницы при прокрутке вниз

Основной макет при прокрутке вниз

Мой код XAML:

    <controls:CollapsablePageHeader>
        <controls:CollapsablePageHeader>
            <Grid x:Name="CollapsablePageHeaderGrid" MinHeight="150" Background="{StaticResource ApplicationAccentBackgroundColorBrush}">
                <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="25 905" HorizontalAlignment="Center" FontSize="50" Foreground="{StaticResource ApplicationAlternativeAccentColorBrush}"/>
                        <controls:TengeSignControl FontSize="50" Foreground="{StaticResource ApplicationAlternativeAccentColorBrush}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="/Assets/CreditCard.png" Height="20" Width="20" Margin="0,5,5,0"/>
                        <TextBlock Text="Bank of Arkham City" FontSize="{StaticResource BigTextSize}" Foreground="{StaticResource ApplicationAlternativeAccentColorBrush}"/>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </controls:CollapsablePageHeader>
    </controls:CollapsablePageHeader>
    <ScrollViewer x:Name="MainScrollViewer" Grid.Row="1" IsTabStop="False" ScrollViewer.HorizontalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <!--Layout for user favorite payment templates-->
            <toolkitControls:DropShadowPanel Style="{StaticResource DefaultCardDropShadowEffect}">
                <Grid Style="{StaticResource CardConontrolElement}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TextBlock x:Uid="Favorites" Style="{StaticResource SectionHeaderTextBlock}" HorizontalAlignment="Left" />
                    <GridView x:Name="UserTemplatesSelector" Grid.Row="1" ItemsSource="{Binding PaymentTemplates}" ItemTemplate="{StaticResource UserTemplatesDataTemplate}" Margin="-10,0,-10,0" Padding="10,0,0,0" Style="{StaticResource DefaultHorizontalGridView}" ItemContainerStyle="{StaticResource DefaultHorizontalGridViewItemContainer}">
                        <GridView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal"/>
                            </ItemsPanelTemplate>
                        </GridView.ItemsPanel>
                    </GridView>
                </Grid>
            </toolkitControls:DropShadowPanel>
            <!-- Layout for last operations -->
            <toolkitControls:DropShadowPanel Grid.Row="1" Margin="0,20,0,0" Style="{StaticResource DefaultCardDropShadowEffect}">
                <Grid Style="{StaticResource CardConontrolElement}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TextBlock x:Uid="LastOperations" Style="{StaticResource SectionHeaderTextBlock}"/>
                    <ListView x:Name="LastOperationsListView" Grid.Row="1" ItemsSource="{Binding LastTransactions}" ItemTemplate="{StaticResource LastOperationsDataTemplate}" Margin="0,10,0,0" ItemContainerStyle="{StaticResource DefaultListViewItemContainer}"/>
                    <Button x:Name="ShowMoreOperationsButton" Content="Показать всё" Grid.Row="2" Style="{StaticResource TiltableAccentButton}"/>
                </Grid>
            </toolkitControls:DropShadowPanel>
            <!-- Layour for bound cards -->
            <toolkitControls:DropShadowPanel Grid.Row="2" Margin="0,20" Style="{StaticResource DefaultCardDropShadowEffect}">
                <Grid Style="{StaticResource CardConontrolElement}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TextBlock x:Uid="LastOperations" Style="{StaticResource SectionHeaderTextBlock}" Typography.Capitals="AllSmallCaps"/>
                    <ListView x:Name="BoundCardListView" Grid.Row="1" ItemsSource="{Binding BoundCards}" ItemTemplate="{StaticResource BoundCardsDataTemplate}" Margin="0,10,0,0" ItemContainerStyle="{StaticResource DefaultListViewItemContainer}"/>
                    <Button x:Name="ShowMoreCardsButton" Content="Показать всё" Grid.Row="2" Style="{StaticResource TiltableAccentButton}"/>
                </Grid>
            </toolkitControls:DropShadowPanel>
        </Grid>
    </ScrollViewer>`

Я попытался реализовать это с помощью Compositor.CreateExpressionAnimation, но это не сработало. Может кто-нибудь, пожалуйста, скажите мне, как это сделать?

ОБНОВЛЕНИЕ:

Выдает исключение при попытке анимировать значение Scale.X или Scale.Y, но я не могу понять, почему. Другие визуальные элементы отлично работают с масштабной анимацией.

        ExpressionNode headerTranslationAnimation = EF.Conditional(progressNode < 1, 0, -scrollingProperties.Translation.Y - clampSizeNode);
        headerVisual.StartAnimation("Offset.Y", headerTranslationAnimation);

        ExpressionNode headerScaleAnimation = EF.Lerp(1, 1.25f, EF.Clamp(scrollingProperties.Translation.Y / 50, 0, 1));
        headerVisual.StartAnimation("Scale.X", headerScaleAnimation);
        headerVisual.StartAnimation("Scale.Y", headerScaleAnimation);

Исключение в headerVisual.StartAnimation:

System.ArgumentException: 'The parameter is incorrect.The animation failed to connect.'

Обновлен xaml:

 <Grid x:Name="LayoutRoot" Style="{StaticResource DefaultLayoutRootStyle}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <ScrollViewer x:Name="MainScrollViewer" IsTabStop="False" ScrollViewer.HorizontalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <Grid x:Name="CollapsiblePageHeader" Height="150" VerticalAlignment="Top">
                <ScrollViewer>
                    <Grid>
                        <Rectangle Height="300" HorizontalAlignment="Left" VerticalAlignment="Top">
                            <Rectangle.Fill>
                                <ImageBrush ImageSource="ms-appx:///Assets/Samples/SampleParallaxImage.jpg"/>
                            </Rectangle.Fill>
                        </Rectangle>
                        <StackPanel>
                            <StackPanel x:Name="TitleContainer" VerticalAlignment="Top" HorizontalAlignment="Center" Orientation="Horizontal">
                                <TextBlock x:Name="TitleText" Text="25 905" FontSize="50" Foreground="{StaticResource ApplicationAlternativeAccentColorBrush}"/>
                                <controls:TengeSignControl x:Name="TitleImage" FontSize="50" Foreground="{StaticResource ApplicationAlternativeAccentColorBrush}"/>
                            </StackPanel>
                            <StackPanel x:Name="SubtitleContainer" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="1" Orientation="Horizontal">
                                <Image x:Name="SubtitleImage" Source="/Assets/CreditCard.png" Height="20" Width="20" Margin="0,5,5,0"/>
                                <TextBlock x:Name="SubtitleText" Text="Bank of Arkham City" FontSize="{StaticResource BigTextSize}" Foreground="{StaticResource ApplicationAlternativeAccentColorBrush}"/>
                            </StackPanel>
                        </StackPanel>
                    </Grid>
                </ScrollViewer>
            </Grid>

            <Grid Grid.Row="1">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <!--Layout for user favorite payment templates-->
                <toolkitControls:DropShadowPanel Grid.Row="1" Style="{StaticResource DefaultCardDropShadowEffect}">
                    <Grid Style="{StaticResource CardConontrolElement}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <TextBlock x:Uid="Favorites" Style="{StaticResource SectionHeaderTextBlock}" HorizontalAlignment="Left" />
                        <GridView x:Name="UserTemplatesSelector" Grid.Row="1" ItemsSource="{Binding PaymentTemplates}" ScrollViewer.HorizontalScrollMode="Enabled" ScrollViewer.VerticalScrollMode="Disabled" ItemTemplate="{StaticResource UserTemplatesDataTemplate}" Margin="-10,0,-10,0" Padding="10,0,0,0" Style="{StaticResource DefaultGridView}" ItemContainerStyle="{StaticResource DefaultGridViewItemContainer}"/>
                    </Grid>
                </toolkitControls:DropShadowPanel>

                <!-- Layout for last operations -->
                <toolkitControls:DropShadowPanel Grid.Row="2" Margin="0,20,0,0" Style="{StaticResource DefaultCardDropShadowEffect}">
                    <Grid Style="{StaticResource CardConontrolElement}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <TextBlock x:Uid="LastOperations" Style="{StaticResource SectionHeaderTextBlock}"/>
                        <ListView x:Name="LastOperationsListView" Grid.Row="1"  ScrollViewer.VerticalScrollMode="Disabled"  ItemsSource="{Binding LastTransactions}" ItemTemplate="{StaticResource LastOperationsDataTemplate}" Margin="0,10,0,0" ItemContainerStyle="{StaticResource DefaultListViewItemContainer}"/>
                        <Button x:Name="ShowMoreOperationsButton" Content="Показать всё" Grid.Row="2" Style="{StaticResource TiltableAccentButton}"/>
                    </Grid>
                </toolkitControls:DropShadowPanel>

                <!-- Layour for bound cards -->
                <toolkitControls:DropShadowPanel Grid.Row="3" Margin="0,20" Style="{StaticResource DefaultCardDropShadowEffect}">
                    <Grid Style="{StaticResource CardConontrolElement}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <TextBlock Text="Привязанные карты" Style="{StaticResource SectionHeaderTextBlock}" Typography.Capitals="AllSmallCaps"/>
                        <ListView x:Name="BoundCardListView" Grid.Row="1" ScrollViewer.VerticalScrollMode="Disabled" ItemsSource="{Binding BoundCards}" ItemTemplate="{StaticResource BoundCardsDataTemplate}" Margin="0,10,0,0" ItemContainerStyle="{StaticResource DefaultListViewItemContainer}"/>
                        <Button x:Name="ShowMoreCardsButton" Content="Показать всё" Grid.Row="2" Style="{StaticResource TiltableAccentButton}"/>
                    </Grid>
                </toolkitControls:DropShadowPanel>
            </Grid>
        </Grid>
    </ScrollViewer>

    <CommandBar x:Name="PaymentOperations" Grid.Row="1">
        <AppBarButton x:Name="VendorPayment" Label="Оплата поставщиков" Icon="Shop" Click="MerchantPayment_Click"/>
        <AppBarButton x:Name="p2pPayment" Label="P2P оплата" Icon="Remote" Click="PersonToPersonPayment_Click"/>
        <AppBarButton x:Name="w2wPayment" Label="Перевод с кошелька на кошелек" Icon="Manage" Click="WalletToWalletPayment_Click"/>
    </CommandBar>
</Grid>

Полный xaml.cs:

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        // Get the PropertySet that contains the scroll values from MyScrollViewer
        _scrollerPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(MainScrollViewer);
        _compositor = _scrollerPropertySet.Compositor;

        // Create a PropertySet that has values to be referenced in the ExpressionAnimations below
        _props = _compositor.CreatePropertySet();
        _props.InsertScalar("progress", 0);
        _props.InsertScalar("clampSize", 150);
        _props.InsertScalar("scaleFactor", 0.7f);

        // Get references to our property sets for use with ExpressionNodes
        var scrollingProperties = _scrollerPropertySet.GetSpecializedReference<ManipulationPropertySetReferenceNode>();
        var props = _props.GetReference();
        var progressNode = props.GetScalarProperty("progress");
        var clampSizeNode = props.GetScalarProperty("clampSize");
        var scaleFactorNode = props.GetScalarProperty("scaleFactor");

        // Create and start an ExpressionAnimation to track scroll progress over the desired distance
        ExpressionNode progressAnimation = EF.Clamp(-scrollingProperties.Translation.Y / clampSizeNode, 0, 1);
        _props.StartAnimation("progress", progressAnimation);

        // Get the backing visual for the header so that its properties can be animated
        Visual headerVisual = ElementCompositionPreview.GetElementVisual(CollapsiblePageHeader);

        // Create and start an ExpressionAnimation to clamp the header's offset to keep it onscreen
        ExpressionNode headerTranslationAnimation = EF.Conditional(progressNode < 1, 0, -scrollingProperties.Translation.Y - clampSizeNode);
        // Works fine
        headerVisual.StartAnimation("Offset.Y", headerTranslationAnimation);

        ExpressionNode headerScaleAnimation = EF.Lerp(1, 1.25f, EF.Clamp(scrollingProperties.Translation.Y / 50, 0, 1));
        // Exception here
        headerVisual.StartAnimation("Scale.X", headerScaleAnimation);
        headerVisual.StartAnimation("Scale.Y", headerScaleAnimation);


        //Set the header's CenterPoint to ensure the overpan scale looks as desired
        headerVisual.CenterPoint = new Vector3((float)(CollapsiblePageHeader.ActualWidth / 2), (float)CollapsiblePageHeader.ActualHeight, 0);

        // Create and start an ExpressionAnimation to scale the profile image with scroll position
        ExpressionNode scaleAnimation = EF.Lerp(1, scaleFactorNode, progressNode);

        // Get backing visuals for the text blocks so that their properties can be animated
        Visual titleVisual = ElementCompositionPreview.GetElementVisual(TitleText);
        Visual titleImageVisual = ElementCompositionPreview.GetElementVisual(TitleImage);
        Visual subtitleVisual = ElementCompositionPreview.GetElementVisual(SubtitleText);
        Visual subtitleImageVisual = ElementCompositionPreview.GetElementVisual(SubtitleImage);

        // Create an ExpressionAnimation that moves between 1 and 0 with scroll progress, to be used for text block opacity
        ExpressionNode textOpacityAnimation = EF.Clamp(1 - (progressNode * 2), 0, 1);

        // Start opacity and scale animations on the text block visuals
        titleVisual.StartAnimation("Scale.X", scaleAnimation);
        titleVisual.StartAnimation("Scale.Y", scaleAnimation);

        titleImageVisual.StartAnimation("Scale.X", scaleAnimation);
        titleImageVisual.StartAnimation("Scale.Y", scaleAnimation);

        subtitleVisual.StartAnimation("Opacity", textOpacityAnimation);
        subtitleVisual.StartAnimation("Scale.X", scaleAnimation);
        subtitleVisual.StartAnimation("Scale.Y", scaleAnimation);

        subtitleImageVisual.StartAnimation("Opacity", textOpacityAnimation);
        subtitleImageVisual.StartAnimation("Scale.X", scaleAnimation);
        subtitleImageVisual.StartAnimation("Scale.Y", scaleAnimation);

        // Get the backing visuals for the text and button containers so that their properites can be animated
        Visual subtitleContainerVisual = ElementCompositionPreview.GetElementVisual(SubtitleContainer);

        // When the header stops scrolling it is 150 pixels offscreen.  We want the text header to end up with 50 pixels of its content
        // offscreen which means it needs to go from offset 0 to 100 as we traverse through the scrollable region
        ExpressionNode contentOffsetAnimation = progressNode * 100;

        subtitleContainerVisual.StartAnimation("Offset.Y", contentOffsetAnimation);
    }

person Konstantin Chsherbakov    schedule 27.06.2017    source источник
comment
Проверяли ли вы UWPCommunityToolkit? Помнится, у них было что-то похожее в управлении. Существует пример приложения, которое вы можете быстро просмотреть и найти.   -  person Andrei Ashikhmin    schedule 28.06.2017
comment
Да. В наборе инструментов представлены так называемые ScrollHeader. Но я хочу немного другого. Более того, я еще плохо разбираюсь в анимации, поэтому не могу написать ее самостоятельно.   -  person Konstantin Chsherbakov    schedule 28.06.2017
comment
Мой плохой, я думал о другом наборе инструментов. WindowsUIDevLabs, в разделе динамического взаимодействия с человеком есть заголовок Shy. Я считаю, что это похоже на то, чего вы хотите достичь.   -  person Andrei Ashikhmin    schedule 28.06.2017
comment
Спасибо вам большое за вашу подсказку! Этот инструментарий чрезвычайно полезен. Я нашел две возможные реализации: Shy Header и прокрутка z-Index. Спасибо еще раз!   -  person Konstantin Chsherbakov    schedule 28.06.2017
comment
Рад, что это помогло. Имейте в виду, что этот репозиторий несколько передовой, то есть он существует для демонстрации новейших возможностей UWP, и большинство примеров работают только начиная с определенной версии SDK.   -  person Andrei Ashikhmin    schedule 28.06.2017
comment
Ваш headerScaleAnimation - это Vector3, поэтому он должен быть Scale, а не Scale.X или Scale.Y.   -  person Justin XL    schedule 29.06.2017
comment
@JustinXL Я изменил свойство на Scale, но результат тот же.   -  person Konstantin Chsherbakov    schedule 29.06.2017


Ответы (1)


Это можно легко сделать без набора инструментов сообщества, если ваша минимальная целевая версия — Anniversary Update. Учитывая, что вы это делаете, давайте проведем вас через решение.

  1. Вам нужно обратиться к репозиторию GitHub WindowsDevLabs. Вы можете найти его здесь.
  2. Теперь, когда вы загрузили репозиторий, добавьте проект Expression Builder в свое решение, и все. Готово.
  3. Теперь, для последней части, просто в загруженном репозитории в разделе примеров найдите "Уменьшение заголовка" page и скопируйте и вставьте код из codeBehind и внесите необходимые изменения в свой пользовательский интерфейс и код, ссылаясь на Desinger. и Code Behind на странице «Уменьшение заголовка» загруженного репозитория.

Обратите внимание: вы можете увидеть активное приложение в магазине для того же репозитория в магазине по ссылке: Приложение пользовательского интерфейса Windows Dev Labs

person iam.Carrot    schedule 28.06.2017
comment
Такое сжатие должно поддерживаться и в 10586. - person Justin XL; 28.06.2017
comment
Да, сжатие будет поддерживаться, но размытие фона прямоугольника произойдет только при обновлении и позже. - person iam.Carrot; 28.06.2017
comment
На самом деле я думаю, что это также поддерживается в 10586. :) Но это не должно иметь большого значения, я думаю, все еще правильный ответ. - person Justin XL; 28.06.2017
comment
нет, это не так. Как только вы попытаетесь создать экземпляр GaussianCanvas и запустить программу, она выйдет из строя, говоря, что ваша минимальная целевая версия не установлена ​​​​на юбилейную версию. - person iam.Carrot; 28.06.2017
comment
О каком GaussianCanvas вы говорите? Этот эффект размытия определенно поддерживается в 10586. - person Justin XL; 28.06.2017
comment
Возможно тогда. Когда я пытался получить размытые эффекты в своем приложении (в ноябре 2016 года), я столкнулся с этой проблемой, и мне пришлось изменить минимальную поддерживаемую версию на Anniversary, чтобы исправить это. Возможно, они что-то изменили, Microsoft, как известно, так делает. - person iam.Carrot; 28.06.2017
comment
@AdityaSharma, не могли бы вы помочь мне понять ошибку в коде, пожалуйста? Я обновил свой вопрос и добавил весь свой код и описание исключения, проверьте его. - person Konstantin Chsherbakov; 29.06.2017
comment
@KonstantinChsherbakov Не могли бы вы также поделиться своим обновленным xaml, пожалуйста? - person iam.Carrot; 29.06.2017
comment
@AdityaSharma спасибо за быстрый ответ! Я обновил сообщение и добавил код xaml. Я пробовал разные варианты структуры xaml, я также пробовал точно такой же xaml, который предоставляется в примере приложения пользовательского интерфейса Windows Dev Labs, но результат тот же. - person Konstantin Chsherbakov; 29.06.2017
comment
@AdityaSharma, хм. Я создал новое решение с нуля, чтобы поделиться с вами, и оно работает! Значит, ошибка в моем xaml, интересно. К сожалению, я не могу поделиться с вами исходным кодом из-за политики конфиденциальности компании. В любом случае, спасибо за вашу помощь! - person Konstantin Chsherbakov; 29.06.2017
comment
Отлично. Рад, что смог помочь. - person iam.Carrot; 29.06.2017