您的位置:首页 > 其它

WPF如何实现类似iPhone界面切换的效果(转载)

2013-07-16 22:09 761 查看

WPF如何实现类似iPhone界面切换的效果 (version .1)

转自:http://blog.csdn.net/fallincloud/article/details/6968764

在论坛上见到有人提出了这个问题(WPF实现点击横向切换界面

我简单地做了个Sample。

效果图1:



效果图2:



设计思路

将这多个界面放入一个Orientation为Horizontal的StackPanel当中,点击Next时,里面所有控件执行TranslteTransform动画。

实现

xaml

[html] view plaincopy

<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中

[csharp] view plaincopy

/// <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);

}

}

[b]WPF如何实现类似iPhone界面切换的效果 (version .2)[/b]

转自:http://blog.csdn.net/fallincloud/article/details/6969329

前面写了篇WPF如何实现类似iPhone界面切换的效果 (version .1)

现在又花了点时间重构了下,将动画的效果和Previous和Next这两个按钮的状态控制都封装了起来,效果依然和前面一样

不过重用性高了许多。使用方法如下:

XAML:

[html] view plaincopy

<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#:

[csharp] view plaincopy

/// <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设计如下:



具体实现如下:

[csharp] view plaincopy

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

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: