2015-04-24 20 views
23

amo Androids nuova animazione in cui si tocca un controllo (ListViewItem, pulsante ecc ecc) e lo fa un'animazione pulito come questo:Ripple Effect di Android in WPF

enter image description here

mi chiedo come questo possa essere implementato in modo gradevole a livello globale per tutti i controlli 'cliccabili' in WPF.


Ciò di cui ho bisogno in particolare di aiuto è come devono essere creati i cerchi sul controllo. L'unica cosa che ho pensato era di creare i propri controlli utente per ogni altro controllo (pulsanti, pulsanti radio, ecc.) In cui ho un genitore per l'ellisse e il controllo originale stesso.

<UserControl> 
    <Grid MouseLeftButtonDown="handler"> 
     <Button/> <--- this would be the button which you normally would place 
    </Grid > 
</UserControl> 

E nel handler-method quindi creare un'ellisse sul punto e.GetPosition(handler) utilizzando il margine-properties e poi animare. Questa soluzione sarebbe lavoro. Ma sarebbe una seccatura fare questo per ogni controllo su cui vorrei l'effetto a catena. Fondamentalmente qualcosa di simile:

void handler(object sender, MouseButtonEventArgs e) 
{ 
    Grid parent = (Grid)sender; 
    Ellipse ellipse = new Ellipse(); 
    ellipse.Height = 10; // would be animated 
    ellipse.Width = 10; // would be animated 

    Point p = e.GetPosition(parent); 

    ellipse.Margin = new Thickness(p.X, p.Y, 0, 0); 

    parent.Children.Add(ellipse); 

    // do the animation parts to later remove the ellipse 
} 

C'è un pulitore, modo più espandibile per posizionare ellissi sui miei comandi diversi dal modo in cui ho in precedenza dimostrato dal momento che non tutti i controlli supportano avere figli?

+1

Il modo in cui di solito funziona è che si presenti il ​​codice che avete tentato, ma hanno problemi con e vi diciamo dove hai bisogno di aiuto. In questo caso la domanda è così genericamente scritta da essere impossibile da aiutarti. Prova qualcosa, quando ricevi un errore, posta una domanda. – paqogomez

+1

@paqogomez OK. Mi dispiace e aggiornerò questa domanda. – Tokfrans

+6

Questo ha avviato una discussione [sulla meta] (http://meta.stackoverflow.com/questions/291399/is-there-really-a-universal-code-requirement). –

risposta

13

UPDATE: Questo problema è stato così interessante per me che l'ho implementato. Puoi trovarlo sulla mia pagina Github: https://github.com/Domysee/WpfCustomControls. Esistono più controlli personalizzati, quello che stai cercando è RippleEffectDecorator.


Ora spiego quello che ho fatto:

ho creato un controllo personalizzato che eredita da ContentControl, RippleEffectDecorator. Definisce una proprietà di dipendenza aggiuntiva HighlightBackground, che viene utilizzata per lo sfondo dopo aver fatto clic sull'elemento.

Il ControlTemplate di RippleEffectDecorator è costituito da una griglia, un'ellisse e un ContentPresenter.

<ControlTemplate TargetType="{x:Type l:RippleEffectDecorator}"> 
    <Grid x:Name="PART_grid" ClipToBounds="True" Background="{TemplateBinding Background}" 
      Width="{Binding ElementName=PART_contentpresenter, Path=ActualWidth}" 
      Height="{Binding ElementName=PART_contentpresenter, Path=ActualHeight}"> 
     <Ellipse x:Name="PART_ellipse" 
         Fill="{Binding Path=HighlightBackground, RelativeSource={RelativeSource TemplatedParent}}" 
         Width="0" Height="{Binding Path=Width, RelativeSource={RelativeSource Self}}" 
         HorizontalAlignment="Left" VerticalAlignment="Top"/> 

     <ContentPresenter x:Name="PART_contentpresenter" /> 
    </Grid> 
</ControlTemplate> 

ho usato una griglia al posto di un bordo in modo che io possa aggiungere più elementi figlio (necessari che Ellisse e ContentPresenter possono sovrapporsi). L'ellisse lega la sua proprietà Height alla sua larghezza, in modo che sia sempre un cerchio.

Ora per la parte importante: l'animazione.

La griglia definisce nelle sue risorse uno storyboard, che viene riprodotto su ogni evento MouseDown.

<Storyboard x:Key="PART_animation" Storyboard.TargetName="PART_ellipse"> 
    <DoubleAnimation Storyboard.TargetProperty="Width" From="0" /> 
    <ThicknessAnimation Storyboard.TargetProperty="Margin" /> 
    <DoubleAnimation BeginTime="0:0:1" Duration="0:0:0.25" Storyboard.TargetProperty="Opacity" 
       From="1" To="0" /> 
    <DoubleAnimation Storyboard.TargetProperty="Width" To="0" BeginTime="0:0:1.25" Duration="0:0:0" /> 
    <DoubleAnimation BeginTime="0:0:1.25" Duration="0:0:0" Storyboard.TargetProperty="Opacity" To="1" /> 
</Storyboard> 

Lo storyboard anima la proprietà di larghezza dell'ellisse in modo che riempia completamente l'area. Inoltre deve animare il margine, poiché l'ellisse si posiziona rispetto al punto in alto a sinistra (non attorno al centro).

La posizione iniziale dell'ellisse, la sua larghezza di destinazione e la sua posizione nel contenitore per tutto l'effetto devono essere impostate a livello di programmazione. Sovrascrivo il metodo OnApplyTemplate() per aggiungere un gestore eventi all'evento mouse down, che avvia lo storyboard e imposta tutti i valori necessari.

public override void OnApplyTemplate() 
{ 
    base.OnApplyTemplate(); 

    ellipse = GetTemplateChild("PART_ellipse") as Ellipse; 
    grid = GetTemplateChild("PART_grid") as Grid; 
    animation = grid.FindResource("PART_animation") as Storyboard; 

    this.AddHandler(MouseDownEvent, new RoutedEventHandler((sender, e) => 
    { 
     var targetWidth = Math.Max(ActualWidth, ActualHeight) * 2; 
     var mousePosition = (e as MouseButtonEventArgs).GetPosition(this); 
     var startMargin = new Thickness(mousePosition.X, mousePosition.Y, 0, 0); 
     //set initial margin to mouse position 
     ellipse.Margin = startMargin; 
     //set the to value of the animation that animates the width to the target width 
     (animation.Children[0] as DoubleAnimation).To = targetWidth; 
     //set the to and from values of the animation that animates the distance relative to the container (grid) 
     (animation.Children[1] as ThicknessAnimation).From = startMargin; 
     (animation.Children[1] as ThicknessAnimation).To = new Thickness(mousePosition.X - targetWidth/2, mousePosition.Y - targetWidth/2, 0, 0); 
     ellipse.BeginStoryboard(animation); 
    }), true); 
} 

Nota: l'ultimo parametro di AddHandler() determina se si desidera o meno ricevere eventi gestiti. È importante impostarlo su true, perché alcuni UiElements gestiscono gli eventi del mouse (ad esempio Button). In caso contrario, MouseDownEvent non si attiva e pertanto l'animazione non viene eseguita.

Per utilizzarlo è sufficiente aggiungere l'elemento sul quale si desidera avere questo effetto come figlio di RippleEffectDecorator, e lo sfondo trasparente:

<cc:RippleEffectDecorator Background="Green" HighlightBackground="LightGreen"> 
    <Button FontSize="60" Background="Transparent">stuff</Button> 
</cc:RippleEffectDecorator> 

Nota 2: alcuni elementi includono trigger che definiscono il modello su MouseOver (ad es. Pulsante) e quindi nascondere l'effetto. Se non vuoi che devi impostare il modello del pulsante e rimuovere questi trigger. Il modo più semplice è utilizzare Blend, ottenere il modello del pulsante da esso, rimuovere tutti i trigger e aggiungerlo come modello del pulsante.

+2

Questo è fantastico, anche se avrei usato un approccio diverso. Ricordo di aver visto un RippleEffect nella WPFShaderEffectLibrary. Ad ogni modo, sarebbe bello se tu lo inserissi in un Nuget affinché chiunque potesse goderne e riutilizzarlo;) –

+0

Questo è totalmente il modo migliore per farlo. Mi sento così stupido da non aver pensato che potrei avere il controllo personalizzato come genitore invece che figlio dei miei pulsanti - il mio problema sarebbe completamente scomparso se avessi pensato a questo .. Soluzione pulita generale però. – Tokfrans

0

Suggerisco di utilizzare i controlli personalizzati su UserControls per questo. Quasi tutto potrebbe essere gestito in xaml in questo modo. Una volta che hai il tuo controllo in stile, tutto ciò che devi fare è aggiungere un Ellipse e impostare MouseDown o Button. Trigger premuto sul ControlTemplate.Triggers. Quindi l'animazione avrebbe solo bisogno di aumentare l'altezza e la larghezza dell'Ellipse fino a quando l'effetto a catena fosse completato, quindi sfumare Opacità a 0.

Per l'Ellisse assicurarsi di avere la posizione corretta e per lo stesso schema di colori provare un riempimento bianco e opacità di 0,3-5.

Per l'effetto di squillo sul pulsante nell'angolo in alto di aggiungere una seconda ellisse, impostare Riempi su Trasparente e Traccia su Bianco.

2

c'è anche un materiale molto cool WPF biblioteca disegno http://materialdesigninxaml.net/

+0

Questo è un commento, non una risposta. [Dalla recensione] (http://stackoverflow.com/review/late-answers/10541594). – Alex

Problemi correlati