简体   繁体   English

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

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

I'm running into a number of problems creating an effect very similar to the photo strip in the Camera app.在创建与相机应用程序中的照片条非常相似的效果时,我遇到了许多问题。

All I want to do is display a row of grids that each have the same dimensions as the screen (whether in portrait or landscape).我要做的就是显示一行网格,每个网格的尺寸都与屏幕相同(无论是纵向还是横向)。 Already, I had to do something hacky and create dependency properties that the grids width and height properties bind to to maintain the aspect ratio.已经,我不得不做一些 hacky 并创建网格宽度和高度属性绑定的依赖属性以保持纵横比。

And this works fine.这很好用。 But when I create a StackPanel for my strip and implement my navigation (or just zoom back with the z-index transform) I see that my StackPanel can't display larger than the screen dimensions (it's clipped to the size of just one grid).但是当我为我的条创建一个 StackPanel 并实现我的导航(或者只是使用 z-index 变换缩小)时,我看到我的 StackPanel 不能显示大于屏幕尺寸(它被剪裁到只有一个网格的大小) . I thought I found a post describing this issue but I can't find it now - please post if you know which post I'm thinking of or if you know more about this limitation.我以为我找到了描述此问题的帖子,但现在找不到 - 如果您知道我在想哪个帖子或者您对这个限制有更多了解,请发布。

The only workaround I've found is to use a ScrollViewer, which is absolutely not the behavior I want, but it allows the StackPanel to be wider than the screen.我发现的唯一解决方法是使用 ScrollViewer,这绝对不是我想要的行为,但它允许 StackPanel 比屏幕更宽。

My real problem is with the ScrollViewer behavior - because I need to hop from grid to grid (just like the photo strip does) instead of freely scrolling, and as far as I can tell the HorizontalOffset is not an animatable property.我真正的问题是 ScrollViewer 行为 - 因为我需要从一个网格跳到另一个网格(就像照片条一样)而不是自由滚动,而且据我所知,HorizontalOffset 不是动画属性。 I can force it to animate by calling ScrollToHorizontalOffset every 15 milliseconds, basically implementing my own easing effect manually.我可以通过每 15 毫秒调用一次 ScrollToHorizontalOffset 来强制它动画,基本上是手动实现我自己的缓动效果。 This seems like a huge hack, and the behavior is very glitchy (either I'm not getting the ManipulationCompleted event every time I expect it - at the end of every swipe action - or the built in inertia physics of ScrollViewer is interfering with my effect).这似乎是一个巨大的黑客行为,并且行为非常有问题(我每次都没有收到 ManipulationCompleted 事件 - 在每次滑动动作结束时 - 或者 ScrollViewer 的内置惯性物理干扰了我的效果)。

Does anyone know better workarounds for the issues I've run into, or a completely different way to get the experience of the Camera Photo strip in Silverlight?有谁知道我遇到的问题的更好解决方法,或者完全不同的方式来获得 Silverlight 中的相机照片条体验?

I have considered using the Pivot control, but it isn't quite what I want (if I wanted each item to animate out completely before the next one comes in, instead of appearing to be all attached to one strip, there should be less constraining ways to achieve that).我考虑过使用 Pivot 控件,但这并不是我想要的(如果我希望每个项目在下一个进入之前完全动画化,而不是看起来全部附加到一个条带上,应该有更少的约束实现这一目标的方法)。 More importantly, the strip is just one of many effects I want to be able to do dynamically.更重要的是,条带只是我希望能够动态实现的众多效果之一。 I'd like to alternately have a CoolIris-like 3d-tilt, or a FlipPad style page turn.我想交替使用类似 CoolIris 的 3d 倾斜或 FlipPad 样式的翻页。 I believe if I could get my current setup working nicely it would be easy to implement these other effects (as themable transitions).我相信,如果我可以让我当前的设置正常工作,那么实现这些其他效果(作为主题转换)会很容易。 Committing to a control like Pivot won't get me any closer to that vision.致力于像 Pivot 这样的控制不会让我更接近那个愿景。

Here is my XAML:这是我的 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>

It turns out the setup I described works pretty well if I just prevent the ScrollViewer from getting manipulated directly by the user and position it manually.事实证明,如果我只是防止 ScrollViewer 被用户直接操作并手动操作 position,那么我描述的设置效果很好。 This eliminates the physics effects that were causing most of the glitchiness I mentioned.这消除了导致我提到的大部分故障的物理效应。

XAML 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">

Codebehind代码隐藏

    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();
        }
    }

This is simplified a bit for clarity (I also use vertical swipe for something in my app and I omitted how I'm animating the ScrollViewer - probably worthy of it's own post).为了清楚起见,这被简化了一点(我还在我的应用程序中使用了垂直滑动,我省略了我如何为 ScrollViewer 设置动画 - 可能值得它自己的帖子)。

I'd love to hear any improvements you can offer to this, or suggestions on better ways to implement it altogether.我很想听听您对此提供的任何改进,或者关于更好地实现它的建议。 Perhaps extending the Panel Class or as a custom Behavior.也许扩展面板 Class 或作为自定义行为。 Thoughts?想法?

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

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