简体   繁体   中英

How to add zoomin-zoomout functionalities with mouse events for the image in WPF in xamarin.froms

I am trying for the image viewer in WPF using xamarin.forms, I did not find anything to start for the zoom functionalities. I am able to get only WPF or Android in xamarin. forms but unable to find the combination of WPF with xamarin.forms. Please help me to achieve this.

EDIT

I have created the another view and able to zoom in and zoom out with the two buttons.

 <ContentPage.Content>
    <ScrollView>
        <StackLayout>
            <Image x:Name="ImageToDisplay"
           HorizontalOptions="Center"
            VerticalOptions="Center"
            Aspect="AspectFill" >
            </Image>
            <StackLayout Orientation="Horizontal" Grid.Row="1" HorizontalOptions="CenterAndExpand">
                <Button Text="ZoomOut" Clicked="ZoomOut"/>
                <Button Text="ZoomIn" Clicked="ZoomIn"/>
            </StackLayout>
        </StackLayout>
    </ScrollView>
</ContentPage.Content>

 private void ZoomIn(object sender, EventArgs e)
    {
        var currentScale = ImageToDisplay.Scale;

        if(currentScale>=1 && currentScale < 5)
        {
            ImageToDisplay.Scale = currentScale + 0.25;
        }
    }

    private void ZoomOut(object sender, EventArgs e)
    {
        var currentScale = ImageToDisplay.Scale;

        if (currentScale >= 1 && currentScale < 5)
        {
            ImageToDisplay.Scale = currentScale - 0.25;
        }
    }

But here, when the image is Zoom in, the remaining part of the image is not visible. the image in the scroll view is not scrolling.

You can custom Behaviors for Image to achieve this function.

Create a custom behavior class, MultiTouchBehavior.cs :

public class MultiTouchBehavior : Behavior<View>
{
    #region Fields

    private double _currentScale = 1, _startScale = 1, _xOffset, _yOffset;

    private PinchGestureRecognizer _pinchGestureRecognizer;

    private PanGestureRecognizer _panGestureRecognizer;

    private ContentView _parent;

    private View _associatedObject;

    #endregion

    /// <summary>
    /// Occurs when BindingContext is changed: used to initialise the Gesture Recognizers.
    /// </summary>
    /// <param name="sender">The sender object.</param>
    /// <param name="e">The event parameters.</param>
    private void AssociatedObjectBindingContextChanged(object sender, EventArgs e)
    {
        _parent = _associatedObject.Parent as ContentView;
        _parent?.GestureRecognizers.Remove(_panGestureRecognizer);
        _parent?.GestureRecognizers.Add(_panGestureRecognizer);
        _parent?.GestureRecognizers.Remove(_pinchGestureRecognizer);
        _parent?.GestureRecognizers.Add(_pinchGestureRecognizer);
    }

    /// <summary>
    /// Cleanup the events.
    /// </summary>
    private void CleanupEvents()
    {
        _pinchGestureRecognizer.PinchUpdated -= OnPinchUpdated;
        _panGestureRecognizer.PanUpdated -= OnPanUpdated;
        _associatedObject.BindingContextChanged -= AssociatedObjectBindingContextChanged;
    }

    /// <summary>
    /// Initialise the events.
    /// </summary>
    private void InitializeEvents()
    {
        CleanupEvents();
        _pinchGestureRecognizer.PinchUpdated += OnPinchUpdated;
        _panGestureRecognizer.PanUpdated += OnPanUpdated;
        _associatedObject.BindingContextChanged += AssociatedObjectBindingContextChanged;
    }

    /// <summary>
    /// Initialise the Gesture Recognizers.
    /// </summary>
    private void InitialiseRecognizers()
    {
        _pinchGestureRecognizer = new PinchGestureRecognizer();
        _panGestureRecognizer = new PanGestureRecognizer();
    }

    /// <summary>
    /// Occurs when Behavior is attached to the View: initialises fields, properties and events.
    /// </summary>
    protected override void OnAttachedTo(View associatedObject)
    {
        InitialiseRecognizers();
        _associatedObject = associatedObject;
        InitializeEvents();

        base.OnAttachedTo(associatedObject);
    }

    /// <summary>
    /// Occurs when Behavior is detached from the View: cleanup fields, properties and events.
    /// </summary>
    protected override void OnDetachingFrom(View associatedObject)
    {
        CleanupEvents();

        _parent = null;
        _pinchGestureRecognizer = null;
        _panGestureRecognizer = null;
        _associatedObject = null;

        base.OnDetachingFrom(associatedObject);
    }

    /// <summary>
    /// Implements Pan/Translate.
    /// </summary>
    /// <param name="sender">The sender object.</param>
    /// <param name="e">The event parameters.</param>
    private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {
        if (_parent == null)
        {
            return;
        }

        if (!IsTranslateEnabled)
        {
            return;
        }

        switch (e.StatusType)
        {
            case GestureStatus.Running:
                _parent.Content.TranslationX = _xOffset + e.TotalX;
                _parent.Content.TranslationY = _yOffset + e.TotalY;
                break;

            case GestureStatus.Completed:
                _xOffset = _parent.Content.TranslationX;
                _yOffset = _parent.Content.TranslationY;
                break;
        }
    }

    /// <summary>
    /// Implements Pinch/Zoom.
    /// </summary>
    /// <param name="sender">The sender object.</param>
    /// <param name="e">The event parameters.</param>
    private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        if (_parent == null)
        {
            return;
        }

        if (!IsScaleEnabled)
        {
            return;
        }

        switch (e.Status)
        {
            case GestureStatus.Started:
                _startScale = _parent.Content.Scale;
                _parent.Content.AnchorX = 0;
                _parent.Content.AnchorY = 0;

                break;

            case GestureStatus.Running:
                _currentScale += (e.Scale - 1) * _startScale;
                _currentScale = Math.Max(1, _currentScale);

                var renderedX = _parent.Content.X + _xOffset;
                var deltaX = renderedX / _parent.Width;
                var deltaWidth = _parent.Width / (_parent.Content.Width * _startScale);
                var originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

                var renderedY = _parent.Content.Y + _yOffset;
                var deltaY = renderedY / _parent.Height;
                var deltaHeight = _parent.Height / (_parent.Content.Height * _startScale);
                var originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

                var targetX = _xOffset - (originX * _parent.Content.Width) * (_currentScale - _startScale);
                var targetY = _yOffset - (originY * _parent.Content.Height) * (_currentScale - _startScale);

                _parent.Content.TranslationX = targetX.Clamp(-_parent.Content.Width * (_currentScale - 1), 0);
                _parent.Content.TranslationY = targetY.Clamp(-_parent.Content.Height * (_currentScale - 1), 0);

                _parent.Content.Scale = _currentScale;

                break;

            case GestureStatus.Completed:
                _xOffset = _parent.Content.TranslationX;
                _yOffset = _parent.Content.TranslationY;

                break;
        }
    }

    /// <summary>
    /// Initialize the behavior when OnAppearing is executed.
    /// </summary>
    public void OnAppearing()
    {
        AssociatedObjectBindingContextChanged(_associatedObject, null);
    }

    #region IsScaleEnabled property

    /// <summary>
    /// Identifies the <see cref="IsScaleEnabledProperty" /> property.
    /// </summary>
    public static readonly BindableProperty IsScaleEnabledProperty =
        BindableProperty.Create<MultiTouchBehavior, bool>(w => w.IsScaleEnabled, default(bool));

    /// <summary>
    /// Identifies the <see cref="IsScaleEnabled" /> dependency / bindable property.
    /// </summary>
    public bool IsScaleEnabled
    {
        get { return (bool)GetValue(IsScaleEnabledProperty); }
        set { SetValue(IsScaleEnabledProperty, value); }
    }

    #endregion

    #region IsTranslateEnabled property

    /// <summary>
    /// Identifies the <see cref="IsTranslateEnabledProperty" /> property.
    /// </summary>
    public static readonly BindableProperty IsTranslateEnabledProperty =
        BindableProperty.Create<MultiTouchBehavior, bool>(w => w.IsTranslateEnabled, default(bool));

    /// <summary>
    /// Identifies the <see cref="IsTranslateEnabled" /> dependency / bindable property.
    /// </summary>
    public bool IsTranslateEnabled
    {
        get { return (bool)GetValue(IsTranslateEnabledProperty); }
        set { SetValue(IsTranslateEnabledProperty, value); }
    }

    #endregion
}

Add a DoubleExtensions.cs which used in MultiTouchBehavior.cs :

public static class DoubleExtensions
{
    public static double Clamp(this double self, double min, double max)
    {
        return Math.Min(max, Math.Max(self, min));
    }
}

Finally , in Xmal add two Button here:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:behaviors="clr-namespace:MultiTouch.Behaviors"
             x:Class="MultiTouch.MainPage">

    <StackLayout>
        <ContentView >
                <Image x:Name="MyImage" Source="desert.jpg">
                    <Image.Behaviors>
                        <behaviors:MultiTouchBehavior IsScaleEnabled="True" IsTranslateEnabled="True" />
                    </Image.Behaviors>
                </Image>
        </ContentView>

        <Button Text="ZoomIn" Clicked="ZoomIn_Clicked"/>
        <Button Text="ZoomOut" Clicked="ZoomOut_Clicked"/>

    </StackLayout>

</ContentPage>

Button methods:

private void ZoomIn_Clicked(object sender, System.EventArgs e)
{
    var currentScale = MyImage.Scale;

    if (currentScale >= 1 && currentScale < 5)
    {
        MyImage.Scale = currentScale + 0.25;
    }
}

private void ZoomOut_Clicked(object sender, System.EventArgs e)
{
    var currentScale = MyImage.Scale;

    if (currentScale >= 1 && currentScale < 5)
    {
        MyImage.Scale = currentScale - 0.25;
    }
}

在此处输入图片说明 在此处输入图片说明

Here is the Sample link .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM