Android FloatingActionButton快速拨号

时间:2016-02-13 01:50:01

标签: android android-layout user-interface speed-dial

我目前正在开发一款Android应用,我使用的是FloatingActionButton。我想使用快速拨号进行多项操作,按照谷歌在Android设计上的this页面中所描述的那样旋转/跳出操作按钮,或者可以在早期版本的Keep应用程序中看到(抱歉,但我只能发布一个链接)。我正在使用Android设计支持库专门版本23.1.1(com.android.support:design:23.1.1)。我已经使用Google进行了搜索并查看了FloatingActionButton的参考资料,但无法找到有关快速拨号的任何内容。

我想知道是否有办法使用默认的FloatingActionButton轻松实现这一点,或者我是否必须手动编程所有过渡/动画?

此外,我希望按钮旁边有小标签,如果可能的话,描述动作。

提前谢谢!

3 个答案:

答案 0 :(得分:9)

我在这里加上我的2美分,因为这是我在Googling之后登陆的地方。

我希望帮助像我这样的人来得太晚。

首先,解决方案来自here,所以不是我的。我只是尝试过它很好用。所以我想我会在一个帖子中与你分享,而不是从那里挖掘代码。

该解决方案使用com.android.support:design:25.3.1库,因此请务必将其添加到build.gradle,并且需要API 21以上版本。

坏消息是,它由几个小动作组成:5个动画师,5个绘图加上图标和布局,当然还有代码,好消息是它可以正常工作,高度可定制,不会不需要在MainActivity之外进行任何编码。

一些注意事项:

  • 大型工厂的图像在更多和减号之间变形,并在拍打时旋转。
  • 按钮可以有文本,只要你将文本和每个小工厂放在一个LineaLayout中并将按钮id移动到LinearLayout,这样它就会变得动画而不是fab,但它需要代码隐藏并在必要时显示文本

结果如下:

enter image description here

所以,成分:

  1. Drawables(res / drawable /)。
  2. animated_minus.xml

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:viewportHeight="24"
        android:viewportWidth="24"
        android:width="24dp"
        android:height="24dp">
    
        <group android:name="plus_group" android:pivotX="12" android:pivotY="12">
            <path
                android:name="plus_path"
                android:strokeColor="@android:color/white"
                android:strokeWidth="3"
                android:pathData="M12,0L12,24M0,12,L24,12" />
        </group>
    </vector>
    

    animated_plus.xml

    <?xml version="1.0" encoding="utf-8"?>
    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/plus">
        <target
            android:animation="@animator/rotate_clockwise"
            android:name="plus_group" />
        <target
            android:animation="@animator/plus_to_minus"
            android:name="plus_path" />
    </animated-vector>
    

    fab_background.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?android:colorControlHighlight">
        <item>
            <shape android:shape="oval">
                <solid android:color="?android:colorAccent" />
            </shape>
        </item>
    </ripple>
    

    minus.xml

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:viewportHeight="24"
        android:viewportWidth="24"
        android:width="24dp"
        android:height="24dp">
        <group android:name="plus_group" android:pivotX="12" android:pivotY="12">
            <path
                android:name="plus_path"
                android:strokeColor="@android:color/white"
                android:strokeWidth="3"
                android:pathData="M12,12L12,12M0,12,L24,12" />
        </group>
    </vector>
    

    plus.xml

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:viewportHeight="24"
        android:viewportWidth="24"
        android:width="24dp"
        android:height="24dp">
        <group android:name="plus_group" android:pivotX="12" android:pivotY="12">
            <path
                android:name="plus_path"
                android:strokeColor="@android:color/white"
                android:strokeWidth="3"
                android:pathData="M12,0L12,24M0,12,L24,12" />
        </group>
    </vector>
    
    1. 动画师(res / animator /)。
    2. fab_state_list_animator.xml

      <selector xmlns:android="http://schemas.android.com/apk/res/android">
          <item
              android:state_pressed="true"
              android:state_enabled="true">
              <set>
                  <objectAnimator
                      android:propertyName="translationZ"
                      android:duration="100"
                      android:valueTo="3dp"
                      android:valueType="floatType" />
                  <objectAnimator
                      android:propertyName="elevation"
                      android:duration="0"
                      android:valueTo="5dp"
                      android:valueType="floatType" />
              </set>
          </item>
          <!-- base state -->
          <item android:state_enabled="true">
              <set>
                  <objectAnimator
                      android:propertyName="translationZ"
                      android:duration="100"
                      android:valueTo="0"
                      android:startDelay="100"
                      android:valueType="floatType" />
                  <objectAnimator
                      android:propertyName="elevation"
                      android:duration="0"
                      android:valueTo="5dp"
                      android:valueType="floatType" />
              </set>
          </item>
          <item>
              <set>
                  <objectAnimator
                      android:propertyName="translationZ"
                      android:duration="0"
                      android:valueTo="0"
                      android:valueType="floatType" />
                  <objectAnimator
                      android:propertyName="elevation"
                      android:duration="0"
                      android:valueTo="0"
                      android:valueType="floatType" />
              </set>
          </item>
      </selector>
      

      minus_to_plus.xml

      <?xml version="1.0" encoding="utf-8"?>
      <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
          android:propertyName="pathData"
          android:valueFrom="M12,0L12,24M12,12,L12,12"
          android:valueTo="M12,0L12,24M0,12,L24,12"
          android:valueType="pathType"
          android:duration="@android:integer/config_mediumAnimTime" />
      

      plus_to_minus.xml

      <?xml version="1.0" encoding="utf-8"?>
      <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
          android:propertyName="pathData"
          android:valueFrom="M12,0L12,24M0,12,L24,12"
          android:valueTo="M12,0L12,24M12,12,L12,12"
          android:valueType="pathType"
          android:duration="@android:integer/config_mediumAnimTime" />
      

      rotate_anticlockwise.xml

      <?xml version="1.0" encoding="utf-8"?>
      <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
          android:propertyName="rotation"
          android:valueFrom="90"
          android:valueTo="0"
          android:valueType="floatType"
          android:duration="@android:integer/config_mediumAnimTime" />
      

      rotate_clockwise.xml

      <?xml version="1.0" encoding="utf-8"?>
      <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
          android:propertyName="rotation"
          android:valueFrom="0"
          android:valueTo="90"
          android:valueType="floatType"
          android:duration="@android:integer/config_mediumAnimTime" />
      
      1. 布局。 (RES /布局/)
      2. fab.xml。所有工厂都在这里宣布。在前3 android:src上将ImageButtons替换为您自己的图标。

        <?xml version="1.0" encoding="utf-8"?>
        <merge xmlns:android="http://schemas.android.com/apk/res/android">
        
            <RelativeLayout
                android:id="@+id/fab_container"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/activity_vertical_margin"
                android:layout_marginEnd="@dimen/activity_horizontal_margin"
                android:clipChildren="false" >
        
                <!-- Please note that the @id are defined the first time they're referenced from top to bottom -->
                <ImageButton
                    android:id="@+id/fab_action_3"
                    style="@style/FloatingActionButton.Mini"
                    android:src="@drawable/ic_volume_up_white_24dp"
                    android:layout_above="@+id/fab_action_2"
                    android:layout_alignEnd="@+id/fab"
                    android:contentDescription="@null"
                    android:backgroundTint="@color/sa_gray"
                    android:width="24dp"
                    android:height="24dp"
                    android:onClick="fabAction3" />
        
                <ImageButton
                    android:id="@id/fab_action_2"
                    style="@style/FloatingActionButton.Mini"
                    android:src="@drawable/ic_credit_card_white_24dp"
                    android:layout_above="@+id/fab_action_1"
                    android:layout_alignEnd="@id/fab"
                    android:contentDescription="@null"
                    android:backgroundTint="@color/sa_gray"
                    android:width="24dp"
                    android:height="24dp"
                    android:onClick="fabAction2" />
        
                <ImageButton
                    android:id="@id/fab_action_1"
                    style="@style/FloatingActionButton.Mini"
                    android:src="@drawable/ic_add_shopping_cart_white_24dp"
                    android:layout_above="@id/fab"
                    android:layout_alignEnd="@id/fab"
                    android:contentDescription="@null"
                    android:backgroundTint="@color/sa_gray"
                    android:width="24dp"
                    android:height="24dp"
                    android:onClick="fabAction1" />
        
                <ImageButton
                    android:id="@id/fab"
                    style="@style/FloatingActionButton"
                    android:src="@mipmap/ic_add_w"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentBottom="true"
                    android:contentDescription="@null"
                    android:visibility="visible"
                    android:layout_marginTop="8dp" />
        
            </RelativeLayout>
        </merge>
        

        最后。

        1. 代码(java // MainActivity.java)
        2. a)一些声明:

          private static final String TAG = "Floating Action Button";
          private static final String TRANSLATION_Y = "translationY";
          private ImageButton fab;
          private boolean expanded = false;
          private View fabAction1;
          private View fabAction2;
          private View fabAction3;
          private float offset1;
          private float offset2;
          private float offset3;
          

          b)删除MainActivity onCreate上的常用晶圆厂代码:

            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
              fab.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                              .setAction("Action", null).show();
                  }
              });
          

          并将其替换为:

          final ViewGroup fabContainer = (ViewGroup) findViewById(R.id.fab_container);
          fab = (ImageButton) findViewById(R.id.fab);
          fabAction1 = findViewById(R.id.fab_action_1);
          // insert onClickListener here
          fabAction2 = findViewById(R.id.fab_action_2);
          // insert onClickListener here
          fabAction3 = findViewById(R.id.fab_action_3);
          // insert onClickListener here
          fab.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  expanded = !expanded;
                  if (expanded) {
                      expandFab();
                  } else {
                      collapseFab();
                  }
              }
          });
          fabContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
              @Override
              public boolean onPreDraw() {
                  fabContainer.getViewTreeObserver().removeOnPreDrawListener(this);
                  offset1 = fab.getY() - fabAction1.getY();
                  fabAction1.setTranslationY(offset1);
                  offset2 = fab.getY() - fabAction2.getY();
                  fabAction2.setTranslationY(offset2);
                  offset3 = fab.getY() - fabAction3.getY();
                  fabAction3.setTranslationY(offset3);
                  return true;
              }
          });
          

          c)在MainActivity上添加支持函数(主要是动画代码和3个小型工厂的onClick方法):

          private void collapseFab() {
              fab.setImageResource(R.drawable.animated_minus);
              AnimatorSet animatorSet = new AnimatorSet();
              animatorSet.playTogether(createCollapseAnimator(fabAction1, offset1),
                      createCollapseAnimator(fabAction2, offset2),
                      createCollapseAnimator(fabAction3, offset3));
              animatorSet.start();
              animateFab();
          }
          
          private void expandFab() {
              fab.setImageResource(R.drawable.animated_plus);
              AnimatorSet animatorSet = new AnimatorSet();
              animatorSet.playTogether(createExpandAnimator(fabAction1, offset1),
                      createExpandAnimator(fabAction2, offset2),
                      createExpandAnimator(fabAction3, offset3));
              animatorSet.start();
              animateFab();
          }
          
          private Animator createCollapseAnimator(View view, float offset) {
              return ObjectAnimator.ofFloat(view, TRANSLATION_Y, 0, offset)
                      .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
          }
          
          private Animator createExpandAnimator(View view, float offset) {
              return ObjectAnimator.ofFloat(view, TRANSLATION_Y, offset, 0)
                      .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
          }
          
          private void animateFab() {
              Drawable drawable = fab.getDrawable();
              if (drawable instanceof Animatable) {
                  ((Animatable) drawable).start();
              }
          }
          
          public void fabAction1(View view) {
              Log.d(TAG, "Action 1");
              Toast.makeText(this, "Go shopping!", Toast.LENGTH_SHORT).show();
          }
          
          public void fabAction2(View view) {
              Log.d(TAG, "Action 2");
              Toast.makeText(this, "Gimme money!", Toast.LENGTH_SHORT).show();
          }
          
          public void fabAction3(View view) {
              Log.d(TAG, "Action 3");
              Toast.makeText(this, "Turn it up!", Toast.LENGTH_SHORT).show();
          }
          

          d)引用res/layout/activity_main.xml

          中的fab.xml布局

          删除fab声明:

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

          替换为:

          <include layout="@layout/fab" />
          

          最后的说明:

          1. 随意废弃工厂的onClick代码并替换为 onClickListener。那些应该在评论中说出来 // insert onClickListener here。只记得删除 onClick文件中每个工厂的fab.xml属性并删除 MainActivity中的最后3个函数(fabAction1fabAction2fabAction3)。
          2. 大多数度量,维度等我将它们放在代码中以避免包含更多文件。
          3. 代码未以任何方式进行优化。
          4. 我希望这可以帮助某人并抱歉留言。

答案 1 :(得分:1)

  

我想知道是否有办法使用默认的FloatingActionButton

轻松实现此目的

设计库中的FAB没有此功能。你需要寻找第三方FAB(在android-arsenal上有一些可供选择)

答案 2 :(得分:0)

此库正在实施Material Design准则中的Speed Dial

https://github.com/leinardi/FloatingActionButtonSpeedDial

enter image description here