Как реализовать фотопленку в стиле приложения «Камера» на WP7? - PullRequest
10 голосов
/ 17 июля 2011

У меня много проблем с созданием эффекта, очень похожего на фотопленку в приложении Камера.

Все, что я хочу сделать, это отобразить ряд сеток, каждая из которых имеет те же размеры, что и экран (в книжной или альбомной ориентации). Мне уже приходилось делать что-то хакерское и создавать свойства зависимостей, которые свойства ширины и высоты сетки связывают с , чтобы поддерживать соотношение сторон.

И это отлично работает. Но когда я создаю StackPanel для своей полосы и реализую свою навигацию (или просто увеличиваю масштаб с помощью преобразования z-index), я вижу, что моя StackPanel не может отображать больше, чем размеры экрана (она обрезается до размера только одной сетки) , Я думал, что нашел сообщение, описывающее эту проблему, но не могу найти его сейчас - пожалуйста, отправьте сообщение, если вы знаете, о каком сообщении я думаю, или если вы знаете больше об этом ограничении.

Единственный обходной путь, который я нашел, - это использовать ScrollViewer, который совершенно не соответствует желаемому поведению, но позволяет StackPanel быть шире экрана.

Моя настоящая проблема связана с поведением ScrollViewer - потому что мне нужно переключаться с сетки на сетку (как это делает фотополоска) вместо свободной прокрутки, и, насколько я могу судить, HorizontalOffset не является анимируемым свойством. Я могу заставить его анимироваться, вызывая ScrollToHorizontOffset каждые 15 миллисекунд, в основном реализуя свой собственный эффект замедления вручную. Это похоже на огромный взлом, и поведение очень глючное (либо я не получаю событие ManipulationCompleted каждый раз, когда ожидаю его - в конце каждого действия смахивания), либо встроенная физика инерции ScrollViewer мешает моему эффекту ).

Кто-нибудь знает лучшие обходные пути для проблем, с которыми я столкнулся, или совершенно другой способ получить опыт работы с Photo Camera strip в 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>

1 Ответ

1 голос
/ 26 июля 2011

Оказывается, что описанная мною установка работает довольно хорошо, если я просто не позволяю ScrollViewer манипулировать пользователем напрямую и позиционирую его вручную.Это устраняет физические эффекты, которые вызывали большую часть упомянутой мною глючности.

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

Это немного упрощено для ясности (Iтакже используйте для моего приложения вертикальное перелистывание, и я пропустил анимацию ScrollViewer - вероятно, достойную отдельного поста).

Мне бы хотелось услышать любые улучшения, которые вы можете предложить в этом отношении, или предложенияо лучших способах его реализации в целом.Возможно расширение класса Panel или как пользовательское поведение.Мысли?

...