Reputation: 1946
Is there a way to have a control which allows me to pinch and zoom using ONLY Xamarin.Forms controls.
I want to display an image in any control from xamarin.forms(WebView or Image or any other ) and be able to zoom from the application.
Upvotes: 4
Views: 4932
Reputation: 9
Use Mr.Gestures package from Nuget : https://www.nuget.org/packages/MR.Gestures/
Upvotes: 0
Reputation: 1946
I ended up using meta viewport for zooming as follows. This might not be a solution for every one but it worked for me.
Put the image hex -64 inside the image tag below and then put the whole html in WebView.
this.WebView.Source = new HtmlWebViewSource { BaseUrl = URL, Html = html };
The html will be defined here.
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.25, maximum-scale=3.0 user-scalable=1">
<title></title>
<style>
body {
margin: 0 20px 0 0;
font-family: HelveticaNeue-Light, HelveticaNeue-UltraLight, Helvetica, Consolas, 'Courier New';
}
table {
width: 100%;
border: 1px outset;
border-color: #3c4142;
}
td {
font-size: 8px;
}
</style>
</head>
<body>
<img src="data:image/png;base64,YourBase64imagestringhere" style="width:100%" />
</body>
</html>
Upvotes: 1
Reputation: 11040
There isn't a way to pinch/zoom with pure built-in Forms controls as of the time of this post. There is a way to achieve this but you have to implement a native renderer for that.
I achieved this in an app I'm writing by creating a class that inherits from Xamarin.Forms.ContentView - PanGestureContainer, which has properties such as number of touch points min/max and an event to listen to.
In the iOS project I made a custom renderer for my view, where the renderer takes the properties from the view and hooks up touch event listeners.
Additionally I made an attachable property (aka Behavior) that can be applied to other Views and when applied it takes the view from its parent, wraps it inside a PanGestureRecognizer and another attached property acts as an event listener wrapper the same way.
It's a complete hack but covers the missing functionality until Xamarin implements it cleanly
Update: now with sample code, seriously trimmed down as it would be too much to post, it should give you an idea how to achieve this rather that be a copy/paste solution. If it seems like too much it probably is, I'm sure there are better ways but it does the trick until this functionality is baked-in.
public abstract class BaseInteractiveGestureRecognizer : BindableObject, IInteractiveGestureRecognizer
{
public static readonly BindableProperty CommandProperty = BindableProperty.Create<BaseInteractiveGestureRecognizer, ICommand> ((b) => b.Command, null, BindingMode.OneWay, null, null, null, null);
public ICommand Command {
get {
return (ICommand)base.GetValue (BaseInteractiveGestureRecognizer.CommandProperty);
}
set {
base.SetValue (BaseInteractiveGestureRecognizer.CommandProperty, value);
}
}
public object CommandParameter {get;set;} // make bindable as above
public GestureState State { get;set;} // make bindable as above
public View SourceView{ get; set; }
public void Send ()
{
if (Command != null && Command.CanExecute (this)) {
Command.Execute (this);
}
}
}
public class PanGesture : BaseInteractiveGestureRecognizer
{
public uint MinTouches { get;set; } // make bindable
public uint MaxTouches { get;set; } // make bindable
// add whatever other properties you need here - starting point, end point, touch count, current touch points etc.
}
And then in the iOS project:
public abstract class BaseInteractiveGestureRenderer : BindableObject,IGestureCreator<UIView>
{
public abstract object Create (IInteractiveGestureRecognizer gesture, Element formsView, UIView nativeView);
public static GestureState FromUIGestureState (UIGestureRecognizerState state)
{
switch (state) {
case UIGestureRecognizerState.Possible:
return GestureState.Possible;
case UIGestureRecognizerState.Began:
return GestureState.Began;
case UIGestureRecognizerState.Changed:
return GestureState.Update;
case UIGestureRecognizerState.Ended:
return GestureState.Ended;
case UIGestureRecognizerState.Cancelled:
return GestureState.Cancelled;
case UIGestureRecognizerState.Failed:
return GestureState.Failed;
default:
return GestureState.Failed;
}
}
}
using StatementsHere;
[assembly: ExportGesture (typeof(PanGesture), typeof(PanGestureRenderer))]
namespace YourNamespaceHere.iOS
{
public class PanGestureRenderer : BaseInteractiveGestureRenderer
{
public PanGestureRenderer () : base ()
{
}
#region IGestureCreator implementation
public override object Create (IInteractiveGestureRecognizer gesture, Element formsView, UIView nativeView)
{
PanGesture panGesture = gesture as PanGesture;
nativeView.UserInteractionEnabled = true;
UIPanGestureRecognizer panGestureRecognizer = null;
panGestureRecognizer = new UIPanGestureRecognizer (() => panGesture.Send());
}
}
Upvotes: 1