This section looks at the GesturesView
page in the downloadable sample code and demonstrates the various events of the GestureListener
class. You see how to move, rotate, and resize a UIElement
using gestures. You also see how to provide an animation that responds to a flick gesture to send a UIElement
hurtling across a page.
The view contains a Border
. Within the Border
we attach the GestureListener
and subscribe to its various events:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock x:Name="messageBlock"
Style="{StaticResource PhoneTextNormalStyle}"
VerticalAlignment="Top" />
<Button Content="reset" Click="Button_Click"
VerticalAlignment="Bottom"
HorizontalAlignment="Left" />
<Border x:Name="border"
Width="300" Height="200"
BorderBrush="{StaticResource PhoneBorderBrush}"
BorderThickness="4,32,4,4"
Background="{StaticResource PhoneAccentBrush}"
RenderTransformOrigin="0.5,0.5"
Opacity=".8"
CacheMode="BitmapCache">
<Border.RenderTransform>
<CompositeTransform x:Name="compositeTransform"/>
</Border.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener
Tap="HandleTap"
DoubleTap="HandleDoubleTap"
Hold="HandleHold"
DragStarted="HandleDragStarted"
DragDelta="HandleDragDelta"
DragCompleted="HandleDragCompleted"
Flick="HandleFlick"
PinchStarted="HandlePinchStarted"
PinchDelta="HandlePinchDelta"
PinchCompleted="HandlePinchCompleted">
</toolkit:GestureListener>
</toolkit:GestureService.GestureListener>
</Border>
</Grid>
A CompositeTransform
is used to change the position, size, and rotation of the Border
.
The following sections walk through each gesture event and show how the Border
control is manipulated in response.
When the user performs a tap gesture, the HandleTap
method in the code-beside is called. This method resets the CompositeTransform
translate values to 0, which returns the Border
to its original location.
void HandleTap(object sender, GestureEventArgs e)
{
compositeTransform.TranslateX = compositeTransform.TranslateY = 0;
}
When the user performs a double tap gesture, the HandleDoubleTap
method is called, which resets the amount of scaling applied to the Border
, returning it to its original size.
void HandleDoubleTap(object sender, GestureEventArgs e)
{
compositeTransform.ScaleX = compositeTransform.ScaleY = 1;
}
When a hold gesture is performed, the HandleHold
method is called. This, in turn, calls the ResetPosition
method, resetting the size and location of the Border
.
void HandleHold(object sender, GestureEventArgs e)
{
ResetPosition();
}
void ResetPosition()
{
compositeTransform.TranslateX = compositeTransform.TranslateY = 0;
compositeTransform.ScaleX = compositeTransform.ScaleY = 1;
compositeTransform.Rotation = 0;
}
When a drag gesture is performed, the HandleDragStarted
method is called. This method changes the background of the Border
, like so:
void HandleDragStarted(object sender, DragStartedGestureEventArgs e)
{
border.Background = dragBrush;
}
An event handler for the DragDelta
event moves the element by the drag amount, via the translation properties of the CompositeTransform
:
void HandleDragDelta(object sender, DragDeltaGestureEventArgs e)
{
compositeTransform.TranslateX += e.HorizontalChange;
compositeTransform.TranslateY += e.VerticalChange;
}
When the drag gesture completes, the DragCompleted
event handler resets the Border
background:
void HandleDragCompleted(object sender, DragCompletedGestureEventArgs e)
{
border.Background = normalBrush;
}
When a pinch gesture is detected, the Pinch
event handler records the amount of rotation applied to the element, along with the scale of the element:
double initialAngle;
double initialScale;
void HandlePinchStarted(object sender, PinchStartedGestureEventArgs e)
{
border.Background = pinchBrush;
initialAngle = compositeTransform.Rotation;
initialScale = compositeTransform.ScaleX;
}
A change in the pinch gesture raises the PinchDelta
event, at which point the level of rotation is applied to the CompositeTransform
, and the element is scaled up or down using the PinchGestureEventArgs.DistanceRatio
property:
void HandlePinchDelta(object sender, PinchGestureEventArgs e)
{
compositeTransform.Rotation = initialAngle + e.TotalAngleDelta;
compositeTransform.ScaleX
= compositeTransform.ScaleY = initialScale * e.DistanceRatio;
}
The completion of a pinch gesture sees the border’s background restored, as shown:
void HandlePinchCompleted(object sender, PinchGestureEventArgs e)
{
border.Background = normalBrush;
}
This section presents a technique for animating a UIElement
in response to a flick gesture. When a flick occurs, we install a StoryBoard
with a timeline animation, which performs a translation on the UIElement
.
The detection of a flick gesture causes the Flick
event handler, HandleFlick
, to be called. This method calculates a destination point for the border control based on the velocity of the flick. It then creates an animation for the border using the custom AddTranslationAnimation
. See the following excerpt:
const double brakeSpeed = 10;
void HandleFlick(object sender, FlickGestureEventArgs e)
{
Point currentPoint = new Point(
(double)compositeTransform.GetValue(
CompositeTransform.TranslateXProperty),
(double)compositeTransform.GetValue(
CompositeTransform.TranslateYProperty));
double toX = currentPoint.X + e.HorizontalVelocity / brakeSpeed;
double toY = currentPoint.Y + e.VerticalVelocity / brakeSpeed;
Point destinationPoint = new Point(toX, toY);
var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };
AddTranslationAnimation(
storyboard, border, currentPoint, destinationPoint,
new Duration(TimeSpan.FromMilliseconds(500)),
new CubicEase {EasingMode = EasingMode.EaseOut});
storyboard.Begin();
}
The static method AddTranslationAnimation
creates two DoubleAnimation
objects: one for the horizontal axis, the other for the vertical axis. Each animation is assigned to the border’s CompositeTransform
, as shown:
static void AddTranslationAnimation(Storyboard storyboard,
FrameworkElement targetElement,
Point fromPoint,
Point toPoint,
Duration duration,
IEasingFunction easingFunction)
{
var xAnimation = new DoubleAnimation
{
From = fromPoint.X,
To = toPoint.X,
Duration = duration,
EasingFunction = easingFunction
};
var yAnimation = new DoubleAnimation
{
From = fromPoint.Y,
To = toPoint.Y,
Duration = duration,
EasingFunction = easingFunction
};
AddAnimation(
storyboard,
targetElement.RenderTransform,
CompositeTransform.TranslateXProperty,
xAnimation);
AddAnimation(
storyboard,
targetElement.RenderTransform,
CompositeTransform.TranslateYProperty,
yAnimation);
}
The static method AddAnimation
associates an animation Timeline
with a DependencyObject
, which in this case is the Border
control:
static void AddAnimation(
Storyboard storyboard,
DependencyObject dependencyObject,
DependencyProperty targetProperty,
Timeline timeline)
{
Storyboard.SetTarget(timeline, dependencyObject);
Storyboard.SetTargetProperty(timeline, new PropertyPath(targetProperty));
storyboard.Children.Add(timeline);
}
When launched, the GestureView
page allows the user to flick the Border
element across the page. A reset button exists to reset the position of the Border
if it happens to leave the visible boundaries of the page (see Figure 12.11).
Toolkit gestures offer a high-level way of interpreting touch input data and make it easy to provide a natural and immersive experience for your users, without the bother of tracking low-level touch events.
18.117.159.116