Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animation in visibility from hidden to collapsed and vice versa

I am trying to achieve something similar to iPhone message view. On a button click, a delete button would slide out for every message and on clicking "done" the delete buttons would slide in. I have been able to achieve that using mvvm except the sliding effect. Here is the style I could write with my limited knowledge:

<Style TargetType="Border">
    <Style.Triggers>
        <DataTrigger Binding="{Binding ShowDeleteButton}" Value="false">
            <Setter Property="Visibility" Value="Collapsed"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

Here "ShowDeleteButton" is a bool property in the view model. This works fine. but the collapsing and "getting visible" is happening abruptly and very fast. I need some sliding animation. Please note that as the delete buttons disappear, the rest of the controls should take up the rest of space and, as the button appear, the existing controls should shrink and give space to the buttons. I tried with storyboard animation but even after a couple hours I am not able to figure out the strange errors it is throwing. Here is the code:

<DataTrigger Binding="{Binding ShowDeleteButton}" Value="false">
     <DataTrigger.EnterActions>
          <BeginStoryboard>
               <Storyboard BeginTime="0:0:1">
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visiblity">
                     <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
           </BeginStoryboard>
      </DataTrigger.EnterActions>
      <DataTrigger.ExitActions>
            <BeginStoryboard>
               <Storyboard BeginTime="0:0:1">
                 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visiblity">
                     <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
                 </ObjectAnimationUsingKeyFrames>
               </Storyboard>
            </BeginStoryboard>
      </DataTrigger.ExitActions>
</DataTrigger>

Can someone please help the soul in distress?

regards

like image 592
James Avatar asked May 22 '12 12:05

James


1 Answers

Old question... huh...

Anyway... forget about visibility. The trick is to animate Width/Height of the Control placed in Grid's Column/Row where the Column/Row has Width set to Auto. Uff :)

So here is a Grid named "container" with two columns. In the first column can be placed whatever you want, but you should align it to Right since you want it to move when your delete button is displayed. And in the second column there is a Control (representing your DeleteButton) Notice that first column has Width="*" and second column has Width="Auto"

<Grid Background="Purple" Width="350" Height="100">
    <CheckBox Content="Show" IsChecked="{Binding Path=ShowDeleteButton}" Height="16" HorizontalAlignment="Left" Margin="12,12,0,0" Name="checkBox1" VerticalAlignment="Top" />
    <Grid x:Name="container" Margin="40,0,0,0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid Name="content" Margin="0">
            <Label Content="Look I'm flyin'!" Margin="0,30,10,0" VerticalAlignment="Top" HorizontalAlignment="Right"/>
        </Grid>
        <Control Grid.Column="1" Margin="0">
            <Control.Template>
                <ControlTemplate>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding ShowDeleteButton}" Value="true">
                            <DataTrigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation 
                                Storyboard.TargetName="flyout"
                                Storyboard.TargetProperty="(Grid.Width)" 
                                From="0" To="120" Duration="0:0:1" AutoReverse="False"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.EnterActions>
                            <DataTrigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation 
                                Storyboard.TargetName="flyout"
                                Storyboard.TargetProperty="(Grid.Width)" 
                                From="120" To="0" Duration="0:0:1" AutoReverse="False"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.ExitActions>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                    <Grid x:Name="flyout" Width="0">
                        <Rectangle Fill="Green"/>
                        <Label Content="I'm DELETE button" Margin="10,30,0,0" VerticalAlignment="Top"/>
                    </Grid>
                </ControlTemplate>
            </Control.Template>
        </Control>
    </Grid>
</Grid>

And the Control in Grid's second column has DataTrigger based on your ViewModel's property "ShowDeleteButton"

Since the Width of column where the Control is placed is Auto you can change the width of the Control using simple DoubleAnimation and you get desired behavior.

EDIT

Look at this if you want the flyout to be over everything else.

<Grid x:Name="LayoutRoot">
    <Grid x:Name="container" Width="120" HorizontalAlignment="Right">
            <Button x:Name="button" Content="In" Margin="0,13,7.5,0" VerticalAlignment="Top" HorizontalAlignment="Right" d:LayoutOverrides="HorizontalAlignment">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation 
                                    Storyboard.TargetName="flyout"
                                    Storyboard.TargetProperty="(Grid.Width)" 
                                    From="0" To="120" Duration="0:0:1" AutoReverse="False"/> 
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
    </Grid>
    <Grid x:Name="flyout" Width="120" Margin="0" HorizontalAlignment="Right">
            <Rectangle Fill="Green"/>
            <Label Content="This is some label" Margin="6.038,27,1.006,0" VerticalAlignment="Top"/>
            <Button Content="Out" Margin="11.917,58,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="80.083">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation 
                                    Storyboard.TargetName="flyout"
                                    Storyboard.TargetProperty="(Grid.Width)" 
                                    From="120" To="0" Duration="0:0:1" AutoReverse="False"/> 
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
        </Grid>
</Grid>

Please note that button "Out" can be clicked while it's moving. It should be probably disabled. I just did it like this because I wanted to do it simple and all in xaml. Sure you can use mahapps. Or you can just make it as fast as it is in MahApps and it's impossible to click it twice. :) I have looked at MahApps FlyOutDemo and my solution looks much simpler to me. And I don't need third party library.

like image 125
Kapitán Mlíko Avatar answered Nov 09 '22 23:11

Kapitán Mlíko