Search code examples
c#xamlanimationuwpwindows-community-toolkit

uwp GridView selectedItem Popup


I am using AdaptiveGridView by UWP Community toolkit. I want the selected Item of the gridview to popup on the Z-axis, meaning the selected Item must scale up to a specific size, but it should not disturb the size of other gridview items, rather it should scale on Z axis of the canvas. what are possibilities to animate this effect also maybe using UWP community toolkit scale effect ( but that effects the size of other items as well). if its not possible on selected Item can it be somehow possible on pointer hover?


Solution

  • Method 1: On Selection changed

    XAML Part

    <GridView Height="200" SelectionChanged="GridView_SelectionChanged">
        <GridView.ItemTemplate>
            <DataTemplate x:DataType="local:ItemSource">
                <Grid Width="100" Height="100">
                    <!-- Content -->
                </Grid>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsWrapGrid VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
    </GridView>
    

    C# Part

    FrameworkElement lastPopUpElement = null;
    private void GridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (lastPopUpElement != null)
        {
            Canvas.SetZIndex(lastPopUpElement, 0);
            lastPopUpElement.Scale(centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
        }
    
        lastPopUpElement = (sender as GridView).ContainerFromIndex((sender as GridView).SelectedIndex) as FrameworkElement;
    
        if (lastPopUpElement != null)
        {
            Canvas.SetZIndex(lastPopUpElement, 1);
            lastPopUpElement.Scale(scaleX: 1.5f, scaleY: 1.5f, centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
        }
    }
    

    Sample Output

    enter image description here

    Method 2: On Pointer Hover

    XAML Part

    <GridView Height="200">
        <GridView.ItemTemplate>
            <DataTemplate x:DataType="local:ItemSource">
                <Grid Width="100" Height="100" PointerEntered="GridView_PointerEntered" PointerExited="GridView_PointerExited">
                    <!-- Content -->
                </Grid>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsWrapGrid VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
    </GridView>
    

    C# Part

    FrameworkElement lastPopUpElement = null;
    private void GridView_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        lastPopUpElement = VisualTreeHelper.GetParent(VisualTreeHelper.GetParent(sender as FrameworkElement) as FrameworkElement) as FrameworkElement;
        Canvas.SetZIndex(lastPopUpElement, 1);
        lastPopUpElement.Scale(scaleX: 1.5f, scaleY: 1.5f, centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
    }
    
    private void GridView_PointerExited(object sender, PointerRoutedEventArgs e)
    {
        if (lastPopUpElement != null)
        {
            Canvas.SetZIndex(lastPopUpElement, 0);
            lastPopUpElement.Scale(centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
        }
    }
    

    Sample Output

    enter image description here

    Method 3: With Drop Shadow

    XAML Part

    <GridView Height="200">
        <GridView.ItemTemplate>
            <DataTemplate x:DataType="local:ItemSource">
                <controls:DropShadowPanel OffsetX="5" OffsetY="5" Color="Black" BlurRadius="5" ShadowOpacity="0" PointerEntered="myListView_PointerEntered" PointerExited="myListView_PointerExited">
                    <Grid Width="100" Height="100" VerticalAlignment="Center" HorizontalAlignment="Center">
                        <!-- Content -->
                    </Grid>
                </controls:DropShadowPanel>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsWrapGrid VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
    </GridView>
    

    C# Part

    private void myListView_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        DropShadowPanel DropShadow = sender as DropShadowPanel;
        lastPopUpElement = VisualTreeHelper.GetParent(VisualTreeHelper.GetParent(DropShadow) as FrameworkElement) as FrameworkElement;
        DropShadow.ShadowOpacity = 0.5;
        Canvas.SetZIndex(lastPopUpElement, 10);
        lastPopUpElement.Scale(scaleX: 1.5f, scaleY: 1.5f, centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
    }
    
    private void myListView_PointerExited(object sender, PointerRoutedEventArgs e)
    {
        if (lastPopUpElement != null)
        {
            DropShadowPanel DropShadow = sender as DropShadowPanel;
            DropShadow.ShadowOpacity = 0;
            Canvas.SetZIndex(lastPopUpElement, 0);
            lastPopUpElement.Scale(centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
        }
    }
    

    Sample Output

    enter image description here


    (Old Post)

    Method 1 (Doesn't overlay with other items)

    XAML Part

    <Grid Name="MainGrid" Height="200">
        <controls:AdaptiveGridView x:Name="myAdaptiveGridView" SelectionChanged="myAdaptiveGridView_SelectionChanged" VerticalAlignment="Center" HorizontalAlignment="Left">
            <controls:AdaptiveGridView.ItemTemplate>
                <DataTemplate>
                    <Grid Width="150" Height="150">
                        <Grid Width="100" Height="100" VerticalAlignment="Center" HorizontalAlignment="Center">
                            <!-- Content -->
                        </Grid>
                    </Grid>
                </DataTemplate>
            </controls:AdaptiveGridView.ItemTemplate>
        </controls:AdaptiveGridView>
    </Grid>
    

    C# Part

    FrameworkElement oldSetectedItem = null;
    
    private void myAdaptiveGridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (oldSetectedItem != null)
            oldSetectedItem.Scale(1, 1, 50, 50, 500).Start();
    
        var container = myAdaptiveGridView.ContainerFromIndex(myAdaptiveGridView.SelectedIndex) as FrameworkElement;
        var listViewItemPresenter = VisualTreeHelper.GetChild(container, 0) as FrameworkElement;
        var outerGrid = VisualTreeHelper.GetChild(listViewItemPresenter, 0) as FrameworkElement;
        var grid = VisualTreeHelper.GetChild(outerGrid, 0) as FrameworkElement;
        oldSetectedItem = grid;
    
        grid.Scale(1.5f, 1.5f, 50, 50, 500).Start();
    }
    

    Sample Output

    enter image description here

    Method 2 (will overlay with other items)

    XAML Part

    <Grid Name="MainGrid" Height="200">
        <controls:AdaptiveGridView x:Name="myAdaptiveGridView" SelectionChanged="myAdaptiveGridView_SelectionChanged" VerticalAlignment="Center" HorizontalAlignment="Left">
            <controls:AdaptiveGridView.ItemTemplate>
                <DataTemplate>
                    <Grid Width="100" Height="100" VerticalAlignment="Center" HorizontalAlignment="Center">
                        <!-- Content -->
                    </Grid>
                </DataTemplate>
            </controls:AdaptiveGridView.ItemTemplate>
        </controls:AdaptiveGridView>
        <Image x:Name="RenderedImage" Stretch="None" Visibility="Collapsed" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    </Grid>
    

    C# Part

    private async void myAdaptiveGridView_SelectionChangedAsync(object sender, SelectionChangedEventArgs e)
    {
        RenderedImage.Scale(1, 1, 0, 0, 0).Start();
    
        var container = myAdaptiveGridView.ContainerFromIndex(myAdaptiveGridView.SelectedIndex) as FrameworkElement;
        var listViewItemPresenter = VisualTreeHelper.GetChild(container, 0) as FrameworkElement;
        var grid = VisualTreeHelper.GetChild(listViewItemPresenter, 0) as FrameworkElement;
        oldSetectedItem = grid;
    
        var TTV = grid.TransformToVisual(MainGrid);
        Point screenCoords = TTV.TransformPoint(new Point(0, 0));
    
        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
        await renderTargetBitmap.RenderAsync(grid);
        RenderedImage.Source = renderTargetBitmap;
        RenderedImage.Margin = new Thickness(screenCoords.X, screenCoords.Y, 0, 0);
        RenderedImage.Width = grid.ActualWidth;
        RenderedImage.Height = grid.ActualHeight;
        RenderedImage.Visibility = Visibility.Visible;
    
        RenderedImage.Scale(1.5f, 1.5f, 50, 50, 500).Start();
    }
    

    Sample Output

    enter image description here