在 WP8.1 应用程序中滚动和缩放图像时出现问题

Problems Scrolling and Zooming an Image in an WP8.1 App

我在 Windows Phone 8.1 (WinRT) 应用程序中遇到 ScrollViewer 问题。基本上,我想要实现的是使用 FileOpenPicker 检索图像,将图像裁剪为固定比例(正方形)格式,同时让用户 select 图像的一部分和缩放级别,然后在我的应用程序中使用该图像。 与 "People" 应用程序中的功能一样完美,您可以在其中向联系人添加图像,但如果我能以某种方式让它在没有 ScrollView 的情况下工作,我会接受更少太古怪了

这是我尝试过的变体之一:

<ScrollViewer x:Name="SelectedImageScrollViewer"
    ZoomMode="Enabled"
    HorizontalScrollBarVisibility="Auto"
    VerticalScrollBarVisibility="Auto"
    Height="300"
    Width="300" >
    <Image x:Name="SelectedImage"
        Source="{Binding SelectedImage}"
        MinHeight="300"
        MinWidth="300" />
</ScrollViewer>

在代码隐藏中(在构造函数中):

if (SelectedImage.ActualHeight > SelectedImage.ActualWidth) {
    SelectedImage.Width = SelectedImageScrollViewer.ViewportWidth;
}
else {
    SelectedImage.Height = SelectedImageScrollViewer.ViewportHeight;
}

就像我说的,这不是真的有效,而且有几个问题:

  1. ScrollViews 内置了这种 "rubber band" 过度滚动功能。虽然我同意平台统一性,但在这里它没有帮助,而且提到的 "People" 应用程序没有也没有。
  2. 当用户缩放超过 MaxZoomLevel 时,缩放不仅会停止,而且图像会漂移并在释放后快速返回 - 这不是很好的用户体验。
  3. 图片可以小于裁剪框。应该不可能将缩放级别降低到图像未填满视口的程度。
  4. ScrollView没有显示图片的中心。

如何解决这些问题,裁剪和缩放图像的最佳方法是什么?如果它像在 Silverlight(照片选择器)中一样作为 SDK 的一部分提供,那就太好了。

以下解决方案提供了相当不错的用户体验。关于问题列表:

  1. 显然无法使用基本的 ScrollViewer.
  2. 解决
  3. 将 MaxZoomFactor 增加到足够大可以让用户不太可能发现问题。
  4. 将图像的较小尺寸设置为裁剪框大小后,MinZoomFactor 为 1 可确保图像始终填满框架。
  5. ScrollView的偏移量可以在后面的代码中设置。

IsScrollInertiaEnabledIsZoomInertiaEnabled 设置为 false 可消除滚动缩放时的一些不稳定行为。图片宽度和高度在 SelectedImage_SizeChanged 中设置,因为初始实际尺寸在构造函数中不可用(在呈现页面之前)。

<ScrollViewer Grid.Row="1"
              x:Name="SelectedImageScrollViewer"
              ZoomMode="Enabled"
              IsScrollInertiaEnabled="False"
              IsZoomInertiaEnabled="False"
              HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto"
              Height="300"
              Width="300"
              MinZoomFactor="1.0"
              MaxZoomFactor="10.0">
    <Image x:Name="SelectedImage"
           Source="{Binding SelectedImage}"
           HorizontalAlignment="Center"
           SizeChanged="SelectedImage_SizeChanged" />
</ScrollViewer>

private void SelectedImage_SizeChanged(object sender, SizeChangedEventArgs e) {
    // Here the proportions of the image are known and the initial size can be set
    // to fill the cropping frame depending on the orientation of the image.

    if (!_imageProportionsSet) {
        if (SelectedImage.ActualWidth != 0) {

            double actualHeight = SelectedImage.ActualHeight;
            double actualWidth = SelectedImage.ActualWidth;
            double viewPortWidth = SelectedImageScrollViewer.ViewportWidth;
            double viewPortHeight = SelectedImageScrollViewer.ViewportHeight;

            if (actualHeight > actualWidth) {
                SelectedImage.Width = viewPortWidth;
                double yOffset = (actualHeight - actualWidth) * viewPortWidth / actualHeight;
                SelectedImageScrollViewer.ChangeView(0, yOffset, 1);
            }
            else {
                SelectedImage.Height = viewPortHeight;
                double xOffset = (actualWidth - actualHeight) * viewPortHeight / actualWidth;
                SelectedImageScrollViewer.ChangeView(xOffset, 0, 1);
            }

            // Do this only once.
            _imageProportionsSet = true;
        }
    }
}

这是可行的。如果您发现任何问题,请不要犹豫发表评论或提供改进的答案。