WPF如何实现类似iPhone界面切换的效果 (version .1)
转自:http://blog.csdn.net/fallincloud/article/details/6968764
在论坛上见到有人提出了这个问题(WPF实现点击横向切换界面)
我简单地做了个Sample。
效果图1:
效果图2:
设计思路
将这多个界面放入一个Orientation为Horizontal的StackPanel当中,点击Next时,里面所有控件执行TranslteTransform动画。
实现
xaml
- <Window x:Class="WPFNavigation.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="MainWindow" Height="350" Width="400">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="*"></RowDefinition>
- <RowDefinition Height="Auto"></RowDefinition>
- </Grid.RowDefinitions>
- <StackPanel Orientation="Horizontal"
- x:Name="NavigationPanel"
- Height="300"
- HorizontalAlignment="Left"
- VerticalAlignment="Top">
- <Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}, Path=ActualWidth }"
- Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type StackPanel}}, Path=ActualHeight}"
- Background="Blue" >
- <TextBlock FontSize="36">Page1</TextBlock>
- </Grid>
- <Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}, Path=ActualWidth }"
- Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type StackPanel}}, Path=ActualHeight}"
- Background="Violet">
- <TextBlock FontSize="36">Page2</TextBlock>
- </Grid>
- <Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}, Path=ActualWidth }"
- Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type StackPanel}}, Path=ActualHeight}"
- Background="Purple" >
- <TextBlock FontSize="36">Page3</TextBlock>
- </Grid>
- </StackPanel>
- <StackPanel Grid.Row="1" Orientation="Horizontal" >
- <Button Content="Previous" x:Name="ButtonPreviousPage" Click="ButtonPreviousPage_Click"></Button>
- <Button Content="Next" x:Name="ButtonNextPage" Click="ButtonNextPage_Click"></Button>
- </StackPanel>
- </Grid>
- </Window>
cs中
- /// <summary>
- /// Interaction logic for MainWindow.xaml
- /// </summary>
- public partial class MainWindow : Window
- {
- private static readonly double COUNT_PAGE = 3;
- private TranslateTransform NavigationPanelTranslateTransform;
- public MainWindow()
- {
- InitializeComponent();
- NavigationPanelTranslateTransform = new TranslateTransform();
- this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
- }
- void MainWindow_Loaded(object sender, RoutedEventArgs e)
- {
- foreach (FrameworkElement fe in NavigationPanel.Children)
- {
- fe.RenderTransform = NavigationPanelTranslateTransform;
- }
- DeterminButtonStates();
- }
- private void DeterminButtonStates()
- {
- double currentTranX = NavigationPanelTranslateTransform.X;
- if (currentTranX >= 0)
- {
- ButtonPreviousPage.IsEnabled = false;
- }
- else if (currentTranX <= -(COUNT_PAGE - 1) * this.ActualWidth)
- {
- ButtonNextPage.IsEnabled = false;
- }
- else
- {
- ButtonPreviousPage.IsEnabled = true;
- ButtonNextPage.IsEnabled = true;
- }
- }
- private void ButtonPreviousPage_Click(object sender, RoutedEventArgs e)
- {
- double currentTranX = NavigationPanelTranslateTransform.X;
- DoubleAnimation da = new DoubleAnimation(currentTranX, currentTranX+this.ActualWidth, TimeSpan.FromMilliseconds(250));
- da.Completed += (o1, e1) =>
- {
- DeterminButtonStates();
- };
- NavigationPanelTranslateTransform.BeginAnimation(TranslateTransform.XProperty, da);
- }
- private void ButtonNextPage_Click(object sender, RoutedEventArgs e)
- {
- double currentTranX = NavigationPanelTranslateTransform.X;
- DoubleAnimation da = new DoubleAnimation(currentTranX, currentTranX - this.ActualWidth, TimeSpan.FromMilliseconds(250));
- da.Completed += (o1, e1) =>
- {
- DeterminButtonStates();
- };
- NavigationPanelTranslateTransform.BeginAnimation(TranslateTransform.XProperty, da);
- }
- }
WPF如何实现类似iPhone界面切换的效果 (version .2)
转自:http://blog.csdn.net/fallincloud/article/details/6969329
前面写了篇WPF如何实现类似iPhone界面切换的效果 (version .1)
现在又花了点时间重构了下,将动画的效果和Previous和Next这两个按钮的状态控制都封装了起来,效果依然和前面一样
不过重用性高了许多。使用方法如下:
XAML:
- <Window x:Class="WPFNavigation.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WPFNavigation"
- Title="MainWindow" Height="350" Width="400">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="*"></RowDefinition>
- <RowDefinition Height="Auto"></RowDefinition>
- </Grid.RowDefinitions>
- <local:NavigationPanel Orientation="Horizontal"
- x:Name="NavigationPanel"
- Height="300"
- HorizontalAlignment="Left"
- VerticalAlignment="Top">
- <Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}, Path=ActualWidth }"
- Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type local:NavigationPanel}}, Path=ActualHeight}"
- Background="Blue" >
- <TextBlock FontSize="36">Page1</TextBlock>
- </Grid>
- <Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}, Path=ActualWidth }"
- Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type local:NavigationPanel}}, Path=ActualHeight}"
- Background="Violet">
- <TextBlock FontSize="36">Page2</TextBlock>
- </Grid>
- <Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType={x:Type Window}}, Path=ActualWidth }"
- Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type local:NavigationPanel}}, Path=ActualHeight}"
- Background="Purple" >
- <TextBlock FontSize="36">Page3</TextBlock>
- </Grid>
- </local:NavigationPanel>
- <StackPanel Grid.Row="1" Orientation="Horizontal" >
- <Button Content="Previous" x:Name="ButtonPreviousPage"
- IsEnabled="{Binding ElementName=NavigationPanel, Path=PreviousIsValid, Mode=OneWay}"
- Click="ButtonPreviousPage_Click"></Button>
- <Button Content="Next" x:Name="ButtonNextPage" Click="ButtonNextPage_Click"
- IsEnabled="{Binding ElementName=NavigationPanel, Path=NextIsValid, Mode=OneWay}"></Button>
- </StackPanel>
- </Grid>
- </Window>
C#:
- /// <summary>
- /// Interaction logic for MainWindow.xaml
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- }
- private void ButtonPreviousPage_Click(object sender, RoutedEventArgs e)
- {
- NavigationPanel.Previous();
- }
- private void ButtonNextPage_Click(object sender, RoutedEventArgs e)
- {
- NavigationPanel.Next();
- }
- }
以上是用法,封装的NavigationPanel设计如下:
具体实现如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using System.Windows.Media.Animation;
- namespace WPFNavigation
- {
- public class NavigationPanel : StackPanel
- {
- public event EventHandler AnimationComplte;
- private static double COUNT_OF_PAGE;
- private TranslateTransform NavigationPanelTranslateTransform;
- private static readonly TimeSpan DURATION = TimeSpan.FromMilliseconds(250);
- public NavigationPanel():base()
- {
- this.Orientation = Orientation.Horizontal;
- NavigationPanelTranslateTransform = new TranslateTransform();
- this.Loaded += new RoutedEventHandler(NavigationPanel_Loaded);
- }
- void NavigationPanel_Loaded(object sender, RoutedEventArgs e)
- {
- COUNT_OF_PAGE = this.Children.Count;
- CurrentIndex = 0;
- foreach (FrameworkElement fe in this.Children)
- {
- fe.RenderTransform = NavigationPanelTranslateTransform;
- }
- }
- public void Next()
- {
- AnimationChildren(true);
- }
- public void Previous()
- {
- AnimationChildren(false);
- }
- private bool ValidateNext()
- {
- return CurrentIndex < (COUNT_OF_PAGE - 1) && CurrentIndex >= 0;
- }
- private bool ValidatePrevious()
- {
- return CurrentIndex <= (COUNT_OF_PAGE - 1) && CurrentIndex > 0;
- }
- private bool ValidateCurrentIndex()
- {
- if (CurrentIndex > -1 && CurrentIndex < this.Children.Count)
- {
- return true;
- }
- return false;
- }
- private void AnimationChildren(bool forward)
- {
- double currentTranX = NavigationPanelTranslateTransform.X;
- double nextTranX = currentTranX;
- if (forward)
- {
- if (ValidateCurrentIndex())
- {
- nextTranX -= (this.Children[CurrentIndex] as FrameworkElement).ActualWidth;
- }
- }
- else
- {
- if (ValidateCurrentIndex())
- {
- nextTranX += (this.Children[CurrentIndex] as FrameworkElement).ActualWidth;
- }
- }
- DoubleAnimation da = new DoubleAnimation(currentTranX, nextTranX, DURATION);
- da.Completed += (o1, e1) =>
- {
- CurrentIndex += forward ? 1 : -1;
- if (AnimationComplte != null)
- {
- AnimationComplte(this, e1);
- }
- };
- NavigationPanelTranslateTransform.BeginAnimation(TranslateTransform.XProperty, da);
- }
- #region CurrentIndex
- /// <summary>
- /// The <see cref="CurrentIndex" /> dependency property's name.
- /// </summary>
- public const string CurrentIndexPropertyName = "CurrentIndex";
- /// <summary>
- /// Gets or sets the value of the <see cref="CurrentIndex" />
- /// property. This is a dependency property.
- /// </summary>
- public int CurrentIndex
- {
- get
- {
- return (int)GetValue(CurrentIndexProperty);
- }
- set
- {
- SetValue(CurrentIndexProperty, value);
- }
- }
- /// <summary>
- /// Identifies the <see cref="CurrentIndex" /> dependency property.
- /// </summary>
- public static readonly DependencyProperty CurrentIndexProperty = DependencyProperty.Register(
- CurrentIndexPropertyName,
- typeof(int),
- typeof(NavigationPanel),
- new UIPropertyMetadata(-1, OnCurrentIndexChanged));
- private static void OnCurrentIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- (d as NavigationPanel).OnCurrentIndexChanged((int)e.OldValue, (int)e.NewValue);
- }
- protected virtual void OnCurrentIndexChanged(int oldIndex, int newIndex)
- {
- NextIsValid = ValidateNext();
- PreviousIsValid = ValidatePrevious();
- }
- #endregion // CurrentIndex
- #region NextIsValid
- /// <summary>
- /// The <see cref="NextIsValid" /> dependency property's name.
- /// </summary>
- public const string NextIsValidPropertyName = "NextIsValid";
- /// <summary>
- /// Gets or sets the value of the <see cref="NextIsValid" />
- /// property. This is a dependency property.
- /// </summary>
- public bool NextIsValid
- {
- get
- {
- return (bool)GetValue(NextIsValidProperty);
- }
- set
- {
- SetValue(NextIsValidProperty, value);
- }
- }
- /// <summary>
- /// Identifies the <see cref="NextIsValid" /> dependency property.
- /// </summary>
- public static readonly DependencyProperty NextIsValidProperty = DependencyProperty.Register(
- NextIsValidPropertyName,
- typeof(bool),
- typeof(NavigationPanel),
- new UIPropertyMetadata(false));
- #endregion // NextIsValid
- #region PreviousIsValid
- /// <summary>
- /// The <see cref="PreviousIsValid" /> dependency property's name.
- /// </summary>
- public const string PreviousIsValidPropertyName = "PreviousIsValid";
- /// <summary>
- /// Gets or sets the value of the <see cref="PreviousIsValid" />
- /// property. This is a dependency property.
- /// </summary>
- public bool PreviousIsValid
- {
- get
- {
- return (bool)GetValue(PreviousIsValidProperty);
- }
- set
- {
- SetValue(PreviousIsValidProperty, value);
- }
- }
- /// <summary>
- /// Identifies the <see cref="PreviousIsValid" /> dependency property.
- /// </summary>
- public static readonly DependencyProperty PreviousIsValidProperty = DependencyProperty.Register(
- PreviousIsValidPropertyName,
- typeof(bool),
- typeof(NavigationPanel),
- new UIPropertyMetadata(false));
- #endregion // PreviousIsValid
- }
- }