While analyzing some controls used for touch devices I found this effective and easy logic for touch control and slow finishing action after touch leaves. Normally in touch devices we like to have control of an application with very smooth touch interaction. We also expect some slow finish of the action, like if we tap and wipe a control then it will move some distance and stay. So I found this logic to do that in an effective manner.
Platform support this approach
- WPF
- Windows Stores (WinRT)
- Windows Phones 8
Concept behind the approach
In my logic I have handled the manipulation of the data to the control. Using the manipulation of the data, I reset the matrix value of the control as desired. For slow finishing, I used a timer that enables the control for slower and smooth finishing actions after touch leaves.
XAML Code snippet behind the approach
<Button x:Class="TouchApplication.SmoothestTouchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
</Grid>
</Button>
<Window x:Class="TouchApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication8">
<Grid >
<local:SmoothestTouchControl IsManipulationEnabled="True"
RenderTransform="0.9 0 0 0.9 100 100" />
<local:SmoothestTouchControl IsManipulationEnabled="True"
RenderTransform="0.9 0 0 0.9 100 100" />
<local:SmoothestTouchControl IsManipulationEnabled="True"
RenderTransform="0.9 0 0 0.9 100 100" />
<local:SmoothestTouchControl IsManipulationEnabled="True"
RenderTransform="0.9 0 0 0.9 100 100" />
<local:SmoothestTouchControl IsManipulationEnabled="True"
RenderTransform="0.9 0 0 0.9 100 100" /
</Grid>
</Window>
C# code snippet behind the approach
// Use required name space using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace TouchApplication
{
/// Interaction logic for SmoothestTouchControl.xaml
public partial class SmoothestTouchControl : Button
{
int i = 0; // Iteration count for slower animation to end
UIElement uiElement = null; // contains current control
MatrixTransform matrixTransform = null; // contains Matrix transform
Matrix uiElementMatrix = new Matrix(); // contains Matrix of the UIElement
ManipulationDelta manipulationDelta = null; // contains data of Manipulation
Point centerPoint = new Point(); // contains center point of the element
System.Windows.Forms.Timer smoother = new System.Windows.Forms.Timer(); // Animater that slow down the action after touch leave
public SmoothestTouchControl()
{
smoother.Interval = 1; // Inverval for animater
smoother.Tick += smoother_Tick; // hook event to animation
}
// override manupulation starting to reset the Z order to get the current touched UI element a top element
protected override void OnManipulationStarting(ManipulationStartingEventArgs args)
{
args.ManipulationContainer = App.Current.MainWindow; // Get the parent window
var frameworkElement = args.Source as FrameworkElement; // Get the current touched element
var panel = frameworkElement.Parent as Panel; // Get parent element to have the children collection
for (int i = 0; i < panel.Children.Count; i++) // Iterate the children collection to reset the Z order
{
Panel.SetZIndex(panel.Children[i], panel.Children[i] == frameworkElement ? panel.Children.Count : i);
}
args.Handled = true; // Get handled true
base.OnManipulationStarting(args); // Call base for original action
}
// override manipulation delta for transform actions
protected override void OnManipulationDelta(ManipulationDeltaEventArgs args)
{
uiElement = args.Source as UIElement; // Get the current touched element
matrixTransform = uiElement.RenderTransform as MatrixTransform; // Get MatrixTransform of the element
uiElementMatrix = matrixTransform.Matrix; // Get Matrix of the element
manipulationDelta = args.DeltaManipulation; // Get delta manipulation of the touch action
centerPoint = args.ManipulationOrigin; // Get center point of the manipulation
uiElementMatrix.RotateAt(manipulationDelta.Rotation, centerPoint.X, centerPoint.Y); // Rotate the ccontrol acccording to manipulation
uiElementMatrix.ScaleAt(manipulationDelta.Scale.X, manipulationDelta.Scale.Y, centerPoint.X, centerPoint.Y);// Scale the ccontrol acccording to manipulation
uiElementMatrix.Translate(manipulationDelta.Translation.X, manipulationDelta.Translation.Y); // Move the ccontrol acccording to manipulation
matrixTransform.Matrix = uiElementMatrix; // Reset the updated matrix to the element matrix
args.Handled = true; // Get handled true
base.OnManipulationDelta(args); // Call base for original action
}
// override manipulation completed to start slower finish of the touch action
protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
base.OnManipulationCompleted(e); // Call base for original action
smoother.Interval = 1; // reset the interval of the slower finish action
i = 10; // Reset the iterator of the slower finish
smoother.Start(); // Start animation for slower finish
}
// slowe finish animater logic
void smoother_Tick(object sender, EventArgs e)
{
i--; // for slow finish action
smoother.Interval = smoother.Interval + 2; // increase interval for integrated slow finish
if (smoother.Interval > 25) // Check for dezire interval
smoother.Stop(); // Stop the animation
if (manipulationDelta.Rotation != 0) // Check if the control atually in rotation
{
uiElementMatrix.RotateAt(manipulationDelta.Rotation - (i > 0 ? i : 1), centerPoint.X, centerPoint.Y); // keep rotation using iterated value
}
uiElementMatrix.Translate(manipulationDelta.Translation.X - (i > 0 ? i : 0), manipulationDelta.Translation.Y - (i > 0 ? i : 0)); // keep moving using iterated value
matrixTransform.Matrix = uiElementMatrix; // reset the updated matrix to the element matrix
}
}
}