【问题标题】:when i add tap gesture the pinch and pan does not work in xamarin forms当我添加点击手势时,捏和平移在 xamarin 表单中不起作用
【发布时间】:2018-09-20 07:39:11
【问题描述】:

我想创建一个功能来点击并在另一个背景图像上添加一个图钉图像,并且背景图像应该能够缩放和平移这是 XAML 代码,这里捏缩放不起作用但点击事件是工作正常

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:POC"
         xmlns:ui="clr-namespace:Vapolia.Lib.Ui;assembly=XamarinFormsGesture"
         x:Class="POC.MainPage"
         Title="Main Page">
<ScrollView AbsoluteLayout.LayoutFlags="All">
    <local:PinchAndPanContainer>
        <local:PinchAndPanContainer.Content >
            <AbsoluteLayout x:Name="AbsoluteLayoutForImage">
                <Image x:Name="FloorPlanImage" 
                Source="Capture2.png"
                HeightRequest="400"
                IsEnabled="True"
                InputTransparent="True"
                ui:Gesture.TapCommand2="{Binding TapCommand2}"/>//This Property
            </AbsoluteLayout>
        </local:PinchAndPanContainer.Content>
    </local:PinchAndPanContainer>
</ScrollView>

在cs文件中,这个tap命令使用Point中的坐标在绝对布局内添加一个pin图像。

public Command<Point> TapCommand2 => new Command<Point>(point =>
    {
        AddPin(point);
    });

现在,如果我们从上面的代码中删除 ui:Gesture.TapCommand2="{Binding TapCommand2}" 这个属性,那么捏和平移就可以正常工作了。

对于 Tap 事件,我使用了 Vapolia.XamarinFormsGesture NuGet 包,对于捏和平移,我使用了 xamarin 表单手势识别器 谁能帮忙

【问题讨论】:

  • 您好 Siddhant,欢迎来到 StackOverflow,只是想确定您是否尝试在这里实现图像缩放功能?
  • 支持图像缩放和平移功能
  • 使用它并尝试添加指向它的指针,看看它是否有效,以防它让我知道,我会更新我的答案

标签: xamarin xamarin.forms


【解决方案1】:

最近我做了一个类似的功能,最终创建了一个自定义控件,如下所示:

注意:我在课堂上使用了 FFImageLoadings CachedImage,以防您不使用 FFImage,只需将其替换为您的默认 xamarin 表单图像即可。

它具有以下功能:PanSwipe、Zoom 和 DoubleTap 进行缩放。

using System;
using Xamarin.Forms;
using FFImageLoading.Forms;

public class ZoomableImage : CachedImage //In case not using ff image replace this with the Image control
{
    private const double MIN_SCALE = 1;
    private const double MAX_SCALE = 4;
    private const double OVERSHOOT = 0.15;
    private double StartScale, LastScale;
    private double StartX, StartY;

    public ZoomableImage()
    {
        var pinch = new PinchGestureRecognizer();
        pinch.PinchUpdated += OnPinchUpdated;
        GestureRecognizers.Add(pinch);

        var pan = new PanGestureRecognizer();
        pan.PanUpdated += OnPanUpdated;
        GestureRecognizers.Add(pan);

        var tap = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
        tap.Tapped += OnTapped;
        GestureRecognizers.Add(tap);

        Scale = MIN_SCALE;
        TranslationX = TranslationY = 0;
        AnchorX = AnchorY = 0;
    }

    protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
    {
        Scale = MIN_SCALE;
        TranslationX = TranslationY = 0;
        AnchorX = AnchorY = 0;
        return base.OnMeasure(widthConstraint, heightConstraint);
    }

    private void OnTapped(object sender, EventArgs e)
    {
        if (Scale > MIN_SCALE)
        {
            this.ScaleTo(MIN_SCALE, 250, Easing.CubicInOut);
            this.TranslateTo(0, 0, 250, Easing.CubicInOut);
        }
        else
        {
            AnchorX = AnchorY = 0.5; //TODO tapped position
            this.ScaleTo(MAX_SCALE, 250, Easing.CubicInOut);
        }
    }

    private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {
        switch (e.StatusType)
        {
            case GestureStatus.Started:
                StartX = (1 - AnchorX) * Width;
                StartY = (1 - AnchorY) * Height;
                break;
            case GestureStatus.Running:
                AnchorX = Clamp(1 - (StartX + e.TotalX) / Width, 0, 1);
                AnchorY = Clamp(1 - (StartY + e.TotalY) / Height, 0, 1);
                break;
        }
    }

    private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        switch (e.Status)
        {
            case GestureStatus.Started:
                LastScale = e.Scale;
                StartScale = Scale;
                AnchorX = e.ScaleOrigin.X;
                AnchorY = e.ScaleOrigin.Y;
                break;
            case GestureStatus.Running:
                if (e.Scale < 0 || Math.Abs(LastScale - e.Scale) > (LastScale * 1.3) - LastScale)
                { return; }
                LastScale = e.Scale;
                var current = Scale + (e.Scale - 1) * StartScale;
                Scale = Clamp(current, MIN_SCALE * (1 - OVERSHOOT), MAX_SCALE * (1 + OVERSHOOT));
                break;
            case GestureStatus.Completed:
                if (Scale > MAX_SCALE)
                    this.ScaleTo(MAX_SCALE, 250, Easing.SpringOut);
                else if (Scale < MIN_SCALE)
                    this.ScaleTo(MIN_SCALE, 250, Easing.SpringOut);
                break;
        }
    }

    private T Clamp<T>(T value, T minimum, T maximum) where T: IComparable
    {
        if (value.CompareTo(minimum) < 0)
            return minimum;
        else if (value.CompareTo(maximum) > 0)
            return maximum;
        else
            return value;
    }
}

祝你好运, 如有疑问请回复。

【讨论】:

  • 感谢您的帮助,您的代码运行良好,但我需要在图像上添加另一个点击事件以获取点击坐标,为此我正在使用 Vapolia.XamarinFormsGesture nuget 包。当我在 Image 视图中使用这个 ui:Gesture.TapCommand2="{Binding TapCommand2}" 属性时,它有点覆盖其他手势识别器事件。
  • 据我了解,您可以在这里做的是将识别器直接添加到我正在使用的 ontapped 功能中的图像控件中,并且由于您不想要该点击功能,因此您不需要它,这有意义吗?
  • 但问题是这个 - ui:Gesture.TapCommand2="{Binding TapCommand2}" 不是手势识别器,它是一个正在产生问题的命令
  • 嗯,那么您可以将该命令绑定到您的 xaml 中的手势识别器中
  • 我不知道该怎么做。你的意思是 。这对我不起作用
【解决方案2】:

我在我的 MVVM 应用程序中使用了来自 FreakyAli 的解决方案。我刚刚将他的代码作为 .cs 文件添加到 ViewModels 文件夹中,并在我的 XAML 中引用了新类:

<?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" >
      <viewModels:ZoomableImage x:Name="WaypointImage"
             Source="{Binding MyImage}"
             HorizontalOptions="FillAndExpand">
      </viewModels:ZoomableImage>
    </StackLayout>
  </Grid>
</views:MvxContentPage>

C#:

   private ImageSource _myImage;
   public ImageSource MyImage
   {
      get => _myImage;
      set
      {
         _myImage = value;
         RaisePropertyChanged(() => MyImage);
      }
   }

【讨论】:

    猜你喜欢
    • 2017-06-10
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多