android悬浮按钮(Floating action button)的两种实现方法

最近android中有很多新的设计规范被引入,最流行的莫过于被称作Promoted Actions的设计了,Promoted Actions是指一种操作按钮,它不是放在actionbar中,而是直接在可见的UI布局中(当然这里的UI指的是setContentView所管辖的范围)。因此它更容易在代码中被获取到(试想如果你要在actionbar中获取一个菜单按钮是不是很难?),Promoted Actions往往主要用于一个界面的主要操作,比如在email的邮件列表界面,promoted action可以用于接受一个新邮件。promoted action在外观上其实就是一个悬浮按钮,更常见的是漂浮在界面上的圆形按钮,一般我直接将promoted action称作悬浮按钮,英文名称Float Action Button 简称(FAB,不是FBI哈)。

float action buttonandroid l中的产物,但是我们也可以在更早的版本中实现。假设我这里有一个列表界面,我想使用floataction button代表添加新元素的功能,界面如下:

http://a3ab771892fd198a96736e50.javacodegeeks.netdna-cdn.com/wp-content/uploads/2014/09/android_floating_action_button_14.png

要实现float action button可以有多种方法,一种只适合android L,另外一种适合任意版本。

ImageButton实现

这种方式其实是在ImageButton的属性中使用了android L才有的一些特性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ImageButton
android:layout_width= "56dp"
android:layout_height= "56dp"
android:src= "@drawable/plus"
android:layout_alignParentBottom= "true"
android:layout_alignParentRight= "true"
android:layout_marginRight= "16dp"
android:layout_marginBottom= "16dp"
android:tint= "@android:color/white"
android:id= "@+id/fab"
android:elevation= "1dp"
android:background= "@drawable/ripple"
android:stateListAnimator= "@anim/fab_anim"
/>

仔细一点,你会发现我们将这个ImageButton放到了布局的右下角,为了实现float action button应该具备的效果,需要考虑以下几个方面:

·Background

·Shadow

·Animation

背景上我们使用ripple drawable来增强吸引力。注意上面的xml代码中我们将background设置成了@drawable/ripple ripple drawable的定义如下:

1
2
3
4
5
6
7
<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>

既然是悬浮按钮,那就需要强调维度上面的感觉,当按钮被按下的时候,按钮的阴影需要扩大,并且这个过程是渐变的,我们使用属性动画去改变translatioz


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<selector xmlns:android= "http://schemas.android.com/apk/res/android" >
     <item
         android:state_enabled= "true"
         android:state_pressed= "true" >
         <objectAnimator
             android:duration= "@android:integer/config_shortAnimTime"
             android:propertyName= "translationZ"
             android:valueFrom= "@dimen/start_z"
             android:valueTo= "@dimen/end_z"
             android:valueType= "floatType" />
     </item>
     <item>
         <objectAnimator
             android:duration= "@android:integer/config_shortAnimTime"
             android:propertyName= "translationZ"
             android:valueFrom= "@dimen/end_z"
             android:valueTo= "@dimen/start_z"
             android:valueType= "floatType" />
     </item>
</selector>

使用自定义控件的方式实现悬浮按钮

这种方式不依赖于android L,而是码代码。

首先定义一个这样的类:

1
2
3
public class CustomFAB extends ImageButton {
...
}

然后是读取一些自定义的属性(假设你了解styleable的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void init(AttributeSet attrSet) {
     Resources.Theme theme = ctx.getTheme();
     TypedArray arr = theme.obtainStyledAttributes(attrSet, R.styleable.FAB, 0, 0);
     try {
         setBgColor(arr.getColor(R.styleable.FAB_bg_color, Color.BLUE));
         setBgColorPressed(arr.getColor(R.styleable.FAB_bg_color_pressed, Color.GRAY));
         StateListDrawable sld = new StateListDrawable();
         sld.addState( new int[] {android.R.attr.state_pressed}, createButton(bgColorPressed));
         sld.addState( new int[] {}, createButton(bgColor));
         setBackground(sld);
     }
     catch (Throwable t) {}
     finally {
          arr.recycle();
     }
}

xml中我们需要加入如下代码,一般是在attr.xml文件中。

1
2
3
4
5
6
7
8
<?xml version= "1.0" encoding= "utf-8" ?>
<resources>
     <declare-styleable name= "FAB" >
         <!-- Background color -->
         <attr name= "bg_color" format= "color|reference" />
         <attr name= "bg_color_pressed" format= "color|reference" />
     </declare-styleable>
</resources>


使用StateListDrawable来实现不同状态下的背景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private Drawable createButton(int color) {
     OvalShape oShape = new OvalShape();
     ShapeDrawable sd = new ShapeDrawable(oShape);
     setWillNotDraw( false );
     sd.getPaint().setColor(color);
     OvalShape oShape1 = new OvalShape();
     ShapeDrawable sd1 = new ShapeDrawable(oShape);
     sd1.setShaderFactory( new ShapeDrawable.ShaderFactory() {
         @Override
         public Shader resize(int width, int height) {
             LinearGradient lg = new LinearGradient(0,0,0, height,
             new int[] {
                 Color.WHITE,
                 Color.GRAY,
                 Color.DKGRAY,
                 Color.BLACK
             }, null , Shader.TileMode.REPEAT);
             return lg;
         }
     });
     LayerDrawable ld = new LayerDrawable( new Drawable[] { sd1, sd });
     ld.setLayerInset(0, 5, 5, 0, 0);
     ld.setLayerInset(1, 0, 0, 5, 5);
     return ld;
}

最后将控件放xml中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     xmlns:tools= "http://schemas.android.com/tools"
     android:layout_width= "match_parent"
     android:layout_height= "match_parent"
     android:paddingLeft= "@dimen/activity_horizontal_margin"
     android:paddingRight= "@dimen/activity_horizontal_margin"
     android:paddingTop= "@dimen/activity_vertical_margin"
     android:paddingBottom= "@dimen/activity_vertical_margin"
     tools:context= ".MyActivity" >
...
     <com.survivingwithandroid.fab.CustomFAB
         android:layout_width= "56dp"
         android:layout_height= "56dp"
         android:src= "@android:drawable/ic_input_add"
         android:layout_alignParentBottom= "true"
         android:layout_alignParentRight= "true"
         android:layout_marginRight= "16dp"
         android:layout_marginBottom= "16dp"
         custom:bg_color= "@color/light_blue"
         android:tint= "@android:color/white"
      />
</RelativeLayout>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值