一个简单的相册,使用FlipView进行捏合和缩放

本文关键字:FlipView 使用 缩放 一个 简单 | 更新日期: 2023-09-27 17:57:04

我正在尝试使用Flip View创建一个简单的相册(Windows应用商店应用程序)。

我将图像元素嵌入在滚动查看器中。我可以浏览照片,但我想做以下事情。

    图像
  • 应均匀填充屏幕高度[当图像未缩放时]。我得到几个项目的垂直滚动条。当所有图像的高度相同时,我没有这个问题。
  • 当我更改屏幕的方向时,图像的一部分被剪裁在右侧。
  • 当我在页面之间移动时,滚动查看器应该忘记缩放级别(将缩放系数重置为 1)。

这是我现在拥有的代码。我做错了什么?我应该在我的事件处理程序中添加什么来重置我的滚动查看器的缩放系数。

<FlipView 
    Name="MainFlipView"
    Margin="0"
    Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
    Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
    Background="Black">
         <FlipView.ItemTemplate>
              <DataTemplate>
                  <ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
                                Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
                                Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                HorizontalScrollBarVisibility="Auto"
                                VerticalScrollBarVisibility="Auto"
                                MinZoomFactor="0.5"
                                MaxZoomFactor="2.5"
                                Margin="0" >
                       <Image Source="{Binding Path=Image}"
                              Name="MainImage" Stretch="Uniform" />
                  </ScrollViewer>
            </DataTemplate>
        </FlipView.ItemTemplate>
    </FlipView>

一个简单的相册,使用FlipView进行捏合和缩放

user2199147所说的应该解决您的第一个要点,另外两个我必须以编程方式修复,尽管应该注意的是,我还必须使用您必须导入的VisualTreeHelper类,以及帮助我使用帮助程序类的扩展方法。

首先,我必须使用VisualTreeHelper扩展中的一个方法,该方法查找FlipView中任何类型的第一个元素:

private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
    if (parentElement != null)
    {
        var count = VisualTreeHelper.GetChildrenCount(parentElement);
        if (count == 0)
            return null;
        for (int i = 0; i < count; i++)
        {
            var child = VisualTreeHelper.GetChild(parentElement, i);
            if (child != null && child is T)
                return (T)child;
            else
            {
                var result = FindFirstElementInVisualTree<T>(child);
                if (result != null)
                {
                    return result;
                }
            }
        }
    }
    return null;
}

为了进入纵向模式,我为 WindowSizeChanged 添加了一个回调处理程序,只需将翻转视图中的所有ScrollViewer重置回默认值

private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
    //Reset scroll view size
    int count = MainFlipView.Items.Count;
    for(int i = 0; i < count; i++)
    {
        var flipViewItem = MainFlipView.ItemContainerGenerator.ContainerFromIndex((i));
        var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
        if (scrollViewItem is ScrollViewer)
        {
            ScrollViewer scroll = (ScrollViewer)scrollViewItem;
            scroll.Height = e.Size.Height; //Reset width and height to match the new size
            scroll.Width = e.Size.Width;
            scroll.ZoomToFactor(1.0f);//Zoom to default factor
        }
    }
}

然后在构造函数中,您需要Window.Current.SizeChanged += WindowSizeChanged;才能调用回调。

现在,为了将每个ScrollViewer设置回其默认位置,我们执行类似的过程,仅在更改FlipView选择时,我们将ScrollViewer重置回其默认缩放因子

private void FlipViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (sender is FlipView)
    {
        FlipView item = (FlipView)sender;
        var flipViewItem = ((FlipView)sender).ItemContainerGenerator.ContainerFromIndex(((FlipView)sender).SelectedIndex);
        var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
        if (scrollViewItem is ScrollViewer)
        {
            ScrollViewer scroll = (ScrollViewer)scrollViewItem;
            scroll.ScrollToHorizontalOffset(0);
            scroll.ScrollToVerticalOffset(0);
            scroll.ZoomToFactor(1.0f);
        }
    }
}

同样,我们必须在构造函数中调用一个看起来像MainFlipView.SelectionChanged += FlipViewSelectionChanged;

我知道这些方法看起来真的很笨拙和迂回,因为它们确实如此,但它对我有用,我希望这有所帮助。

尝试将高度和宽度绑定从滚动查看器更改为图像。

<FlipView 
    Name="MainFlipView"
    Margin="0"
    Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
    Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
    Background="Black">
         <FlipView.ItemTemplate>
              <DataTemplate>
                  <ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                HorizontalScrollBarVisibility="Auto"
                                VerticalScrollBarVisibility="Auto"
                                MinZoomFactor="0.5"
                                MaxZoomFactor="2.5"
                                Margin="0" >
                       <Image Source="{Binding Path=Image}"
                                      Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
                                      Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
                                      Name="MainImage" Stretch="Uniform" />
                  </ScrollViewer>
            </DataTemplate>
        </FlipView.ItemTemplate>
    </FlipView>

WinRT 的良好做法是:

1) 为 ScrollViewer 创建附加属性,这将更改缩放因子

public class ScrollViewerExtension : DependencyObject
{
    public static readonly DependencyProperty ScrollViewerZoomFactorProperty = DependencyProperty.RegisterAttached(
        "ScrollViewerZoomFactor", typeof(double), typeof(ScrollViewerExtension), new PropertyMetadata(default(double), OnZoomFactorChanged));
    public static void SetScrollViewerZoomFactor(DependencyObject element, double value)
    {
        element.SetValue(ScrollViewerZoomFactorProperty, value);
    }
    public static double GetScrollViewerZoomFactor(DependencyObject element)
    {
        return (double)element.GetValue(ScrollViewerZoomFactorProperty);
    }
    private static void OnZoomFactorChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs args)
    {
        if (depObject is ScrollViewer)
        {
            var scrollViewer = (ScrollViewer)depObject;
            var zoomValue = (double)args.NewValue;
            if (!Double.IsNaN(zoomValue))
                scrollViewer.ZoomToFactor((float)zoomValue);
        }
        else
        {
            throw new Exception("ARE YOU KIDDING ME ? ITS NOT SCROLLVIEWER");
        }
    }
}

2) 转换器翻转视图项目模板

<Style TargetType="FlipViewItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid Width="1040">
                    <ScrollViewer HorizontalAlignment="Stretch"
                                  HorizontalScrollBarVisibility="Auto"
                                  MaxZoomFactor="4"
                                  MinZoomFactor="1"
                                  Tag="{Binding IsSelected}"
                                  VerticalScrollBarVisibility="Auto"
                                  VerticalScrollMode="Auto"
                                  ZoomMode="Enabled"
                                  extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding  RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Converter={StaticResource IsSelectedToZoom}}">
                        <ContentPresenter />
                    </ScrollViewer>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

3)创建转换器,如果未选择项目,则会将滚动查看器缩放因子更改为默认值。

public class IsSelectedToZoomConverter :DependencyObject, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var val = (bool) value;
        return val ? Double.NaN : 1.0;
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

4)FlipView代码将如下所示:

<FlipView x:Name="FlipView"
          Grid.Row="5"
          Width="1040"
          MinHeight="392"
          MaxHeight="600"
          ItemsSource="{Binding Path=CurrentSession.Photos}"
          Visibility="{Binding CurrentSession.HasContent,
                               Converter={StaticResource BoolToVisibility}}">
  <FlipView.ItemContainerStyle>
    <Style TargetType="FlipViewItem">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <Grid Width="1040">
              <ScrollViewer HorizontalAlignment="Stretch"
                            HorizontalScrollBarVisibility="Auto"
                            MaxZoomFactor="4"
                            MinZoomFactor="1"
                            Tag="{Binding IsSelected}"
                            VerticalScrollBarVisibility="Auto"
                            VerticalScrollMode="Auto"
                            ZoomMode="Enabled"
                            extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                                                             Path=IsSelected,
                                                                                             Converter={StaticResource IsSelectedToZoom}}">
                  <ContentPresenter />
              </ScrollViewer>
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    </FlipView.ItemContainerStyle>
    <FlipView.ItemTemplate>
      <DataTemplate>
        <Image HorizontalAlignment="Stretch" Source="{Binding Path=Path}" />
      </DataTemplate>
    </FlipView.ItemTemplate>
</FlipView>

为什么你的FlipViewItemTemplate中有一个ScrollViewer?该模板将用于每个项目,因此对于您添加到项目列表中的每个图像。也就是说,模板中包含 Image 元素就足够了。这至少应该避免比屏幕大的图像的滚动条,因为 Stretch="Uniform" 应该处理大小调整......