简体   繁体   中英

Xamarin MVVM image viewer with zoom and pan

I have a Xamarin MVVM class that displays a full page image. The code is shown below. The single tap simply closes the view. My question is how to implement the pan or zoom. The only things that I can find are written for Xamarin Forms and I can't figure out how to adapt them to MVVM. Thanks.

<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage x:TypeArguments="viewModels:ImageViewModel"
                  xmlns="http://xamarin.com/schemas/2014/forms"
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                  xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
                  xmlns:viewModels="clr-namespace:BLE.Client.ViewModels;assembly=BLE.Client"
                  x:Class="BLE.Client.Pages.ImagePage" Title="View Image">
   <Grid>
      <Grid.RowDefinitions>
         <RowDefinition Height="*"></RowDefinition>
      </Grid.RowDefinitions>
      <StackLayout Grid.Row="0" Orientation="Horizontal" >
         <Image x:Name="WaypointImage" Source="{Binding MyImage}" HorizontalOptions="FillAndExpand">
           <Image.GestureRecognizers>
              <TapGestureRecognizer   Command="{Binding TapCommand}"/>
              <PinchGestureRecognizer Command="{Binding PinchCommand}"/>
              <PanGestureRecognizer   Command="{Binding PanCommand}"/>
           </Image.GestureRecognizers>
         </Image>
      </StackLayout>
  </Grid>
</views:MvxContentPage>


using System;
using System.Windows.Input;
using Xamarin.Forms;
using Acr.UserDialogs;
using MvvmCross;
using MvvmCross.ViewModels;
using MvvmCross.Navigation;
using Plugin.BLE.Abstractions.Contracts;

namespace BLE.Client.ViewModels
{
    public class ImageViewModel : BaseViewModel
    {
       private ImageSource _myImage;
       public ImageSource MyImage
       {
          get => _myImage;
          set
          {
             _myImage = value;
             RaisePropertyChanged(() => MyImage);
          }
       }

   private readonly IUserDialogs _userDialogs;
   private readonly IMvxNavigationService _navigation;

   public String _waypoint;
   public Waypoint waypoint;

   public ICommand tapCommand;
   public ICommand TapCommand {
      get { return tapCommand; }
   }

   public ICommand pinchCommand;
   public ICommand PinchCommand {
      get { return pinchCommand; }
   }

   public ICommand panCommand;
   public ICommand PanCommand {
      get { return panCommand; }
   }

   public ImageViewModel(IAdapter adapter, IUserDialogs userDialogs) : base(adapter)
   {
      _userDialogs = userDialogs;
      _navigation = Mvx.IoCProvider.Resolve<IMvxNavigationService>();

      tapCommand   = new Command (OnTapped);
      pinchCommand = new Command (OnPinched);
      panCommand   = new Command (OnPan);
   }

   void OnTapped (object s)  {
      Console.WriteLine($"OnTapped: {s}");
      _navigation.Close(this);
   }

   void OnPinched (object s)  {
      Console.WriteLine($"OnPinched: {s}");
   }

   void OnPan (object s)  {
      Console.WriteLine($"OnPan: {s}");
   }

   public override async void Prepare(MvxBundle parameters)
   {
      base.Prepare(parameters);

      _waypoint = await GetWaypointFromBundleAsync(parameters);
      string[] tags = _waypoint?.Split(' ');
      char[] trimChars = { 'I', 'D', '=' };
      string id = tags[0].TrimStart(trimChars);
      int ID = System.Convert.ToInt32(id);
      waypoint = await Database.GetWaypointAsync(ID);
      MyImage = ImageSource.FromFile(waypoint.FileName);
      Console.WriteLine($"prepare       ID={waypoint.ID} {waypoint.FileName} ");
   }

    public override void ViewAppeared()
   {
      base.ViewAppeared();
      if (_waypoint != null)
      {
         return;
      }
      _navigation.Close(this);
   }

    public override void ViewDisappearing()
   {
      base.ViewDisappearing();
   }

    public override void ViewDisappeared()
   {
      base.ViewDisappeared();
   }
}

}

Update:

I found an even better solution to the one below:

My answer to a pinch and pan question

This is my previous answer that works to a point but I could not get the pinch and pan gestures to trigger:

I have found an MVVM solution that takes advantage of the bindable properties Image: TranslationX, TranslationY, and Scale. Here are the relevant code changes. I tested this by modifying MyImageTranslationX in the OnTapped method and saw that the image shifts to the right.

Now I just need to get the Image.GestureRecognizers (PinchGestureRecognizer and PanGestureRecognizer) working and then add code that I have seen elsewhere to smoothly pan and zoom.

 <Image x:Name="WaypointImage"
         Source="{Binding MyImage}"
         Scale   = "{Binding MyImageScale}"
         TranslationX = "{Binding MyImageTranslationX}"
         TranslationY = "{Binding MyImageTranslationY}"
         HorizontalOptions="FillAndExpand">
    <Image.GestureRecognizers>
      <TapGestureRecognizer   Command="{Binding TapCommand}"/>
      <PinchGestureRecognizer Command="{Binding PinchCommand}"/>
      <PanGestureRecognizer   Command="{Binding PanCommand}"/>
    </Image.GestureRecognizers>
 </Image>

   public double _myImageScale = 1.0;
   public double MyImageScale
   {
      get => _myImageScale;
      set
      {
         _myImageScale = value;
         RaisePropertyChanged(() => MyImageScale);
      }
   }
   public double _myImageTranslationX = 0;
   public double MyImageTranslationX
   {
      get => _myImageTranslationX;
      set
      {
         _myImageTranslationX = value;
         RaisePropertyChanged(() => MyImageTranslationX);
      }
   }
   public double _myImageTranslationY = 0;
   public double MyImageTranslationY
   {
      get => _myImageTranslationY;
      set
      {
         _myImageTranslationY = value;
         RaisePropertyChanged(() => MyImageTranslationY);
      }
   }
   private ImageSource _myImage;
   public ImageSource MyImage
   {
      get => _myImage;
      set
      {
         _myImage = value;
         RaisePropertyChanged(() => MyImage);
      }
   }

   void OnTapped (object s)  {
      Console.WriteLine($"OnTapped: {MyImage}");
      MyImageTranslationX = MyImageTranslationX + 100;
      // _navigation.Close(this);
   }

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