Android Design Support Libraryの拡張可能なフローティングアクションボタン(FAB)メニュー


172

Android Design Support Libraryがリリースされたので、Inbox Appのfabのように、拡張されたFabメニューを実装する方法を知っている人はいますか?

次のようになります。

ここに画像の説明を入力してください



私はすでにすべてのドキュメントを確認しましたが、FABメニューの兆候はないようです:(
EkKoZ

8
このFloatingActionButtonライブラリをご覧ください。
Markus Rubey、2015年

3
@MarkusRubeyのおかげで、実際にそれを使用しているのは実際にそれです。ネイティブのものでそれを作りたかったのですが、明らかにまだ可能ではありません。
EkKoZ 2015年

多くのオープンソースライブラリがあり、作業を完了することができます。これをチェックしてください:github.com/futuresimple/android-floating-action-button
capt.swag

回答:


143

現在、デザインライブラリにはウィジェットはありません。それをすばやく簡単に行う唯一の方法は、サードパーティのライブラリを使用することです。

もちろん、デザインライブラリを使用してこれを行うこともできますが、これは膨大な作業であり、多くの時間を必要とします。これを実現するのに役立ついくつかの有用なライブラリーについて説明しました。

  1. ラピッドフローティングボタン(ワンジェグル)
  2. フローティングアクションボタン(クラン)
  3. フローティングアクションボタン(makovkastar)
  4. Androidフローティングアクションボタン(futuresimple)

4枚目を使用しています。


31
まあ、アイデアはネイティブデザインライブラリでそれを行うことでした、私はすでにこの機能を実行する多くのライブラリがあることを知っています。お返事をありがとうございます。
EkKoZ

4つ目の問題は見つかりましたか?鉱山はlollipop +デバイスでは表示されません。また、背景のオーバーレイの色とテキストが機能しません
Ajith Memana 2016年

@AjithMemanaいいえ。私のアプリは10万人以上のユーザーに向けて製品化されており、あなたが言ったように私は何の問題もありませんでした。
Aritra Roy 2016

アプリへのリンクを教えていただけませんか?ボタンがクリックされたときに画面を覆う半透明の背景と共に、上に示されているものに似たものが必要です。
Ajith Memana

2
注として、クランとmakovkastarはサポートされなくなりました。これはFABデザインライブラリの改善によるものだと思います
正直な反対

161

ライブラリを使用せずにアニメーションFABメニューを実装したり、アニメーション用の巨大なxmlコードを記述したりするためのより良いアプローチを得ました。これが将来これを実装する簡単な方法を必要とする誰かのために役立つことを願っています。

animate().translationY()関数を使用するだけで、下のコードで行ったようにビューを上下にアニメーション化できます。githubで完全なコードを確認してください。kotlinで同じコードを探している場合は、kotlinコードリポジトリのFABメニューのアニメーションをチェックアウトできます

最初に、すべての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を取り、ラベルとしてtextviewを使用してFABを配置し、これを行う問題が見つかった場合はレイアウトをアニメーション化します。githubでサンプルコードを確認できます。すべての下位互換性をサポートしていますそのサンプルコードの問題。GithubでFABMenuのサンプルコードを確認してください

バックプレスでFABを閉じるには、以下に示すようにonBackPress()をオーバーライドします。

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

スクリーンショットには、FABのタイトルも含まれています。これは、githubにあるサンプルアプリから取得したためです。

ここに画像の説明を入力してください


8
メニューにラベルを追加することも簡単です。ラベルとしていくつかのテキストビューを使用して、Linearlayout内にFABを追加する必要があります。その後、アニメーション全体の線形レイアウトを開いて閉じる関数内の線形レイアウトを非表示および表示することを忘れないでください
HAXM

1
しかし、prashantはアニメーション用に個別のxmlを作成しましたが、私のソリューションはアニメーション用の追加のxmlを必要としません。したがって、ビューをアニメーション化するための追加のコード行を必要としないため、私の答えがより良いと考えています。
HAXM 2016年

2
それが最良の答えです。デザインライブラリの実際のFABを使用できますが、それほど複雑ではありません。
Stephane Mathis

3
私がこのアプローチについても気に入っているのは、Android FABを使用しているため、多くの基礎がすでに行われていることです。たとえば、カスタムビューの動作を最初から作成する代わりに(ライブラリはFABを拡張しなかったため)、ネイティブのfab動作を拡張することができます。これは、すでに利用可能な膨大な量のコードです
RJFares

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メニューの表示と非表示を切り替えました。

ファブメニューを表示:

  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;

}

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

こちらがスクリーンショットです

Androidの新しい筆記体フォントファミリーのラベルテキストビュー付きのフローティングアクションメニュー

Androidの新しいRoboto Font FamilyのラベルTextviewを備えたフローティングアクションメニュー



7

受信トレイのフローティングアクションボタンに似たものを作成しようとしたときに、独自のカスタムコンポーネントを作成することを考えました。

これは、FABボタンと3つ以上がFABの下に配置された(拡張メニューを含めるために)高さが固定された単純なフレームレイアウトです。FABをクリックすると、他のボタンをアニメーション化するだけで、FABの下から上に移動します。

それを行ういくつかのライブラリーがあります(例えば、https://github.com/futuresimple/android-floating-action-button)が、自分で作成した方が常に楽しいです:)


素晴らしい説明!私はそのライブラリを調査していますが、それを使用して2つのビュー間でFABを整列させるのに問題があります。ちょっとこの質問で何が尋ねられたのか。stackoverflow.com/ questions/ 24459352/…。それを行う方法についてのアイデアはありますか?layout_anchorそしてlayout_anchorGravity私のために働いていません
acrespo

Futuresimpleのライブラリでは、FloatingActionMenu要素にデフォルトで追加されるプラスの一意のアイコンを許可していません
Odaym

7

FloatingActionMenuライブラリを使用するか、ここをクリックしてステップバイステップのチュートリアルをご覧ください。チュートリアルの出力:

ここに画像の説明を入力してください


シンプルで問題なく動作します。今後リンクがダウンした場合に備えて、チュートリアルをリンクする代わりに、ここに詳細を追加することをお勧めします。もう1つ、悲しいことに、ライブラリがもう開発されていないことを知りました。
アーメドサラ

3

私はこれを行うためにこのライブラリを使用します:https : //github.com/futuresimple/android-floating-action-button

使い方はかなり簡単です;)

ここに画像の説明を入力してください


他の同様の答えに対して私が行ったコメント。2つのビュー間でFABを位置合わせするのに使用できません。ちょっとこの質問で何が尋ねられたのか。stackoverflow.com/ questions/ 24459352/…。それを行う方法についてのアイデアはありますか?layout_anchorそしてlayout_anchorGravity私のために働いていません
acrespo

0

ConstraintSetアニメーションで同じ結果を得る別のオプション:

fabアニメーションの例

1)すべてのアニメーションビューを1つのConstraintLayoutに配置する

2)このようなコードからアニメーション化します(さらにエフェクトが必要な場合は、これはあくまでも例です)

menuItem1menuItem2はメニューの最初と2番目のFAB、 descriptionItem1descriptionItem2はメニューの左側の説明、 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)
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.