Erweiterbares Floating Action Button (FAB) -Menü der Android Design Support Library

172

Weiß jemand, wie die erweiterte Fab-Menübibliothek implementiert wird, wie die Fab on Inbox-App, nachdem die Android Design Support Library veröffentlicht wurde?

Sollte so aussehen:

Geben Sie hier die Bildbeschreibung ein

EkKoZ
quelle
Ich habe bereits die gesamte Dokumentation überprüft, aber anscheinend gibt es keine Anzeichen für das FAB-Menü :(
EkKoZ
8
Sie können sich diese FloatingActionButton- Bibliothek ansehen .
Markus Rubey
3
@ MarkusRubey danke, eigentlich ist das das, was ich gerade benutze, es ist nur so, dass ich es mit dem nativen machen wollte, aber anscheinend ist es noch nicht möglich.
EkKoZ
Es gibt viele Open-Source-Bibliotheken, mit denen die Arbeit erledigt werden kann. Überprüfen Sie dieses: github.com/futuresimple/android-floating-action-button
capt.swag

Antworten:

143

Derzeit ist in der Designbibliothek kein Widget verfügbar. Nur so geht das schnell und einfach ist die Verwendung von Bibliotheken von Drittanbietern.

Sie können dies natürlich auch mit der Designbibliothek tun, aber es wird eine große Arbeit sein und viel Zeit erfordern. Ich habe einige nützliche Bibliotheken erwähnt, die Ihnen dabei helfen können.

  1. Schneller schwebender Knopf (Wangjiegulu)
  2. Floating Action Button (Clans)
  3. Floating Action Button (makovkastar)
  4. Android Floating Action Button (Zukunft einfach)

Ich benutze den 4..

Aritra Roy
quelle
31
Nun, die Idee war, es mit der nativen Designbibliothek zu machen. Ich weiß, dass es viele Bibliotheken gibt, die diese Funktion bereits ausführen. Danke für deine Antwort.
EkKoZ
Haben Sie Probleme mit dem vierten gefunden? Meins wird auf Lollipop + -Geräten nicht angezeigt. Auch die Hintergrundüberlagerung Farbe und Text funktioniert nicht
Ajith Memana
@ AjithMemana Nein. Meine App ist für mehr als 100.000 Benutzer in Produktion und ich hatte nie Probleme, wie Sie erwähnt haben.
Aritra Roy
Könnten Sie mir bitte einen Link zu Ihrer App geben? Ich brauche etwas Ähnliches wie oben gezeigt, zusammen mit einem durchscheinenden Hintergrund, der den Bildschirm bedeckt, wenn auf die Schaltfläche geklickt wird.
Ajith Memana
2
Clans und Makovkastar werden nicht mehr unterstützt. Ich vermute, dass dies auf Verbesserungen in der FAB-Designbibliothek zurückzuführen ist
Ehrliche Einwände
161

Ich habe einen besseren Ansatz erhalten, um das animierende FAB-Menü ohne Verwendung einer Bibliothek zu implementieren oder großen XML-Code für Animationen zu schreiben. Ich hoffe, dies wird in Zukunft jemandem helfen, der einen einfachen Weg benötigt, dies umzusetzen.

Mit der animate().translationY()Funktion können Sie jede Ansicht nach oben oder unten animieren, wie ich es in meinem folgenden Code getan habe . Überprüfen Sie den vollständigen Code in Github . Wenn Sie in Kotlin nach demselben Code suchen, können Sie das Kotlin-Code-Repo- Animations-FAB-Menü auschecken .

Definieren Sie zuerst alle Ihre FABs an derselben Stelle, damit sie sich überlappen. Denken Sie daran, dass das FAB oben sein sollte, dass Sie klicken und andere anzeigen möchten. z.B:

    <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" />

Definieren Sie jetzt in Ihrer Java-Klasse einfach alle Ihre FABs und führen Sie den Klick wie unten gezeigt aus:

 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();
            }
        }
    });

Verwenden Sie das animation().translationY(), um Ihr FAB zu animieren. Ich bevorzuge, dass Sie das Attribut dieser Methode in DP verwenden, da nur die Verwendung eines int die Anzeigekompatibilität mit höherer oder niedrigerer Auflösung beeinträchtigt. Wie nachfolgend dargestellt:

 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);
}

Definieren Sie nun die oben genannte Dimension in res-> values-> dimension.xml wie folgt:

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

Das ist alles Hoffnung, dass diese Lösung den Menschen in Zukunft helfen wird, die nach einer einfachen Lösung suchen.

BEARBEITET

Wenn Sie eine Beschriftung über dem FAB hinzufügen möchten, nehmen Sie einfach ein horizontales LinearLayout und fügen Sie das FAB mit der Textansicht als Beschriftung ein. Animieren Sie die Layouts, wenn Sie Probleme damit haben. Sie können meinen Beispielcode in github überprüfen. Ich habe die gesamte Abwärtskompatibilität behandelt Probleme in diesem Beispielcode. Überprüfen Sie meinen Beispielcode für FABMenu in Github

Um das FAB bei Backpress zu schließen, überschreiben Sie onBackPress () wie unten gezeigt:

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

Der Screenshot hat auch den Titel mit dem FAB, da ich ihn aus meiner Beispiel-App ingithub nehme

Geben Sie hier die Bildbeschreibung ein

HAXM
quelle
8
Selbst das Hinzufügen von Beschriftungen zum Menü ist ebenfalls einfach. Sie müssen lediglich das FAB in einem linearen Layout mit einer Textansicht als Beschriftung hinzufügen und anschließend das gesamte lineare Layout animieren. Vergessen Sie nicht, das lineare Layout in der
Öffnungs-
1
Prashant hatte jedoch separate XML-Dateien für Animationen erstellt, aber meine Lösung benötigt keine zusätzlichen XML-Dateien für Animationen. Ich glaube, meine Antwort ist besser, da keine zusätzliche Codezeile für die Animation der Ansicht erforderlich ist.
HAXM
2
Das ist die beste Antwort. Sie können das echte FAB aus der Designbibliothek verwenden und es ist nicht so vollständig.
Stephane Mathis
3
Was mir an diesem Ansatz auch gefallen hat, ist, dass seit wir Android FAB verwenden, bereits viele Vorarbeiten geleistet wurden. Anstatt beispielsweise ein benutzerdefiniertes Ansichtsverhalten von Grund auf neu zu schreiben (da Bibliotheken FAB nicht erweitert haben), können Sie einfach das native Fab-Verhalten erweitern, bei dem bereits eine große Menge Code verfügbar ist
RJFares,
1
@droidHeaven nehmen Sie ein Framelayout und platzieren Sie alle Ihre FAB darin
HAXM
31
  • Erstellen Sie zunächst die Menülayouts in der XML-Datei Ihres Aktivitätslayouts. Zum Beispiel ein lineares Layout mit horizontaler Ausrichtung und einer Textansicht für die Beschriftung und einer schwebenden Aktionsschaltfläche neben der Textansicht.

  • Erstellen Sie die Menülayouts nach Bedarf und Nummer.

  • Erstellen Sie eine schwebende Basisaktionsschaltfläche und ändern Sie durch Klicken darauf die Sichtbarkeit der Menülayouts.

Bitte überprüfen Sie den folgenden Code als Referenz und für weitere Informationen überprüfen Sie mein Projekt von Github

Kassenprojekt von 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>

Dies sind die Animationen

Eröffnungsanimation des FAB-Menüs:

<?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>

Abschlussanimation des FAB-Menüs:

<?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>

Dann habe ich in meiner Aktivität einfach die obigen Animationen verwendet, um das FAB-Menü ein- und auszublenden:

Fab-Menü anzeigen:

  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;

}

Fab-Menü schließen:

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;

}

Hier ist die Aktivitätsklasse -

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();
}
}

Hier sind die Screenshots

Floating Action Menu mit Label Textview in der neuen Cursive Font-Familie von Android

Floating Action Menu mit Label Textview in der neuen Roboto Font Family von Android

Prashant
quelle
7

Als ich versuchte, etwas zu erstellen, das der schwebenden Aktionsschaltfläche im Posteingang ähnelt, dachte ich darüber nach, eine eigene benutzerdefinierte Komponente zu erstellen.

Es wäre ein einfaches Rahmenlayout mit fester Höhe (um ein erweitertes Menü zu enthalten), das die FAB-Schaltfläche und 3 weitere unter dem FAB enthält. Wenn Sie auf FAB klicken, animieren Sie einfach andere Schaltflächen, um sie unter dem FAB zu übersetzen.

Es gibt einige Bibliotheken, die das tun (zum Beispiel https://github.com/futuresimple/android-floating-action-button ), aber es macht immer mehr Spaß, wenn Sie es selbst erstellen :)

rwojcik
quelle
Hervorragende Erklärung! Ich erkunde diese Bibliothek, habe jedoch Probleme damit, das FAB zwischen zwei Ansichten auszurichten. Ein bisschen was es in dieser Frage gestellt wird stackoverflow.com/questions/24459352/… . Irgendeine Idee, wie es geht? layout_anchorund layout_anchorGravityarbeiten nicht für mich
Acrespo
Die Bibliothek von Futuresimple erlaubt kein eindeutiges Symbol für das Plus, das standardmäßig für das FloatingActionMenu-Element verwendet wird
Odaym
7

Sie können die FloatingActionMenu-Bibliothek verwenden oder hier klicken, um eine schrittweise Anleitung zu erhalten. Ausgabe des Tutorials:

Geben Sie hier die Bildbeschreibung ein

Pacific P. Regmi
quelle
Einfach und funktioniert gut. Ich würde jedoch vorschlagen, dass Sie die Details hier hinzufügen, anstatt das Tutorial zu verlinken, falls der Link in Zukunft ausfällt. Eine andere Sache, ich habe gerade erfahren, dass sich die Bibliothek leider nicht mehr in der Entwicklung befindet.
Ahmed Salah
3

Ich benutze diese Bibliothek, um dies zu tun: https://github.com/futuresimple/android-floating-action-button

Ziemlich einfach zu bedienen;)

Geben Sie hier die Bildbeschreibung ein

florent champigny
quelle
Einige Kommentare, die ich zu den anderen ähnlichen Antworten gemacht habe. Ich habe Probleme damit, das FAB zwischen zwei Ansichten auszurichten. Ein bisschen was es in dieser Frage gestellt wird stackoverflow.com/questions/24459352/… . Irgendeine Idee, wie es geht? layout_anchorund layout_anchorGravityarbeiten nicht für mich
Acrespo
0

Eine weitere Option für dasselbe Ergebnis mit ConstraintSet-Animation:

fabelhaftes Animationsbeispiel

1) Fügen Sie alle animierten Ansichten in ein ConstraintLayout ein

2) Animieren Sie es aus Code wie diesem (wenn Sie weitere Effekte wünschen, liegt es an Ihnen ... dies ist nur ein Beispiel)

menuItem1 und menuItem2 sind die ersten und zweiten FABs im Menü, descriptionItem1 und descriptionItem2 ist die Beschreibung links vom Menü. parentConstraintLayout ist das Stamm-ConstraintLayout, das alle animierten Ansichten enthält. isMenuOpened ist eine Funktion zum Ändern des offenen / geschlossenen Flags im Status

Ich habe Animationscode in die Erweiterungsdatei eingefügt, aber es ist nicht notwendig.

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)
}
Konstantin Kuznetsov
quelle