2009-12-09 25 views
2

Est-il possible de transalte/faire pivoter/mettre à l'échelle des articles sans ScatterView? Je veux manipuler des éléments qui peuvent être sur d'autres éléments comme un bouton, une liste ou un contrôle personnalisé qui devrait être statique. Quand je les ajoute à un ScatterView, ils deviennent tous ScatterViewItems ce qui n'est pas l'effet désiré.Développement de surface: Traduire/Tourner/Échelle des articles sans ScatterView

Répondre

0

oui, vous pouvez utiliser de la ManipulationProcessor qui viennent avec l'API

4

expansion un peu sur la réponse de Mark ...

Oui, vous pouvez utiliser de l'API de manipulation et d'inertie pour ce faire, voir ce overview page .

Un temps, j'ai créé mon propre contrôle de ScatterView très basique qui essentiellement fait ce que ScatterView fait, mais avec les limitations suivantes:

  • Un seul enfant, il fonctionne plus comme une frontière
  • Aucun défaut aspect visuel ou d'un comportement particulier de l'élément enfant comme SV ne

un problème qui m'a frappé tout en développant ceci est que vous devez faire votre contrôle conteneur occupent une superficie plus grande que l'enfant réel. Sinon, vous ne pourrez pas capturer de manière fiable les événements de contact lorsque les doigts sont à l'extérieur de votre objet manipulé. Ce que j'ai fait était de faire mon conteneur en plein écran (1024x768) et être transparent et cela fonctionne bien pour mon cas.

Pour la manipulation elle-même, vous utilisez une instance du Affine2DManipulationProcessor class. Cette classe nécessite que vous commenciez la manipulation et ensuite elle vous nourrira constamment avec l'événement delta (Affine2DManipulationDelta).

Si vous voulez que votre manipulation ait un comportement plus réel après que l'utilisateur ait libéré ses doigts, vous utiliserez le Affine2DInertiaProcessor class qui fonctionne de la même manière que le processeur de manipulation. La configuration de base est que dès que le processeur de manipulation est terminé (doigts libérés par l'utilisateur), vous dites au processeur d'inertie de démarrer.

Let look à un code :) Voici ma méthode d'installation dans ma classe de conteneurs:

private void InitializeManipulationInertiaProcessors() 
{ 
    manipulationProcessor = new Affine2DManipulationProcessor(
     Affine2DManipulations.TranslateY | Affine2DManipulations.TranslateX | 
     Affine2DManipulations.Rotate | Affine2DManipulations.Scale, 
     this); 
    manipulationProcessor.Affine2DManipulationCompleted += new EventHandler<Affine2DOperationCompletedEventArgs>(processor_Affine2DManipulationCompleted); 
    manipulationProcessor.Affine2DManipulationDelta += new EventHandler<Affine2DOperationDeltaEventArgs>(processor_Affine2DManipulationDelta); 
    inertiaProcessor = new Affine2DInertiaProcessor(); 
    inertiaProcessor.Affine2DInertiaDelta += new EventHandler<Affine2DOperationDeltaEventArgs>(processor_Affine2DManipulationDelta); 
} 

Pour commencer tout, je piège ContactDown dans ma classe de conteneurs:

protected override void OnContactDown(ContactEventArgs e) 
{ 
    base.OnContactDown(e); 
    e.Contact.Capture(this); 
    // Tell the manipulation processor what contact to track and it will 
    // start sending manipulation delta events based on user motion. 
    manipulationProcessor.BeginTrack(e.Contact); 
    e.Handled = true; 
} 

C'est tout, maintenant asseyez-vous et laissez le processeur de manipulation faire son travail. Chaque fois qu'il a de nouvelles données, il va augmenter l'événement delta (arrive plusieurs fois/seconde pendant que l'utilisateur bouge les doigts). Notez que c'est à vous, en tant que consommateur du processeur, de faire quelque chose avec les valeurs. Il ne vous dira que des choses comme "l'utilisateur a appliqué une rotation de X degrés" ou "l'utilisateur a déplacé le doigt X, Y pixels". Ce que vous faites habituellement est de transmettre ces valeurs à rendertransforms pour montrer à l'utilisateur ce qui s'est passé.

Dans mon cas, mon objet enfant a trois formats de rendu codés en dur: "translate", "rotate" et "scale" que je mets à jour avec les valeurs du processeur.Je fais aussi quelques vérifications limite pour vous assurer que l'objet ne se déplace pas en dehors de la surface ou mis à l'échelle trop grande ou trop petite:

/// <summary> 
/// This is called whenever the manipulator or the inertia processor has calculated a new position 
/// </summary> 
/// <param name="sender">The processor who caused the change</param> 
/// <param name="e">Event arguments containing the calculations</param> 
void processor_Affine2DManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e) 
{    
    var x = translate.X + e.Delta.X; 
    var y = translate.Y + e.Delta.Y; 
    if (sender is Affine2DManipulationProcessor) 
    { 
     // Make sure we don't move outside the screen 
     // Inertia processor does this automatically so only adjust if sender is manipulation processor 
     y = Math.Max(0, Math.Min(y, this.ActualHeight - box.RenderSize.Height)); 
     x = Math.Max(0, Math.Min(x, this.ActualWidth - box.RenderSize.Width)); 
    } 
    translate.X = x; 
    translate.Y = y; 
    rotate.Angle += e.RotationDelta; 
    var newScale = scale.ScaleX * e.ScaleDelta; 
    Console.WriteLine("Scale delta: " + e.ScaleDelta + " Rotate delta: " + e.RotationDelta); 
    newScale = Math.Max(0.3, Math.Min(newScale, 3)); 
    scale.ScaleY = scale.ScaleX = newScale; 
} 

Une chose à noter ici est que la manipulation et le processeur d'inertie utilise le même rappel pour les événements delta.

La dernière pièce du puzzle est lorsque l'utilisateur relâche le doigt et je veux commencer le processeur d'inertie:

/// <summary> 
/// This is called when the manipulator has completed (i.e. user released contacts) and we let inertia take over movement to make a natural slow down 
/// </summary> 
void processor_Affine2DManipulationCompleted(object sender, Affine2DOperationCompletedEventArgs e) 
{ 
    inertiaProcessor.InitialOrigin = e.ManipulationOrigin; 

    // Set the deceleration rates. Smaller number means less friction (i.e. longer time before it stops) 
    inertiaProcessor.DesiredAngularDeceleration = .0010; 
    inertiaProcessor.DesiredDeceleration = .0010; 
    inertiaProcessor.DesiredExpansionDeceleration = .0010; 
    inertiaProcessor.Bounds = new Thickness(0, 0, this.ActualWidth, this.ActualHeight); 
    inertiaProcessor.ElasticMargin = new Thickness(20); 

    // Set the initial values. 
    inertiaProcessor.InitialVelocity = e.Velocity; 
    inertiaProcessor.InitialExpansionVelocity = e.ExpansionVelocity; 
    inertiaProcessor.InitialAngularVelocity = e.AngularVelocity; 

    // Start the inertia. 
    inertiaProcessor.Begin(); 
}