Search code examples
c#wpfxaml

wpf listview item animation


I need some advice. Would anyone know how to make this ListView animation in wpf. I need the ListView item animation to run symmetrically see gif 1. gif 1

But the problem is that the ListView can't scroll and the items are generally displaced, as the setting for VirtualizingStackPanel is HorizontalAlignment="Center" and for ListView I have set ScrollViewer.CanContentScroll="False".

So, how can I modify the code so that the animation of the items in the ListView is symmetrical while preserving the scrolling.

my current code looks like this:

<ListView
      x:Name="ListView1"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center" 
      ScrollViewer.CanContentScroll="False"
      ScrollViewer.HorizontalScrollBarVisibility="Disabled">
      <ListView.ItemsPanel>
          <ItemsPanelTemplate>
              <VirtualizingStackPanel
                  HorizontalAlignment="Center"
                  CacheLength="10,10"
                  CacheLengthUnit="Pixel"
                  IsItemsHost="True"
                  IsVirtualizing="True"
                  Orientation="Horizontal"
                  ScrollUnit="Pixel"
                  VirtualizationMode="Recycling">
              </VirtualizingStackPanel>
          </ItemsPanelTemplate>
      </ListView.ItemsPanel>
      <ListViewItem>
          <Button
              Width="100"
              Height="120"
              Margin="3"
              HorizontalAlignment="Center"
              FontSize="18"
              FontWeight="Bold"
              Foreground="MediumPurple"
              MouseEnter="Button_MouseEnter"
              MouseLeave="Button_MouseLeave" />
      </ListViewItem>

      <!--  more items  -->

  </ListView>
    private void Button_MouseEnter(object sender, MouseEventArgs e)
    {

        var button = sender as Button;
        var WidthAnimation = new DoubleAnimation() { To = 130, Duration = TimeSpan.FromSeconds(0.3) };
        var HeightAnimation = new DoubleAnimation() { To = 150, Duration = TimeSpan.FromSeconds(0.3) };

        button.BeginAnimation(Button.WidthProperty, WidthAnimation);
        button.BeginAnimation(Button.HeightProperty, HeightAnimation);
    }

    private void Button_MouseLeave(object sender, MouseEventArgs e)
    {

        var button = sender as Button;
        var WidthAnimation = new DoubleAnimation() { To = 100, Duration = TimeSpan.FromSeconds(0.3) };
        var HeightAnimation = new DoubleAnimation() { To = 120, Duration = TimeSpan.FromSeconds(0.3) };

        button.BeginAnimation(Button.WidthProperty, WidthAnimation);
        button.BeginAnimation(Button.HeightProperty, HeightAnimation);
    }

Solution

  • Add extra horizontal margin to ItemsPanel and decrease it when a Button is enlarged to compensate the increased width.

    <ListView ItemsSource="{Binding ...}">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsItemsHost="True"
                                        IsVirtualizing="True"
                                        Orientation="Horizontal"
                                        VirtualizationMode="Recycling"
                                        Margin="15,0,0,0"
                                        Loaded="ItemsPanel_Loaded"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemContainerStyle>
            <Style TargetType="{x:Type ListViewItem}">
                <Setter Property="OverridesDefaultStyle" Value="True"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Button Width="100"
                                    Height="120"
                                    Margin="3"
                                    FontSize="18"
                                    FontWeight="Bold"
                                    Foreground="MediumPurple"
                                    MouseEnter="Button_MouseEnter"
                                    MouseLeave="Button_MouseLeave">
                                <ContentPresenter/>
                            </Button>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>
    
    private Panel? _panel;
    
    private void ItemsPanel_Loaded(object sender, RoutedEventArgs e)
    {
        _panel = sender as Panel;
    }
    
    private void Button_MouseEnter(object sender, MouseEventArgs e)
    {
        if (sender is Button button)
        {
            var widthAnimation = new DoubleAnimation { To = 130, Duration = TimeSpan.FromSeconds(0.3) };
            button.BeginAnimation(WidthProperty, widthAnimation);
        }
        if (_panel is not null)
        {
            var marginAnimation = new ThicknessAnimation { To = new Thickness(0, 0, 0, 0), Duration = TimeSpan.FromSeconds(0.3) };
            _panel.BeginAnimation(MarginProperty, marginAnimation);
        }
    }
    
    private void Button_MouseLeave(object sender, MouseEventArgs e)
    {
        if (sender is Button button)
        {
            var widthAnimation = new DoubleAnimation { To = 100, Duration = TimeSpan.FromSeconds(0.3) };
            button.BeginAnimation(WidthProperty, widthAnimation);
        }
        if (_panel is not null)
        {
            var marginAnimation = new ThicknessAnimation { To = new Thickness(15, 0, 0, 0), Duration = TimeSpan.FromSeconds(0.3) };
            _panel.BeginAnimation(MarginProperty, marginAnimation);
        }
    }
    

    The height animation is omitted for brevity.