在ListBox中限制捏合缩放图像

4

我想在我的应用程序中实现捏合缩放。我找到了这篇文章(Silverlight中的正确的捏合缩放),对于单个图像它可以完美地工作。但问题是,我的图像在下面的XAML中作为列表框显示:

<ListBox x:Name="lstImage" Margin="-20,-23,-12,32" Height="709" Width="480">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Image Source="{Binding Path=ImageSource}" VerticalAlignment="Top" Margin="10,12,10,10" Width="640" Height="800">
            </Image>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

我不知道如何实现那个解决方案。先提前感谢。

1个回答

5
创建一个名为PinchZoomBehavior.cs的类,并添加以下代码。
 public class PinchZomBehavior : Behavior<Image>
{
    private double _totalImageScale = 1d;
    private Point _imagePosition = new Point(0, 0);
    private const double MaxImageZoom = 5;
    private Point _oldFinger1;
    private Point _oldFinger2;
    private double _oldScaleFactor;
    private Image _imgZoom;

    protected override void OnAttached()
    {
        _imgZoom = AssociatedObject;

        _imgZoom.RenderTransform = new CompositeTransform { ScaleX = 1, ScaleY = 1, TranslateX = 0, TranslateY = 0 };
        var listener = GestureService.GetGestureListener(AssociatedObject);
        listener.PinchStarted += OnPinchStarted;
        listener.PinchDelta += OnPinchDelta;
        listener.DragDelta += OnDragDelta;
        listener.DoubleTap += OnDoubleTap;
        base.OnAttached();
    }

    #region Pinch and Zoom Logic


    #region Event handlers

    /// <summary>
    /// Initializes the zooming operation
    /// </summary>
    private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
    {
        _oldFinger1 = e.GetPosition(_imgZoom, 0);
        _oldFinger2 = e.GetPosition(_imgZoom, 1);
        _oldScaleFactor = 1;
    }

    /// <summary>
    /// Computes the scaling and translation to correctly zoom around your fingers.
    /// </summary>
    private void OnPinchDelta(object sender, PinchGestureEventArgs e)
    {
        var scaleFactor = e.DistanceRatio / _oldScaleFactor;
        if (!IsScaleValid(scaleFactor))
            return;

        var currentFinger1 = e.GetPosition(_imgZoom, 0);
        var currentFinger2 = e.GetPosition(_imgZoom, 1);

        var translationDelta = GetTranslationDelta(
            currentFinger1,
            currentFinger2,
            _oldFinger1,
            _oldFinger2,
            _imagePosition,
            scaleFactor);

        _oldFinger1 = currentFinger1;
        _oldFinger2 = currentFinger2;
        _oldScaleFactor = e.DistanceRatio;

        UpdateImageScale(scaleFactor);
        UpdateImagePosition(translationDelta);
    }

    /// <summary>
    /// Moves the image around following your finger.
    /// </summary>
    private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
    {
        var translationDelta = new Point(e.HorizontalChange, e.VerticalChange);

        if (IsDragValid(1, translationDelta))
            UpdateImagePosition(translationDelta);
    }

    /// <summary>
    /// Resets the image scaling and position
    /// </summary>
    private void OnDoubleTap(object sender, GestureEventArgs e)
    {
        ResetImagePosition();
    }

    #endregion

    #region Utils

    /// <summary>
    /// Computes the translation needed to keep the image centered between your fingers.
    /// </summary>
    private Point GetTranslationDelta(
        Point currentFinger1, Point currentFinger2,
        Point oldFinger1, Point oldFinger2,
        Point currentPosition, double scaleFactor)
    {
        var newPos1 = new Point(
         currentFinger1.X + (currentPosition.X - oldFinger1.X) * scaleFactor,
         currentFinger1.Y + (currentPosition.Y - oldFinger1.Y) * scaleFactor);

        var newPos2 = new Point(
         currentFinger2.X + (currentPosition.X - oldFinger2.X) * scaleFactor,
         currentFinger2.Y + (currentPosition.Y - oldFinger2.Y) * scaleFactor);

        var newPos = new Point(
            (newPos1.X + newPos2.X) / 2,
            (newPos1.Y + newPos2.Y) / 2);

        return new Point(
            newPos.X - currentPosition.X,
            newPos.Y - currentPosition.Y);
    }

    /// <summary>
    /// Updates the scaling factor by multiplying the delta.
    /// </summary>
    private void UpdateImageScale(double scaleFactor)
    {
        _totalImageScale *= scaleFactor;
        ApplyScale();
    }

    /// <summary>
    /// Applies the computed scale to the image control.
    /// </summary>
    private void ApplyScale()
    {
        ((CompositeTransform)_imgZoom.RenderTransform).ScaleX = _totalImageScale;
        ((CompositeTransform)_imgZoom.RenderTransform).ScaleY = _totalImageScale;
    }

    /// <summary>
    /// Updates the image position by applying the delta.
    /// Checks that the image does not leave empty space around its edges.
    /// </summary>
    private void UpdateImagePosition(Point delta)
    {
        var newPosition = new Point(_imagePosition.X + delta.X, _imagePosition.Y + delta.Y);

        if (newPosition.X > 0) newPosition.X = 0;
        if (newPosition.Y > 0) newPosition.Y = 0;

        if ((_imgZoom.ActualWidth * _totalImageScale) + newPosition.X < _imgZoom.ActualWidth)
            newPosition.X = _imgZoom.ActualWidth - (_imgZoom.ActualWidth * _totalImageScale);

        if ((_imgZoom.ActualHeight * _totalImageScale) + newPosition.Y < _imgZoom.ActualHeight)
            newPosition.Y = _imgZoom.ActualHeight - (_imgZoom.ActualHeight * _totalImageScale);

        _imagePosition = newPosition;

        ApplyPosition();
    }

    /// <summary>
    /// Applies the computed position to the image control.
    /// </summary>
    private void ApplyPosition()
    {
        ((CompositeTransform)_imgZoom.RenderTransform).TranslateX = _imagePosition.X;
        ((CompositeTransform)_imgZoom.RenderTransform).TranslateY = _imagePosition.Y;
    }

    /// <summary>
    /// Resets the zoom to its original scale and position
    /// </summary>
    private void ResetImagePosition()
    {
        _totalImageScale = 1;
        _imagePosition = new Point(0, 0);
        ApplyScale();
        ApplyPosition();
    }

    /// <summary>
    /// Checks that dragging by the given amount won't result in empty space around the image
    /// </summary>
    private bool IsDragValid(double scaleDelta, Point translateDelta)
    {
        if (_imagePosition.X + translateDelta.X > 0 || _imagePosition.Y + translateDelta.Y > 0)
            return false;

        if ((_imgZoom.ActualWidth * _totalImageScale * scaleDelta) + (_imagePosition.X + translateDelta.X) < _imgZoom.ActualWidth)
            return false;

        if ((_imgZoom.ActualHeight * _totalImageScale * scaleDelta) + (_imagePosition.Y + translateDelta.Y) < _imgZoom.ActualHeight)
            return false;

        return true;
    }

    /// <summary>
    /// Tells if the scaling is inside the desired range
    /// </summary>
    private bool IsScaleValid(double scaleDelta)
    {
        return (_totalImageScale * scaleDelta >= 1) && (_totalImageScale * scaleDelta <= MaxImageZoom);
    }

    #endregion
    #endregion
}

将行为附加到图像控件,如下所示

 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

 <Image Stretch="Uniform" Source="{Binding Image}" CacheMode="BitmapCache">
            <i:Interaction.Behaviors>
                <Behaviors:PinchZomBehavior/>
            </i:Interaction.Behaviors>
  </Image>

请记住,在列表控件中应用捏合和缩放并不是一个好的做法。而且这也不是 Windows Phone 遵循的默认约定。例如,Windows Phone 图像库列表中没有可用的捏合和缩放功能。 - Rakesh R Nair
1
如果您对此回复感到满意,请将其标记为答案,这将有助于其他遇到类似问题的人。 - Rakesh R Nair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接