91 votes

Icône animée ActionItem

J'ai été à la recherche partout pour une bonne solution à mon problème et je n'arrive pas à en trouver un encore. J'ai une ActionBar (ActionBarSherlock) avec un menu qui se gonfle à partir d'un fichier XML et que le menu contient un élément et un élément est présenté comme un ActionItem.

menu:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >    
    <item
        android:id="@+id/menu_refresh"       
        android:icon="@drawable/ic_menu_refresh"
        android:showAsAction="ifRoom"
        android:title="Refresh"/>    
</menu>

activité:

[...]
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getSupportMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
  }
[...]

Le ActionItem est affiché avec une icône et le texte n'toutefois, lorsqu'un utilisateur clique sur le ActionItem, je veux l'icône pour démarrer l'animation, plus particulièrement, en tournant en place. L'icône en question est une icône d'actualisation.

Je me rends compte que ActionBar a en charge l'utilisation de vues personnalisées (l'Ajout d'une Action Vue) cependant cette vue personnalisée est élargi pour couvrir l'ensemble de la zone de l'ActionBar et bloque effectivement tout à l'exception de l'icône de l'application, ce qui dans mon cas n'est pas ce que je cherchais.

Donc ma prochaine tentative a été d'essayer d'utiliser AnimationDrawable et de définir mon animation image par image, définissez le drawable comme l'icône de l'élément de menu, puis en onOptionsItemSelected(MenuItem item) obtenir l'icône et de commencer à animer à l'aide de ((AnimationDrawable)item.getIcon()).start(). Toutefois, cela a été un échec. Personne ne sait de toute façon de réaliser cet effet?

175voto

Jake Wharton Points 26095

Vous êtes sur la bonne voie. Voici comment le GitHub Gaug.es de l'application sera mise en œuvre.

D'abord ils définissent une animation XML:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="1000"
    android:interpolator="@android:anim/linear_interpolator" />

Maintenant définir une mise en page pour l'action en vue:

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_action_refresh"
    style="@style/Widget.Sherlock.ActionButton" />

Tout ce que nous devons faire est d'activer ce point de vue chaque fois que l'élément est cliqué:

 public void refresh() {
     /* Attach a rotating ImageView to the refresh item as an ActionView */
     LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     ImageView iv = (ImageView) inflater.inflate(R.layout.refresh_action_view, null);

     Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.clockwise_refresh);
     rotation.setRepeatCount(Animation.INFINITE);
     iv.startAnimation(rotation);

     refreshItem.setActionView(iv);

     //TODO trigger loading
 }

Lorsque le chargement est terminé, il suffit de cesser de l'animation et de clarté de la vue:

public void completeRefresh() {
    refreshItem.getActionView().clearAnimation();
    refreshItem.setActionView(null);
}

Et vous avez terminé!

Quelques autres choses à faire:

  • Cache de l'action à la disposition de l'affichage de l'inflation et de l'animation de l'inflation. Ils sont lents, donc vous ne voulez les faire une fois.
  • Ajouter null des contrôles en completeRefresh()

Voici le pull request sur l'application: https://github.com/github/gauges-android/pull/13/files

16voto

Marek Sebera Points 15987

J'ai travaillé un peu sur la solution à l'aide de ActionBarSherlock, j'ai trouvé ça:

res/layout/indeterminate_progress_action.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="48dp"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingRight="12dp" >

    <ProgressBar
        style="@style/Widget.Sherlock.ProgressBar"
        android:layout_width="44dp"
        android:layout_height="32dp"
        android:layout_gravity="left"
        android:layout_marginLeft="12dp"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/rotation_refresh"
        android:paddingRight="12dp" />

</FrameLayout>

res/layout-v11/indeterminate_progress_action.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center" >

    <ProgressBar
        style="@style/Widget.Sherlock.ProgressBar"
        android:layout_width="32dp"
        android:layout_gravity="left"
        android:layout_marginRight="12dp"
        android:layout_marginLeft="12dp"
        android:layout_height="32dp"
        android:indeterminateDrawable="@drawable/rotation_refresh"
        android:indeterminate="true" />

</FrameLayout>

res/drawable/rotation_refresh.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX="50%"
    android:pivotY="50%"
    android:drawable="@drawable/ic_menu_navigation_refresh"
    android:repeatCount="infinite" >

</rotate>

Code de l'activité (je l'ai en ActivityWithRefresh classe parent)

// Helper methods
protected MenuItem refreshItem = null;  

protected void setRefreshItem(MenuItem item) {
    refreshItem = item;
}

protected void stopRefresh() {
    if (refreshItem != null) {
        refreshItem.setActionView(null);
    }
}

protected void runRefresh() {
    if (refreshItem != null) {
        refreshItem.setActionView(R.layout.indeterminate_progress_action);
    }
}

dans l'activité de création d'éléments de menu

private static final int MENU_REFRESH = 1;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(Menu.NONE, MENU_REFRESH, Menu.NONE, "Refresh data")
            .setIcon(R.drawable.ic_menu_navigation_refresh)
            .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
    setRefreshItem(menu.findItem(MENU_REFRESH));
    refreshData();
    return super.onCreateOptionsMenu(menu);
}

private void refreshData(){
    runRefresh();
    // work with your data
    // for animation to work properly, make AsyncTask to refresh your data
    // or delegate work anyhow to another thread
    // If you'll have work at UI thread, animation might not work at all
    stopRefresh();
}

Et l'icône, c'est - drawable-xhdpi/ic_menu_navigation_refresh.png
drawable-xhdpi/ic_menu_navigation_refresh.png

Cela peut être trouvé dans http://developer.android.com/design/downloads/index.html#action-bar-icon-pack

6voto

Lesik2008 Points 93

En plus de ce que Jake Wharton dit, vous devriez probablement prendre les mesures suivantes pour s'assurer que l'animation s'arrête en douceur et ne pas sauter dès que le chargement terminé.

Tout d'abord, créez une nouvelle valeur booléenne (pour l'ensemble de la classe):

private boolean isCurrentlyLoading;

Trouver la méthode qui démarre votre chargement. Définissez votre booléen à true lorsque l'activité commence à charger.

isCurrentlyLoading = true;

Trouver la méthode qui est démarré lorsque votre chargement est terminé. Au lieu de compensation de l'animation, votre booléen à false.

isCurrentlyLoading = false;

Définir une AnimationListener sur votre animation:

animationRotate.setAnimationListener(new AnimationListener() {

Ensuite, chaque fois que l'animation est exécutée une fois, cela signifie que lorsque votre icône, faites une rotation, vérifier l'état de chargement, et si pas de chargement de plus, l'animation s'arrête.

@Override
public void onAnimationRepeat(Animation animation) {
    if(!isCurrentlyLoading) {
        refreshItem.getActionView().clearAnimation();
        refreshItem.setActionView(null);
    }
}

De cette façon, l'animation ne peut être arrêtée si elle a déjà tourné jusqu'à la fin et sera repris peu de temps ET il n'est pas de chargement plus.

C'est du moins ce que j'ai fait quand j'ai voulu le mettre en œuvre de Jake idée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X