A while back after scouring the net and merging some code, I created PhotoViewer that is used in my cool camera app. It might not be perfect but it works acceptably. Here’s how it work in code.
Lets start with Xaml..
<Image x:Name="imgViewer" Stretch="UniformToFill" Width="728" Height="480"> <Image.RenderTransform> <ScaleTransform x:Name="scaleTrans" ScaleX="1" ScaleY="1" /> </Image.RenderTransform> <toolkit:GestureService.GestureListener> <toolkit:GestureListener Flick="GestureListener_Flick" PinchStarted="GestureListener_PinchStart" PinchDelta="GestureListener_PinchDelta" PinchCompleted="GestureListener_PinchComplete" DragStarted="GestureListener_DragStart" DragDelta="GestureListener_DragDelta" DragCompleted="GestureListener_DragCompleted" Tap="GestureListener_Tap" DoubleTap="GestureListener_DoubleTap"/> </toolkit:GestureService.GestureListener> </Image>
as you can see.. we start with Image and add a ScaleTransform. Next up with add GestureService from SL Toolkit. I am going to subscribe to some events. Here’s how the code behind looks
lets start by defining some data members
private readonly DispatcherTimer m_animationTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) }; private double m_friction = 0.99; private Point m_scrollStartPoint; private Point m_scrollTarget = new Point(); private double m_hvelocity; private double m_vvelocity; private double m_angle; private double _cx, _cy;
Next up, set the Tick event in the constructor so we can do something on Tick of the DispatcherTimer.
m_animationTimer.Tick += new EventHandler(m_animationTimer_Tick);
Now the real code.. lets implement some of the event handlers
void m_animationTimer_Tick(object sender, EventArgs e) { if (m_hvelocity < 0.1) m_hvelocity = 0; if (m_vvelocity < 0.1) m_vvelocity = 0; if (m_hvelocity == 0 && m_vvelocity == 0) { m_animationTimer.Stop(); return; } if (m_angle > 0 && m_angle < 180) scaleTrans.CenterY -= m_vvelocity; else scaleTrans.CenterY += m_vvelocity; if(m_angle > 90 && m_angle < 270) scaleTrans.CenterX += m_hvelocity; else scaleTrans.CenterX -= m_hvelocity; m_hvelocity *= m_friction; m_vvelocity *= m_friction; if ((scaleTrans.CenterX <= 0 || scaleTrans.CenterX >= imgViewer.Width) || (scaleTrans.CenterY <= 0 || scaleTrans.CenterY >= imgViewer.Height)) { if (scaleTrans.CenterX < 0) scaleTrans.CenterX = 0; if (scaleTrans.CenterX > imgViewer.Width) scaleTrans.CenterX = imgViewer.Width; if (scaleTrans.CenterY < 0) scaleTrans.CenterY = 0; if (scaleTrans.CenterY > imgViewer.Height) scaleTrans.CenterY = imgViewer.Height; m_animationTimer.Stop(); } } private void GestureListener_Flick(object sender, FlickGestureEventArgs e) { m_angle = e.Angle; m_animationTimer.Stop(); m_scrollStartPoint = e.GetPosition(this); m_scrollTarget.X = m_scrollStartPoint.X + e.HorizontalVelocity; m_scrollTarget.Y = m_scrollStartPoint.Y + e.VerticalVelocity; m_hvelocity = Math.Abs(e.HorizontalVelocity)/100; m_vvelocity = Math.Abs(e.VerticalVelocity)/100; if (m_scrollTarget.X < 0) m_scrollTarget.X = 0; if(m_scrollTarget.X > imgViewer.Width) m_scrollTarget.X = imgViewer.Width; if (m_scrollTarget.Y < 0) m_scrollTarget.Y = 0; if (m_scrollTarget.Y > imgViewer.Height) m_scrollTarget.Y = imgViewer.Height; m_animationTimer.Start(); } private void GestureListener_PinchStart(object sender, PinchStartedGestureEventArgs e) { Point p1 = e.GetPosition(imgViewer, 0); Point p2 = e.GetPosition(imgViewer, 1); scaleTrans.CenterX = (p1.X + ((p2.X - p1.X) / 2)); scaleTrans.CenterY = (p1.Y + ((p2.Y - p1.Y) / 2)); _cx = scaleTrans.ScaleX; _cy = scaleTrans.ScaleY; } private void GestureListener_PinchDelta(object sender, PinchGestureEventArgs e) { // Compute new scaling factors double cx = _cx * e.DistanceRatio; double cy = _cy * e.DistanceRatio; // If they're between 1.0 and 4.0, inclusive, apply them if (cx >= 1.0 && cx <= 4.0 && cy >= 1.0 && cy <= 4.0) { if ((cy - 1) < 0.1 && (cx - 1) < 0.1) cx = cy = 1; scaleTrans.ScaleX = cx; scaleTrans.ScaleY = cy; } } private void GestureListener_PinchComplete(object sender, PinchGestureEventArgs e) { } private void GestureListener_DragStart(object sender, DragStartedGestureEventArgs e) { } private void GestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e) { scaleTrans.CenterX = (scaleTrans.CenterX - e.HorizontalChange); scaleTrans.CenterY = (scaleTrans.CenterY - e.VerticalChange); if (scaleTrans.CenterX < 0) scaleTrans.CenterX = 0; else if (scaleTrans.CenterX > (imgViewer.Height * scaleTrans.ScaleX)) scaleTrans.CenterX = imgViewer.Height * scaleTrans.ScaleX; if(scaleTrans.CenterY < 0) scaleTrans.CenterY = 0; else if (scaleTrans.CenterY > (imgViewer.Height * scaleTrans.ScaleY)) scaleTrans.CenterY = imgViewer.Height * scaleTrans.ScaleY; } private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e) { scaleTrans.CenterX = (scaleTrans.CenterX - e.HorizontalChange); scaleTrans.CenterY = (scaleTrans.CenterY - e.VerticalChange); if (scaleTrans.CenterX < 0) scaleTrans.CenterX = 0; else if (scaleTrans.CenterX > imgViewer.Width) scaleTrans.CenterX = imgViewer.Width; if (scaleTrans.CenterY < 0) scaleTrans.CenterY = 0; else if (scaleTrans.CenterY > (imgViewer.Height)) scaleTrans.CenterY = imgViewer.Height; } private void GestureListener_DoubleTap(object sender, Microsoft.Phone.Controls.GestureEventArgs e) { scaleTrans.ScaleX = scaleTrans.ScaleY = 1; } private void GestureListener_Tap(object sender, Microsoft.Phone.Controls.GestureEventArgs e) { m_animationTimer.Stop(); m_hvelocity = 0; m_vvelocity = 0; }
Advertisements
Pingback: [Windows Phone] PhotoViewer with pinch & zoom, pan and flick support
Pingback: PhotoViewer with pinch & zoom, pan and flick support | Hispafoxing
Thanks but as is this code doesn’t seem to do anything.
This code is a part of overall album viewer and it works 🙂 i might do a sample thats downloadable later.
I’m not sure but it looks like it’s missing an important part: inertia… touch Manipulation without inertia feels very bad in my opinion.
GestureListener is deprecated in the new Windows Phone Toolkit. Should we be following this ?
http://www.jeff.wilcox.name/2011/11/nov2011phonetoolkit/
Its been deprecated since Mango Release ? that’s almost 2 years now. I’d probably use it as long as its still there. Having said that, if I was designing something for Windows 8 and had to implement something, I use Manipulation Events (Started, Delta and Complete) to create one and share some code
Hello, this code works with HIGH RESOLUTION IMAGES? (20MP – 41MP) thank you
you should try WP8 sdk’s ViewportControl
Pingback: How to limiting the image zooming, dragging with the screen? - Popular Windows Phone Questions