Menu FAB (Floating Action Button) espandibile della libreria di supporto di Android Design


172

Ora che è disponibile la libreria di supporto per la progettazione di Android, qualcuno sa come implementare il menu Fab ampliato con esso, come il fab sull'app Inbox?

Dovrebbe apparire così:

inserisci qui la descrizione dell'immagine



Ho già controllato tutta la documentazione ma a quanto pare non ci sono segni del menu FAB :(
EkKoZ

8
Puoi dare un'occhiata a questa libreria FloatingActionButton .
Markus Rubey,

3
@MarkusRubey grazie, in realtà è quello che sto usando al momento, è solo che volevo farlo con quello nativo, ma a quanto pare non è ancora possibile.
EkKoZ,

Ci sono molte librerie open source, che potrebbero portare a termine il lavoro.
Dai un'occhiata a

Risposte:


143

Attualmente, non è disponibile alcun widget nella Design Library. L'unico modo per farlo rapidamente e facilmente è usare librerie di terze parti.

Ovviamente puoi farlo anche usando la Design Library, ma sarà un lavoro enorme e richiederà molto tempo. Ho citato alcune utili librerie che possono aiutarti a raggiungere questo obiettivo.

  1. Pulsante galleggiante rapido (wangjiegulu)
  2. Pulsante di azione mobile (clan)
  3. Pulsante di azione mobile (makovkastar)
  4. Pulsante di azione mobile Android (futuresimple)

Sto usando il quarto.


31
bene, l'idea era di farlo con la libreria di design nativo, so che ci sono molte librerie che già fanno questa funzione. grazie per la tua risposta.
EkKoZ,

Hai riscontrato problemi con il quarto? Il mio non viene visualizzato sui dispositivi lollipop +. Anche il colore e il testo della sovrapposizione di sfondo non funzionano
Ajith Memana,

@AjithMemana Nope. La mia app è in produzione per oltre 100.000 utenti e non ho mai avuto problemi come hai già detto.
Aritra Roy,

Potresti fornirmi un link alla tua app? Ho bisogno di qualcosa di simile a quanto mostrato sopra, insieme a uno sfondo traslucido che copre lo schermo quando si fa clic sul pulsante.
Ajith Memana,

2
Come nota, clan e makovkastar non sono più supportati. Ho il sospetto che ciò sia dovuto a miglioramenti nella libreria di design FAB
Honest Objections,

162

Hai un approccio migliore per implementare il menu FAB di animazione senza usare alcuna libreria o per scrivere un enorme codice XML per le animazioni. spero che questo possa aiutare in futuro per qualcuno che ha bisogno di un modo semplice per implementarlo.

Solo usando la animate().translationY()funzione, puoi animare qualsiasi vista su o giù come ho fatto nel mio codice qui sotto, controlla il codice completo in github . Nel caso in cui tu stia cercando lo stesso codice in kotlin, puoi controllare il repository animato del menu FAB di repo code kotlin .

per prima cosa definisci tutti i tuoi FAB nello stesso posto in modo che si sovrappongano, ricorda che il FAB dovrebbe essere che vuoi fare clic e mostrare altri. per esempio:

    <android.support.design.widget.FloatingActionButton
    android:id="@+id/fab3"
    android:layout_width="@dimen/standard_45"
    android:layout_height="@dimen/standard_45"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/standard_21"
    app:srcCompat="@android:drawable/ic_btn_speak_now" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab2"
    android:layout_width="@dimen/standard_45"
    android:layout_height="@dimen/standard_45"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/standard_21"
    app:srcCompat="@android:drawable/ic_menu_camera" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab1"
    android:layout_width="@dimen/standard_45"
    android:layout_height="@dimen/standard_45"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/standard_21"
    app:srcCompat="@android:drawable/ic_dialog_map" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/fab_margin"
    app:srcCompat="@android:drawable/ic_dialog_email" />

Ora nella tua classe Java basta definire tutto il tuo FAB ed eseguire il clic come mostrato di seguito:

 FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab1 = (FloatingActionButton) findViewById(R.id.fab1);
    fab2 = (FloatingActionButton) findViewById(R.id.fab2);
    fab3 = (FloatingActionButton) findViewById(R.id.fab3);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(!isFABOpen){
                showFABMenu();
            }else{
                closeFABMenu();
            }
        }
    });

Usa il animation().translationY()per animare il tuo FAB, preferisco che tu usi l'attributo di questo metodo in DP poiché solo usando un int influirà sulla compatibilità del display con una risoluzione più alta o più bassa. come mostrato di seguito:

 private void showFABMenu(){
    isFABOpen=true;
    fab1.animate().translationY(-getResources().getDimension(R.dimen.standard_55));
    fab2.animate().translationY(-getResources().getDimension(R.dimen.standard_105));
    fab3.animate().translationY(-getResources().getDimension(R.dimen.standard_155));
}

private void closeFABMenu(){
    isFABOpen=false;
    fab1.animate().translationY(0);
    fab2.animate().translationY(0);
    fab3.animate().translationY(0);
}

Ora definisci la dimensione sopra menzionata in res-> valori-> dimens.xml come mostrato di seguito:

    <dimen name="standard_55">55dp</dimen>
<dimen name="standard_105">105dp</dimen>
<dimen name="standard_155">155dp</dimen>

È tutta speranza che questa soluzione possa aiutare le persone in futuro, che sono alla ricerca di una soluzione semplice.

MODIFICATO

Se vuoi aggiungere un'etichetta sul FAB, prendi semplicemente un LinearLayout orizzontale e metti il ​​FAB con textview come etichetta e animi i layout se trovi qualche problema facendo questo, puoi controllare il mio codice di esempio in github, ho gestito tutta la compatibilità con le versioni precedenti problemi in quel codice di esempio. controlla il mio codice di esempio per FABMenu in Github

per chiudere il FAB su Backpress, sovrascrivi onBackPress () come mostrato di seguito:

    @Override
public void onBackPressed() {
    if(!isFABOpen){
        this.super.onBackPressed();
    }else{
        closeFABMenu();
    }
}

Lo screenshot ha anche il titolo con il FAB, perché lo prendo dal mio ingithub app di esempio presente

inserisci qui la descrizione dell'immagine


8
anche l'aggiunta di etichette al menu è anche semplice, devi solo aggiungere il FAB all'interno di un Linearlayout con un po 'di testo come etichetta, e dopo di che animare l'intero layout lineare non dimenticare di nascondere e mostrare il layout lineare all'interno della funzione apri e chiudi
HAXM

1
ma prashant aveva creato xml separati per l'animazione, ma la mia soluzione non ha bisogno di alcun xml aggiuntivo per l'animazione, quindi credi che la mia risposta sia migliore, in quanto non ha bisogno di una riga aggiuntiva di codice per animare la vista.
HAXM,

2
Questa è la risposta migliore. È possibile utilizzare il FAB reale dalla libreria di progettazione e non è così compatibile.
Stephane Mathis,

3
quello che mi è piaciuto anche di questo approccio è che da quando stiamo usando Android FAB, molte delle basi sono già state fatte. ad esempio invece di scrivere da zero il comportamento della vista personalizzata (poiché le librerie non estendono FAB), puoi semplicemente estendere il comportamento fab nativo, che è un enorme gruppo di codice già disponibile
RJFares

1
@droidHeaven fai un framelayout e metti tutto il tuo FAB al suo interno
HAXM,

31
  • Per prima cosa crea i layout del menu nel tuo file xml del layout Activity. Ad esempio un layout lineare con orientamento orizzontale e includere un oggetto TextView per l'etichetta, quindi un pulsante di azione mobile accanto a TextView.

  • Crea i layout del menu secondo le tue necessità e il tuo numero.

  • Crea un pulsante di azione mobile di base e al suo clic cambia la visibilità dei layout di menu.

Si prega di controllare il codice qui sotto per il riferimento e per ulteriori informazioni, controllare il mio progetto da Github

Progetto di checkout da Github

<android.support.constraint.ConstraintLayout
            android:id="@+id/activity_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context="com.app.fabmenu.MainActivity">

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/baseFloatingActionButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="16dp"
                android:layout_marginEnd="16dp"
                android:layout_marginRight="16dp"
                android:clickable="true"
                android:onClick="@{FabHandler::onBaseFabClick}"
                android:tint="@android:color/white"
                app:fabSize="normal"
                app:layout_constraintBottom_toBottomOf="@+id/activity_main"
                app:layout_constraintRight_toRightOf="@+id/activity_main"
                app:srcCompat="@drawable/ic_add_black_24dp" />

            <LinearLayout
                android:id="@+id/shareLayout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="12dp"
                android:layout_marginEnd="24dp"
                android:layout_marginRight="24dp"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:visibility="invisible"
                app:layout_constraintBottom_toTopOf="@+id/createLayout"
                app:layout_constraintLeft_toLeftOf="@+id/createLayout"
                app:layout_constraintRight_toRightOf="@+id/activity_main">

                <TextView
                    android:id="@+id/shareLabelTextView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginRight="8dp"
                    android:background="@drawable/shape_fab_label"
                    android:elevation="2dp"
                    android:fontFamily="sans-serif"
                    android:padding="5dip"
                    android:text="Share"
                    android:textColor="@android:color/white"
                    android:typeface="normal" />


                <android.support.design.widget.FloatingActionButton
                    android:id="@+id/shareFab"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:clickable="true"
                    android:onClick="@{FabHandler::onShareFabClick}"
                    android:tint="@android:color/white"
                    app:fabSize="mini"
                    app:srcCompat="@drawable/ic_share_black_24dp" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/createLayout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="24dp"
                android:layout_marginEnd="24dp"
                android:layout_marginRight="24dp"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:visibility="invisible"
                app:layout_constraintBottom_toTopOf="@+id/baseFloatingActionButton"
                app:layout_constraintRight_toRightOf="@+id/activity_main">

                <TextView
                    android:id="@+id/createLabelTextView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginRight="8dp"
                    android:background="@drawable/shape_fab_label"
                    android:elevation="2dp"
                    android:fontFamily="sans-serif"
                    android:padding="5dip"
                    android:text="Create"
                    android:textColor="@android:color/white"
                    android:typeface="normal" />

                <android.support.design.widget.FloatingActionButton
                    android:id="@+id/createFab"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:clickable="true"
                    android:onClick="@{FabHandler::onCreateFabClick}"
                    android:tint="@android:color/white"
                    app:fabSize="mini"
                    app:srcCompat="@drawable/ic_create_black_24dp" />

            </LinearLayout>

        </android.support.constraint.ConstraintLayout>

Queste sono le animazioni

Animazione di apertura del menu FAB:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
    android:duration="300"
    android:fromXScale="0"
    android:fromYScale="0"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1"
    android:toYScale="1" />
<alpha
    android:duration="300"
    android:fromAlpha="0.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="1.0" />

</set>

Animazione di chiusura del menu FAB:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
    android:duration="300"
    android:fromXScale="1"
    android:fromYScale="1"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="0.0"
    android:toYScale="0.0" />
<alpha
    android:duration="300"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="0.0" />
</set>

Quindi nella mia attività ho semplicemente usato le animazioni sopra per mostrare e nascondere il menu FAB:

Mostra menu Fab:

  private void expandFabMenu() {

    ViewCompat.animate(binding.baseFloatingActionButton).rotation(45.0F).withLayer().setDuration(300).setInterpolator(new OvershootInterpolator(10.0F)).start();
    binding.createLayout.startAnimation(fabOpenAnimation);
    binding.shareLayout.startAnimation(fabOpenAnimation);
    binding.createFab.setClickable(true);
    binding.shareFab.setClickable(true);
    isFabMenuOpen = true;

}

Chiudi menu Fab:

private void collapseFabMenu() {

    ViewCompat.animate(binding.baseFloatingActionButton).rotation(0.0F).withLayer().setDuration(300).setInterpolator(new OvershootInterpolator(10.0F)).start();
    binding.createLayout.startAnimation(fabCloseAnimation);
    binding.shareLayout.startAnimation(fabCloseAnimation);
    binding.createFab.setClickable(false);
    binding.shareFab.setClickable(false);
    isFabMenuOpen = false;

}

Ecco la classe Activity -

package com.app.fabmenu;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.OvershootInterpolator;

import com.app.fabmenu.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

private ActivityMainBinding binding;
private Animation fabOpenAnimation;
private Animation fabCloseAnimation;
private boolean isFabMenuOpen = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    binding = DataBindingUtil.setContentView(this,    R.layout.activity_main);
    binding.setFabHandler(new FabHandler());

    getAnimations();


}

private void getAnimations() {

    fabOpenAnimation = AnimationUtils.loadAnimation(this, R.anim.fab_open);

    fabCloseAnimation = AnimationUtils.loadAnimation(this, R.anim.fab_close);

}

private void expandFabMenu() {

    ViewCompat.animate(binding.baseFloatingActionButton).rotation(45.0F).withLayer().setDuration(300).setInterpolator(new OvershootInterpolator(10.0F)).start();
    binding.createLayout.startAnimation(fabOpenAnimation);
    binding.shareLayout.startAnimation(fabOpenAnimation);
    binding.createFab.setClickable(true);
    binding.shareFab.setClickable(true);
    isFabMenuOpen = true;


}

private void collapseFabMenu() {

    ViewCompat.animate(binding.baseFloatingActionButton).rotation(0.0F).withLayer().setDuration(300).setInterpolator(new OvershootInterpolator(10.0F)).start();
    binding.createLayout.startAnimation(fabCloseAnimation);
    binding.shareLayout.startAnimation(fabCloseAnimation);
    binding.createFab.setClickable(false);
    binding.shareFab.setClickable(false);
    isFabMenuOpen = false;

}


public class FabHandler {

    public void onBaseFabClick(View view) {

        if (isFabMenuOpen)
            collapseFabMenu();
        else
            expandFabMenu();


    }

    public void onCreateFabClick(View view) {

        Snackbar.make(binding.coordinatorLayout, "Create FAB tapped", Snackbar.LENGTH_SHORT).show();

    }

    public void onShareFabClick(View view) {

        Snackbar.make(binding.coordinatorLayout, "Share FAB tapped", Snackbar.LENGTH_SHORT).show();

    }


}

@Override
public void onBackPressed() {

    if (isFabMenuOpen)
        collapseFabMenu();
    else
        super.onBackPressed();
}
}

Ecco gli screenshot

Menu di azione mobile con etichetta Textview nella nuova famiglia di caratteri corsivi di Android

Menu di azione mobile con etichetta Textview nella nuova famiglia di caratteri Roboto di Android



7

Quando ho provato a creare qualcosa di simile al pulsante di azione mobile della posta in arrivo, ho pensato di creare il proprio componente personalizzato.

Sarebbe un semplice layout di frame con altezza fissa (per contenere il menu espanso) contenente il pulsante FAB e altri 3 posizionati sotto il FAB. quando fai clic su FAB, devi semplicemente animare altri pulsanti per tradurre da sotto il FAB.

Ci sono alcune librerie che lo fanno (ad esempio https://github.com/futuresimple/android-floating-action-button ), ma è sempre più divertente se lo crei da solo :)


Spiegazione eccellente! Sto esplorando quella libreria ma ho problemi ad usarla per allineare il FAB tra due viste. Kinda cosa viene chiesto in questa domanda stackoverflow.com/questions/24459352/… . Qualche idea su come farlo? layout_anchore layout_anchorGravitynon funzionano per me
acrespo

La libreria di Futuresimple non consente un'icona unica sul plus che viene automaticamente
impostata

7

Puoi utilizzare la libreria FloatingActionMenu o fare clic qui per un'esercitazione dettagliata. Uscita del tutorial:

inserisci qui la descrizione dell'immagine


Semplice e funziona benissimo. Suggerirei tuttavia di aggiungere i dettagli qui invece di collegare il tutorial nel caso in cui il collegamento si interrompa in futuro. Un'altra cosa, ho appena imparato che la biblioteca non è più in fase di sviluppo, purtroppo.
Ahmed salah,


0

Un'altra opzione per lo stesso risultato con l'animazione ConstraintSet:

favoloso esempio di animazione

1) Metti tutte le viste animate in un layout vincolo

2) Animalo da questo codice (se vuoi qualche effetto in più dipende da te ... questo è solo un esempio)

menuItem1 e menuItem2 è il primo e il secondo FAB nel menu, descriptionItem1 e descriptionItem2 è la descrizione a sinistra del menu, parentConstraintLayout è la radice ConstraintLayout che contiene tutte le viste animate, isMenuOpened è una funzione per modificare la bandiera aperta / chiusa nello stato

Ho inserito il codice di animazione nel file di estensione ma non è necessario.

fun FloatingActionButton.expandMenu(
    menuItem1: View,
    menuItem2: View,
    descriptionItem1: TextView,
    descriptionItem2: TextView,
    parentConstraintLayout: ConstraintLayout,
    isMenuOpened: (Boolean)-> Unit
) {
    val constraintSet = ConstraintSet()
    constraintSet.clone(parentConstraintLayout)

    constraintSet.setVisibility(descriptionItem1.id, View.VISIBLE)
    constraintSet.clear(menuItem1.id, ConstraintSet.TOP)
    constraintSet.connect(menuItem1.id, ConstraintSet.BOTTOM, this.id, ConstraintSet.TOP, 0)
    constraintSet.connect(menuItem1.id, ConstraintSet.START, this.id, ConstraintSet.START, 0)
    constraintSet.connect(menuItem1.id, ConstraintSet.END, this.id, ConstraintSet.END, 0)

    constraintSet.setVisibility(descriptionItem2.id, View.VISIBLE)
    constraintSet.clear(menuItem2.id, ConstraintSet.TOP)
    constraintSet.connect(menuItem2.id, ConstraintSet.BOTTOM, menuItem1.id, ConstraintSet.TOP, 0)
    constraintSet.connect(menuItem2.id, ConstraintSet.START, this.id, ConstraintSet.START, 0)
    constraintSet.connect(menuItem2.id, ConstraintSet.END, this.id, ConstraintSet.END, 0)

    val transition = AutoTransition()
    transition.duration = 150
    transition.interpolator = AccelerateInterpolator()

    transition.addListener(object: Transition.TransitionListener {
        override fun onTransitionEnd(p0: Transition) {
            isMenuOpened(true)
        }
        override fun onTransitionResume(p0: Transition) {}
        override fun onTransitionPause(p0: Transition) {}
        override fun onTransitionCancel(p0: Transition) {}
        override fun onTransitionStart(p0: Transition) {}
    })

    TransitionManager.beginDelayedTransition(parentConstraintLayout, transition)
    constraintSet.applyTo(parentConstraintLayout)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.