1

ScrollViewer在我的 Windows Phone 8.1 (WinRT) 应用程序中苦苦挣扎。基本上,我想要实现的是使用 检索图像FileOpenPicker,将图像裁剪为固定比例(正方形)格式,同时让用户选择图像的一部分和缩放级别,然后在我的应用程序中使用该图像. 完美的功能就像“人物”应用程序中的功能,您可以在其中将图像添加到联系人,但如果我能以某种方式让它工作而 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 内置了这种“橡皮筋”过度滚动功能。虽然我同意平台统一性,但在这里它没有帮助,并且提到的“人”应用程序也没有。
  2. 当用户放大超出 时MaxZoomLevel,缩放不仅会停止,而且图像会漂移并在释放后快速恢复 - 这不是良好的用户体验。
  3. 可以使图像小于裁剪框。不能将缩放级别降低到图像未填充视口的程度。
  4. ScrollView不显示图像的中心。

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

4

1 回答 1

1

以下解决方案提供了相当好的用户体验。关于问题清单:

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

设置IsScrollInertiaEnabled和删除滚动缩放IsZoomInertiaEnabledfalse的一些不稳定行为。设置图像宽度和高度是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;
        }
    }
}

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

于 2015-03-07T23:09:19.363 回答