2011-07-16 21 views
10

Tengo varios problemas para crear un efecto muy similar al de la tira de fotos en la aplicación de la cámara.¿Cómo implementar la tira de fotos de la aplicación de la cámara en WP7?

Todo lo que quiero hacer es mostrar una fila de cuadrículas que tienen las mismas dimensiones que la pantalla (ya sea en vertical u horizontal). Ya, tuve que hacer algo hacky y create dependency properties that the grids width and height properties bind to para mantener la relación de aspecto.

Y esto funciona bien. Pero cuando creo un StackPanel para mi tira e implemento mi navegación (o simplemente hago zoom con la transformación z-index) veo que mi StackPanel no puede mostrar dimensiones más grandes que la pantalla (está recortado al tamaño de una sola cuadrícula) . Creo que encontré una publicación que describe este problema pero no puedo encontrarlo ahora, publíquelo si sabe en qué publicación estoy pensando o si conoce más sobre esta limitación.

La única solución que he encontrado es usar ScrollViewer, que no es el comportamiento que quiero, pero permite que el StackPanel sea más ancho que la pantalla.

Mi verdadero problema es con el comportamiento de ScrollViewer, porque necesito saltar de la cuadrícula a la cuadrícula (al igual que la tira de fotos) en lugar de desplazarme libremente, y hasta donde puedo decir que HorizontalOffset no es una propiedad animable. Puedo forzarlo a animar llamando a ScrollToHorizontalOffset cada 15 milisegundos, básicamente implementando mi propio efecto de relajación manualmente. Esto parece un gran truco, y el comportamiento es muy impreciso (o no recibo el evento ManipulationCompleted cada vez que lo espero, al final de cada acción de deslizamiento) o la física de inercia incorporada de ScrollViewer está interfiriendo con mi efecto)

¿Alguien sabe mejores soluciones para los problemas que me he encontrado, o una forma completamente diferente de obtener la experiencia de la tira de la cámara de fotos en Silverlight?

He considerado utilizar el control Pivot, pero no es exactamente lo que quiero (si quería que cada elemento se animara por completo antes de que aparezca el siguiente, en lugar de parecer que está unido a una tira, deberían ser formas menos restrictivas de lograr eso). Más importante aún, la tira es solo uno de los muchos efectos que quiero poder hacer dinámicamente. Me gustaría alternativamente tener un giro de página 3d estilo CoolIris o un giro de página de estilo FlipPad. Creo que si pudiera hacer que mi configuración actual funcionara bien, sería fácil implementar estos otros efectos (como las transiciones personalizables). Comprometerme con un control como Pivot no me acercará más a esa visión.

Aquí es mi 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> 
+0

¿Ha considerado simplemente cambiar el contenido (es decir, propiedad de origen de la imagen) cuando mueve hacia la izquierda o hacia la derecha? Es mucho más simple. –

+0

En realidad no, eso es solo rendirse y realmente no estoy tan lejos. – Subcreation

Respuesta

1

Resulta que la configuración que he descrito funciona bastante bien si sólo evitar que el ScrollViewer de conseguir manipulada directamente por el usuario y la posición de forma manual. Esto elimina los efectos de la física que estaban causando la mayoría de los problemas que mencioné.

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

Esto se simplifica un poco de claridad (también uso golpe vertical para algo en mi aplicación y me omite cómo estoy animando la ScrollViewer - Probablemente digno de su propia publicación).

Me encantaría escuchar cualquier mejora que pueda ofrecer a esto, o sugerencias sobre mejores formas de implementarlo por completo. Tal vez extendiendo la Clase del Panel o como un Comportamiento personalizado. ¿Pensamientos?

Cuestiones relacionadas