Розширюване меню плаваючої кнопки дій FAB (Бібліотека підтримки Android)


172

Тепер, коли бібліотека підтримки дизайну Android вийшла, хтось знає, як реалізувати розширене меню Fab з нею, як fab в Inbox App?

Має виглядати так:

введіть тут опис зображення



Я вже перевірив всю документацію, але, мабуть, немає жодної ознаки меню FAB :(
EkKoZ

8
Ви можете подивитися на цю бібліотеку FloatingActionButton .
Маркус Рубі

3
@MarkusRubey дякую, насправді це той, хто використовує на даний момент, його я просто хотів зробити з рідним, але, мабуть, це ще не можливо.
EkKoZ

Існує багато бібліотек з відкритим кодом, які могли б виконати роботу. Перевірте це: github.com/futuresimple/android-floating-action-button
capt.swag

Відповіді:


143

Наразі у бібліотеці дизайну немає віджета. Єдиний спосіб зробити це швидко і легко - це використання сторонніх бібліотек.

Очевидно, це можна зробити і за допомогою бібліотеки дизайну, але це буде величезна робота і вимагатиме багато часу. Я згадав кілька корисних бібліотек, які можуть допомогти вам досягти цього.

  1. Швидка плаваюча кнопка (wangjiegulu)
  2. Кнопка плаваючої дії (клани)
  3. Кнопка плаваючої дії (маківкастар)
  4. Android плаваюча кнопка дій (ф'ючерсне просте)

Я використовую 4-й.


31
ну, ідея полягала в тому, щоб зробити це з натурною бібліотекою дизайну, я знаю, що існує багато бібліотек, які вже мають цю функцію. Спасибі за Вашу відповідь.
EkKoZ

Чи були у вас проблеми з четвертим? Шахта не відображається на пристроях льодяника +. Також кольори та текст накладення фону не працюють
Айфіт Мемана

@AjithMemana Nope. Моя програма виробляється для більш ніж 100 тис. Користувачів, і я ніколи не мав жодних проблем, як ви вже згадували.
Арітра Рой

Не могли б ви надати мені посилання на ваш додаток? Мені потрібно щось подібне до того, що показано вище, а також напівпрозорий фон, що охоплює екран при натисканні кнопки.
Аджит Мемана

2
Як зауважимо, Клани та маковкастар більше не підтримуються. Я підозрюю, що це пов’язано з удосконаленнями в бібліотеці дизайну FAB
Чесні заперечення

162

У вас є кращий підхід до впровадження анімаційного меню FAB без використання бібліотеки або написання величезного коду XML для анімації. сподіваюся, що це допоможе в майбутньому тому, хто потребує простого способу втілення цього.

Використовуючи animate().translationY()функцію, ви можете анімувати будь-який вид вгору або вниз, як я це зробив у своєму коді нижче, перевірити повний код у github . Якщо ви шукаєте той самий код у kotlin, ви можете оформити код kotlin repo Animating FAB Menu .

спочатку визначте всі свої FAB в одному місці, щоб вони перекривались один з одним, пам’ятайте, зверху FAB повинен бути таким, що ви хочете натиснути та показати інше. наприклад:

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

Тепер у вашому класі java просто визначте всі свої FAB та виконайте клацання, як показано нижче:

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

Використовуйте animation().translationY()для анімації свого FAB, я вважаю за краще використовувати атрибут цього методу в DP, оскільки лише використання int вплине на сумісність дисплея з більшою роздільною здатністю або меншою роздільною здатністю. як показано нижче:

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

Тепер визначте вищезазначений вимір усередині res-> values-> dimens.xml, як показано нижче:

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

Ось і вся надія, що це рішення допоможе людям у майбутньому, які шукають простого рішення.

ВИДАЛЕНО

Якщо ви хочете додати мітку через FAB, тоді просто візьміть горизонтальний LinearLayout і поставте FAB з текстовим переглядом як мітку, і анімуйте макети, якщо знайдете якісь проблеми з цим, ви можете перевірити мій зразок коду в github, я обробив всю зворотну сумісність проблеми в цьому зразковому коді. перевірити мій зразок коду для FABMenu в Github

щоб закрити FAB на Backpress, замініть onBackPress (), як показано нижче:

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

Скріншот має назву, як і у FAB, тому що я беру його з мого прикладу прикладу ingithub

введіть тут опис зображення


8
навіть додавання міток до меню також просто, вам просто потрібно додати FAB всередині Linearlayout з деяким переглядом тексту як мітка, а після цього анімувати весь лінійний макет не забув сховатися та показати лінійний макет всередині функції відкриття та закриття
HAXM

1
але prashant створив окремий xml для анімації, але моєму рішення не потрібні додаткові xml для анімації, тому повірте, що моя відповідь краща, оскільки для анімації подання не потрібен додатковий рядок коду.
HAXM

2
Це найкраща відповідь. Ви можете використовувати справжній FAB з бібліотеки дизайну, і він не такий вже завершений.
Стефан Матіс

3
Що мені також сподобалось у цьому підході, це те, що оскільки ми використовуємо Android FAB, багато основної роботи вже зроблено. наприклад, замість того, щоб писати нестандартну поведінку перегляду з нуля (оскільки бібліотеки не розширювали FAB), ви можете просто розширити нативну поведінку
файлів

1
@droidHeaven зробіть рамку і помістіть все своє FAB всередину
HAXM

31
  • Спочатку створіть макети меню у вашому XML-файлі макета діяльності. Наприклад, лінійний макет з горизонтальною орієнтацією і включає TextView для мітки, а потім плаваючу кнопку дії поруч з TextView.

  • Створіть макети меню відповідно до ваших потреб та кількості.

  • Створіть базову кнопку з плаваючою дією та натисканням на неї змініть видимість макетів меню.

Будь ласка, ознайомтесь із наведеним нижче кодом для довідки та для отримання більш детальної інформації замовляйте мій проект від github

Оформити замовлення від 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>

Це анімації,

Анімація відкриття меню 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>

Закриваюча анімація меню 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>

Тоді у своїй діяльності я просто використовував анімації, наведені вище, щоб показати та приховати меню FAB:

Показати меню 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;

}

Закрити меню 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;

}

Ось клас активності -

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

Ось скріншоти

Меню з плаваючою дією з текстовим переглядом міток у новій сімействі курсивних шрифтів Android

Меню з плаваючою дією з текстовим переглядом міток у новій сім'ї шрифтів Roboto для Android



7

Коли я намагався створити щось подібне до вхідної плаваючої кнопки дій, я думав про створення власного користувальницького компонента.

Це було б просто макет кадру з фіксованою висотою (містити розширене меню), що містить кнопку FAB та ще 3, розміщені під FAB. при натисканні на FAB ви просто анімуєте інші кнопки для перекладу з-під FAB.

Є деякі бібліотеки, які роблять це (наприклад, https://github.com/futuresimple/android-floating-action-button ), але завжди веселіше, якщо створити його самостійно :)


Відмінне пояснення! Я вивчаю цю бібліотеку, але у мене виникають проблеми з її використанням для вирівнювання FAB між двома видами перегляду. Цікаве , що запитується в цьому питанні stackoverflow.com/questions/24459352 / ... . Будь-яка ідея, як це зробити? layout_anchorі layout_anchorGravityне працюють для мене
acrespo

Бібліотека Futuresimple не дозволяє створити унікальну піктограму плюс, яка за замовчуванням відповідає її елементу FloatingActionMenu
Одайм

7

Ви можете скористатися бібліотекою FloatingActionMenu або натиснути тут покроковий посібник. Вихід підручника:

введіть тут опис зображення


Простий і чудово працює. Я б радив, але ви додасте тут деталі замість того, щоб пов'язувати підручник, якщо посилання в майбутньому знизиться. Інша справа, я тільки що дізнався, що бібліотека вже не в розвитку, на жаль.
Ахмед Салах

3

Я використовую цю бібліотеку для цього: https://github.com/futuresimple/android-floating-action-button

Досить простий у використанні;)

введіть тут опис зображення


Деякі коментарі, які я зробив до інших подібних відповідей. У мене виникають проблеми з його вирівнюванням FAB між двома видами перегляду. Цікаве , що запитується в цьому питанні stackoverflow.com/questions/24459352 / ... . Будь-яка ідея, як це зробити? layout_anchorі layout_anchorGravityне працюють для мене
acrespo

0

Ще один варіант для того ж результату з анімацією ConstraintSet:

приклад анімації для файлів

1) Помістіть усі анімовані перегляди в одну ConstraintLayout

2) Анімуйте його з подібного коду (якщо ви хочете ще кілька ефектів, це залежить від вас. Це лише приклад)

menuItem1 та menuItem2 - це перша та друга FAB в меню, descriptionItem1 та descriptionItem2 - це опис зліва від меню, parentConstraintLayout - корінь ConstraintLayout, який містить усі анімовані види, isMenuOpened - це деяка функція змінити відкритий / закритий прапор у стані

Я поміщаю анімаційний код у розширення, але його не потрібно.

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)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.