繁体   English   中英

如何在 WP7 上实现相机应用风格的照片条?

[英]How to implement Camera app style photo strip on WP7?

在创建与相机应用程序中的照片条非常相似的效果时,我遇到了许多问题。

我要做的就是显示一行网格,每个网格的尺寸都与屏幕相同(无论是纵向还是横向)。 已经,我不得不做一些 hacky 并创建网格宽度和高度属性绑定的依赖属性以保持纵横比。

这很好用。 但是当我为我的条创建一个 StackPanel 并实现我的导航(或者只是使用 z-index 变换缩小)时,我看到我的 StackPanel 不能显示大于屏幕尺寸(它被剪裁到只有一个网格的大小) . 我以为我找到了描述此问题的帖子,但现在找不到 - 如果您知道我在想哪个帖子或者您对这个限制有更多了解,请发布。

我发现的唯一解决方法是使用 ScrollViewer,这绝对不是我想要的行为,但它允许 StackPanel 比屏幕更宽。

我真正的问题是 ScrollViewer 行为 - 因为我需要从一个网格跳到另一个网格(就像照片条一样)而不是自由滚动,而且据我所知,HorizontalOffset 不是动画属性。 我可以通过每 15 毫秒调用一次 ScrollToHorizontalOffset 来强制它动画,基本上是手动实现我自己的缓动效果。 这似乎是一个巨大的黑客行为,并且行为非常有问题(我每次都没有收到 ManipulationCompleted 事件 - 在每次滑动动作结束时 - 或者 ScrollViewer 的内置惯性物理干扰了我的效果)。

有谁知道我遇到的问题的更好解决方法,或者完全不同的方式来获得 Silverlight 中的相机照片条体验?

我考虑过使用 Pivot 控件,但这并不是我想要的(如果我希望每个项目在下一个进入之前完全动画化,而不是看起来全部附加到一个条带上,应该有更少的约束实现这一目标的方法)。 更重要的是,条带只是我希望能够动态实现的众多效果之一。 我想交替使用类似 CoolIris 的 3d 倾斜或 FlipPad 样式的翻页。 我相信,如果我可以让我当前的设置正常工作,那么实现这些其他效果(作为主题转换)会很容易。 致力于像 Pivot 这样的控制不会让我更接近那个愿景。

这是我的 XAML:

<Grid x:Name="LayoutRoot" Background="Transparent" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" HorizontalAlignment="Left" VerticalAlignment="Top">
        <ScrollViewer x:Name="SlideScroller" VerticalScrollBarVisibility="Disabled" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" Margin="0,0,0,-31" ScrollViewer.HorizontalScrollBarVisibility="Auto" HorizontalAlignment="Left" VerticalAlignment="Top">
            <StackPanel x:Name="SlidePanel" Orientation="Horizontal" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" VerticalAlignment="Top" HorizontalAlignment="Left">    
                <Grid x:Name="Slide0" Margin="0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" Background="#FFCCCCCC">
                    <Image x:Name="Photo0" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="UniformToFill"/>
                </Grid>
                <Grid x:Name="Slide1" Margin="0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" Background="#FFCCCCCC">
                    <Image x:Name="Photo1" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="UniformToFill"/>
                </Grid>
                <Grid x:Name="Slide2" Margin="0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" Background="#FFCCCCCC">
                    <Image x:Name="Photo2" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="UniformToFill"/>
                </Grid>
            </StackPanel>    
        </ScrollViewer>
    </Grid>

事实证明,如果我只是防止 ScrollViewer 被用户直接操作并手动操作 position,那么我描述的设置效果很好。 这消除了导致我提到的大部分故障的物理效应。

XAML

<ScrollViewer x:Name="SlideScroller" VerticalScrollBarVisibility="Disabled" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" ScrollViewer.HorizontalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top">
            <StackPanel x:Name="SlidePanel" Orientation="Horizontal" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" VerticalAlignment="Top" HorizontalAlignment="Left">
            </StackPanel>
        </ScrollViewer>
<Rectangle x:Name="ScrollInterceptRect" Margin="0,0,0,-31" Width="{Binding RealWidth, ElementName=phoneApplicationPage}" Height="{Binding RealHeight, ElementName=phoneApplicationPage}" HorizontalAlignment="Left" VerticalAlignment="Top">

代码隐藏

    public MainPage()
    {
        InitializeComponent();

        ScrollInterceptRect.MouseLeftButtonUp += new MouseButtonEventHandler(ScrollInterceptRect_MouseLeftButtonUp);
        ScrollInterceptRect.MouseLeftButtonDown += new MouseButtonEventHandler(ScrollInterceptRect_MouseLeftButtonDown);
        ScrollInterceptRect.MouseMove += new MouseEventHandler(ScrollInterceptRect_MouseMove);
    }
    //...
    NavigationIndices navigationIndices = new NavigationIndices();
    readonly double swipeThreshold = 80.0;
    SwipeDirection swipeDirection;
    bool tapCancelled;
    Point swipeDelta;
    Point swipeStartPosition;
    double startScrollOffsetX;
    void SlideScroller_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        swipeStartPosition = e.GetPosition(this);
        startScrollOffsetX = SlideScroller.HorizontalOffset;
    }
    void ScrollInterceptRect_MouseMove(object sender, MouseEventArgs e)
    {
        Point touchPosition = e.GetPosition(this);
        swipeDelta = new Point() { X = swipeStartPosition.X - touchPosition.X, Y = swipeStartPosition.Y - touchPosition.Y };
        SlideScroller.ScrollToHorizontalOffset(startScrollOffsetX + swipeDelta.X);
        // swipe right
        if (swipeDelta.X > swipeThreshold)
        {
            swipeDirection = SwipeDirection.Left;
            tapCancelled = true;
        }
        // swipe left
        else if (swipeDelta.X < -swipeThreshold)
        {
            swipeDirection = SwipeDirection.Right;
            tapCancelled = true;
        }
    }
    void ScrollInterceptRect_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (swipeDirection == SwipeDirection.Left && navigationIndices.X < photos.Count - 1 && photos[navigationIndices.X] != null)
        {
            navigationIndices.X++;
        }
        // only go back when you aren't already at the beginning
        else if (swipeDirection == SwipeDirection.Right && navigationIndices.X > 0)
        {
            navigationIndices.X--;
        }
        if (!tapCancelled)
        {
            // handle tap
        }
        else
        {
            animateScrollViewerToCurrentPhoto();
        }
    }

为了清楚起见,这被简化了一点(我还在我的应用程序中使用了垂直滑动,我省略了我如何为 ScrollViewer 设置动画 - 可能值得它自己的帖子)。

我很想听听您对此提供的任何改进,或者关于更好地实现它的建议。 也许扩展面板 Class 或作为自定义行为。 想法?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM