1

Je travaille sur un projet dans lequel je souhaite utiliser l'effet Circular Reveal selon le Material Design. Projet a minSDK = 11, donc pour la compatibilité avec les appareils pré-Lollipop, j'utilise cette bibliothèque https://github.com/ozodrukh/CircularRevealUtilisation de setVisibility (View.INVISIBLE) avec la bibliothèque pre Lollipop Circular Reveal

J'ai un fragment avec un FloatingActionButton que, quand on tape dessus, va se transformer en Vignettes, comme décrit ici FAB transformations .

Une fois que la carte est révélée, elle dispose d'un bouton pour inverser l'animation, re-transformant la carte en FAB. Maintenant, mon problème est le suivant: disons qu'un utilisateur tape sur le FAB et que le CardView est révélé. Maintenant, l'utilisateur fait pivoter son appareil, l'activité réinitialise le fragment. Ce que je veux réaliser, c'est que la carte reste visible et visible, alors que le FAB doit être désactivé et invisible. Le problème est que si j'utilise simplement setVisibility(View.INVISIBLE) sur mon FAB il ne fonctionne pas (notez que si j'utilise getVisibility() dessus juste après l'avoir rendu invisible, il me renvoie correctement la valeur 4 == View.INVISIBLE, mais le fab est encore visible). Je dois envelopper l'appel setVisibility(...) dans un postDelayed() avec au moins 50-100 ms de retard pour rendre le fab invisible. Donc, ma question est la suivante: est-ce que je fais les choses correctement ou y at-il une meilleure façon d'accomplir ce que je veux (parce que cela me semble très moche)?

Voici du code. Ceci est ma mise en page XML du fragment:

<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/my_appbar" 
     android:layout_width="match_parent" 
     android:layout_height="@dimen/toolbar_expanded_height" 
     android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> 

     <android.support.design.widget.CollapsingToolbarLayout 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      app:expandedTitleMarginEnd="64dp" 
      app:expandedTitleMarginStart="70dp" 
      app:layout_scrollFlags="scroll|exitUntilCollapsed"> 

      <android.support.v7.widget.Toolbar 
       android:layout_width="match_parent" 
       android:layout_height="?attr/actionBarSize" 
       app:popupTheme="@style/ToolbarPopupTheme" 
       app:layout_collapseMode="pin"/> 
     </android.support.design.widget.CollapsingToolbarLayout> 
    </android.support.design.widget.AppBarLayout> 
    ... 
    <io.codetail.widget.RevealFrameLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <include layout="@layout/my_fragment" /> 
    </io.codetail.widget.RevealFrameLayout> 
    <android.support.design.widget.FloatingActionButton 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_margin="@dimen/fab_margin" 
     app:fabSize="mini" 
     app:layout_anchor="@+id/my_appbar" 
     app:layout_anchorGravity="bottom|left|start" /> 
</android.support.design.widget.CoordinatorLayout> 

Ceci est la mise en page XML du Vignettes inclus:

<android.support.v7.widget.CardView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:card_view="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_margin="16dp" 
    android:layout_gravity="center" 
    card_view:cardCornerRadius="2dp" 
    android:visibility="invisible" 
    android:focusableInTouchMode="true"> 

    <RelativeLayout android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     ... 
     <LinearLayout android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="horizontal" 
      android:gravity="end"> 
      <Button android:layout_height="wrap_content" 
       android:layout_width="wrap_content" 
       android:text="Ok" /> 
      <Button android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Cancel" /> 
     </LinearLayout> 
    </RelativeLayout> 
</android.support.v7.widget.CardView> 

Et voici le code de mon Fragment:

public class MyFragment extends Fragment { 

    private static final String CARD_OPEN_TAG = "CARD_OPEN_TAG"; 

    public static MyFragment newInstance(){ 
     return new MyFragment(); 
    } 

    private int cardOpen; 
    private FloatingActionButton fabAddPublication; 
    private CardView card; 
    private Button cardCancel; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
     final View rootView = inflater.inflate(R.layout.fragment_magazines, container, false); 
     toolbar = (Toolbar) rootView.findViewById(R.id.layout); 

     ... 

     // Initialize view status 
     if (savedInstanceState != null){ 
      cardOpen = savedInstanceState.getInt(CARD_OPEN_TAG); 
     } else { 
      cardOpen = -1; 
     } 

     ... 

     // Get FAB reference 
     fab = (FloatingActionButton) rootView.findViewById(R.id.fab_id); 
     // Get card reference 
     card = (CardView) rootView.findViewById(R.id.card_id); 
     editorPublication.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
       // Using this event because I need my card to be measured to move correctly fab at his center 
       if (cardOpen != -1){ 
        // Move FAB to center of card 
        fab.setTranslationX(coordX); // WORKS 
        fab.setTranslationY(coordY); // WORKS 
        // fab.setVisibility(View.INVISIBLE) -> DOESN'T WORK, fab remain visible on top and at center of my card 
        // Ugly workaround 
        new Handler().postDelayed(new Runnable() { 
         @Override 
         public void run() { 
          // Hide FAB 
          fab.setVisibility(View.INVISIBLE); 
         } 
        }, 50); // Sometimes fails: if device/emulator use too much time to "rotate" screen, fab stay visible 
        // Remove listener 
        ViewTreeObserver obs = card.getViewTreeObserver(); 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 
         obs.removeOnGlobalLayoutListener(this); 
        else obs.removeGlobalOnLayoutListener(this); 
       } 
      } 
     }); 
     if (editorOpen != -1){ 
      fab.setEnabled(false); // WORKS 
      card.setVisibility(View.VISIBLE); // WORKS 
     } 
     // Get editors buttons reference 
     cardCancel = (Button) card.findViewById(R.id.card_cancel_id); 
     // Set FAB listener 
     fab.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       // Explode FAB 
       explodeFab(fab, card); // This method trigger the reveal animation 
       cardOpen = card.getId(); 
      } 
     }); 
     // Set editors button listeners 
     cardCancel.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       // Implode FAB 
       implodeFAB(fab, card); // This card reverts the reveal animation 
     cardOpen = -1; 
      } 
     }); 

     ... 

     return rootView; 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState){ 
     super.onSaveInstanceState(outState); 
     ... 
     outState.putInt(CARD_OPEN_TAG, cardOpen); 
    } 

} 

Répondre

0

I ne pensez pas que ce que vous faites est correct et voici pourquoi:

1.

Cette bibliothèque circulaire que vous utilisez est incompatible avec l'accélération matérielle sur Android 11 à 17 (3.0 à 4.2). Il utilise Canvas.clipPath() - une méthode qui a été implémentée dans les logiciels uniquement jusqu'à Android 4.3. Cela signifie que vous devez désactiver l'accélération matérielle ou que votre application se bloquera sur un appel OpenGL non pris en charge. La meilleure façon de découper des dispositions est d'utiliser Canvas.saveLayer()/restoreLayer(). C'est le seul moyen de prendre en charge tous les périphériques, d'obtenir une image anti-aliasée et de prendre en charge le flux invalide/layout/draw correctement.

2.

En se fondant sur les minuteries et les auditeurs de mise en page pour changer dispositions signifie que quelque chose ne fonctionne pas vraiment pour vous. Chaque changement peut être exécuté directement sans attendre. Vous devez juste trouver le bon endroit pour ce morceau de code. Les temporisateurs peuvent également se déclencher lorsque votre application est en arrière-plan. Cela signifie qu'il va planter en essayant d'accéder à l'interface utilisateur à partir du thread Timer. Peut-être que vous appelez setVisibility (true) quelque part dans le code et c'est pourquoi votre FAB est visible? La définition de la visibilité est correcte et devrait fonctionner sans aucun appel différé. Sauvegardez simplement la visibilité en tant qu'état FAB et restaurez-la après un changement d'orientation.

Si vous souhaitez positionner le FAB au centre de la barre d'outils, placez-les dans un FrameLayout (wrap_content) et positionnez le FAB avec layout_gravity = "center". Cela devrait vous permettre de supprimer l'écouteur de mise en page.

3.

support.CardView est cassé et ne doit pas être utilisé du tout. Il semble et fonctionne un peu différemment sur Lollipop et sur les anciens systèmes. L'ombre est différente, le remplissage est différent, le découpage de contenu ne fonctionne pas sur les appareils pré-Lollipop, etc. C'est pourquoi il est difficile d'obtenir de bons résultats sur toutes les plateformes.

Vous devriez envisager d'utiliser des dispositions simples à cette fin.

4.

Certaines animations sont cool prospectifs, mais difficile à mettre en œuvre, ne donne pas de valeur et deviennent rapidement irritants, car l'utilisateur doit attendre l'animation pour terminer chaque fois qu'il/elle clique le bouton. Je ne dis pas non pour votre cas, mais vous pouvez envisager de supprimer la transformation et d'utiliser un menu déroulant, une feuille de fond, une barre d'outils statique ou une boîte de dialogue à cet effet.

+0

Salut Zielony, merci pour votre temps. Je commence à penser que vous avez raison de supprimer cette animation, surtout parce que je ne suis pas un expert en matière de graphisme. J'utilisais cette librairie car elle prétendait activer cet effet dans les versions Android antérieures à Lollipop et je n'ai rien lu sur les problèmes d'accélération matérielle (ou est-ce que je me trompe encore?). J'utilisais CardView pour montrer un petit formulaire pour créer une nouvelle entrée dans ma base de données (seulement 2 éditiés). Si je décide de remplacer CardView, que me suggérez-vous à cet effet? Un DialogFragment (j'utilise des fragments)? – MatteoBelfiori

+0

Le problème d'accélération matérielle dont je parle a été signalé comme un problème ici: https://github.com/ozodrukh/CircularReveal/issues/27. J'utiliserais une sorte de dialogue là-bas, mais je ne connais pas votre cas et c'est seulement mon opinion. Choisissez ce qui fonctionne le mieux pour vous. – Zielony

+0

Merci Zielony, je pense que je vais aller pour un DialogFragment. – MatteoBelfiori