浮动操作按钮FloatingActionButton&源码设计

来源:互联网 发布:java分布式如何开发 编辑:程序博客网 时间:2024/05/13 11:47

前言

          作为Material Design成员之一,旨在在手机、平板电脑、台式机和其它的平台提供一致、更广泛的外观和感觉。它有自身独特的动态效果,比如变形、弹出、位移等等,代表着当前页面上用户的特定操作。FloatingActionButton在用户界面起着不可替代的作用,看到这里是不是有一种跃跃欲试的感觉。

效果~

    


Part 1、FloatingActionButton常规应用

配置

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    compile 'com.android.support:design:25.0.1'}
代码
    <android.support.design.widget.FloatingActionButton        android:id="@+id/fab"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentRight="true"        android:layout_margin="16dp"        android:src="@android:drawable/ic_dialog_email"        app:backgroundTint="@color/colorAccent"        app:elevation="10dp"        app:fabSize="normal"        app:pressedTranslationZ="12dp"        android:clickable="true"        app:rippleColor="#ff0"        android:onClick="rotate"/>
tips:

1、app:fabSize="" : 设置Fab的大小,normal(56dp) mini(40dp)

2、app:backgroundTint="" : 设置Fab的背景

3、app:rippleColor="" : 设置Fab按下时的波纹效果(在5.0以上起作用)

4、app:elevation="" : 设置Fab正常状态下的海拔高度

5、app:pressedTranslationZ="" : 设置Fab按下的时候Z轴距离

6、在你想触发点击事件之前要设置clickable为true

效果~

    

从效果图可以看出5.0以上和5.0以下Fab的位置不一样,因为在5.0以下会默认为Fab设置边距所以在这里要使用两种尺寸

在5.0以下设置

android:layout_margin="0dp"
在5.0以上设置
android:layout_margin="16dp"
效果~

    

问题解决了~

我们还可以为Fab设置动画效果

        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) fab.getLayoutParams();//        fab.animate().translationY(fab.getHeight()+layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));        //fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));        ObjectAnimator go = ObjectAnimator.ofFloat(fab,"translationY",0,fab.getHeight()+layoutParams.bottomMargin);        go.setDuration(500);        go.setInterpolator(new AccelerateInterpolator());        go.start();        go.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) fab.getLayoutParams();                ObjectAnimator back = ObjectAnimator.ofFloat(fab,"translationY",fab.getHeight()+layoutParams.bottomMargin,0);                back.setDuration(500);                back.setInterpolator(new DecelerateInterpolator());                back.start();            }        });

效果~

    

当然你也可以使用github上的库,如下所示

    

地址:https://github.com/makovkastar/FloatingActionButton


Part 2、FloatingActionButton的源码分析

 * <p>Floating action buttons come in two sizes: the default and the mini. The size can be * controlled with the {@code fabSize} attribute.</p> * 悬浮的按钮有两个尺寸,默认和mini大小,这个尺寸和控制FabSize属性 * <p>As this class descends from {@link ImageView}, you can control the icon which is displayed * via {@link #setImageDrawable(Drawable)}.</p> * 这个类继承ImageView,你可以通过设置setImageDrawable来设置是否显示icon * <p>The background color of this view defaults to the your theme's {@code colorAccent}. If you * wish to change this at runtime then you can do so via * {@link #setBackgroundTintList(ColorStateList)}.</p>   这个View的默认背景颜色为你的主题colorAccent颜色,如果你希望改变这个可以通过setBackgroundTintList方法 */@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)public class FloatingActionButton extends ImageButton {

在来看一下构造方法

    public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        ......        Drawable background = a.getDrawable(R.styleable.FloatingActionButton_android_background);        mBackgroundTint = a.getColorStateList(R.styleable.FloatingActionButton_backgroundTint);        mBackgroundTintMode = parseTintMode(a.getInt(                R.styleable.FloatingActionButton_backgroundTintMode, -1), null);        mRippleColor = a.getColor(R.styleable.FloatingActionButton_rippleColor, 0);        mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, SIZE_NORMAL);        mBorderWidth = a.getDimensionPixelSize(R.styleable.FloatingActionButton_borderWidth, 0);        final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f);        final float pressedTranslationZ = a.getDimension(                R.styleable.FloatingActionButton_pressedTranslationZ, 0f);        a.recycle();       ......        final int sdk = Build.VERSION.SDK_INT;        if (sdk >= 21) {            mImpl = new FloatingActionButtonLollipop(this, delegate);        } else if (sdk >= 12) {            mImpl = new FloatingActionButtonHoneycombMr1(this, delegate);        } else {            mImpl = new FloatingActionButtonEclairMr1(this, delegate);        }        final int maxContentSize = (int) getResources().getDimension(                R.dimen.design_fab_content_size);        mContentPadding = (getSizeDimension() - maxContentSize) / 2;        mImpl.setBackgroundDrawable(background, mBackgroundTint,                mBackgroundTintMode, mRippleColor, mBorderWidth);        mImpl.setElevation(elevation);        mImpl.setPressedTranslationZ(pressedTranslationZ);        setClickable(true);    }
从代码中不难看出,得到xml设置的属性,让FloatingActionButtonImpl实现
随后查看测量方法

    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        final int preferredSize = getSizeDimension();        final int w = resolveAdjustedSize(preferredSize, widthMeasureSpec);        final int h = resolveAdjustedSize(preferredSize, heightMeasureSpec);        // As we want to stay circular, we set both dimensions to be the        // smallest resolved dimension        final int d = Math.min(w, h);        // We add the shadow's padding to the measured dimension        setMeasuredDimension(                d + mShadowPadding.left + mShadowPadding.right,                d + mShadowPadding.top + mShadowPadding.bottom);    }
getSizeDimension()得到不同尺寸下的大小

    final int getSizeDimension() {        switch (mSize) {            case SIZE_MINI:                return getResources().getDimensionPixelSize(R.dimen.design_fab_size_mini);            case SIZE_NORMAL:            default:                return getResources().getDimensionPixelSize(R.dimen.design_fab_size_normal);        }    }
resolveAdjustedSize()得到父控件测量之后的尺寸

    private static int resolveAdjustedSize(int desiredSize, int measureSpec) {        int result = desiredSize;//将期望的大小赋值给result        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);//得到实际的大小        switch (specMode) {            case MeasureSpec.UNSPECIFIED://无穷大                result = desiredSize;//当mode为无穷大时,将最终值设置为期望值                break;            case MeasureSpec.AT_MOST://不多于实际值                result = Math.min(desiredSize, specSize);//为了保证在内部区域画圆,得到两者的最小值                break;            case MeasureSpec.EXACTLY://准确值                // No choice. Do what we are told.                result = specSize;                break;        }        return result;    }
上面的方法通过判断specMode来对result进行赋值





1 0
原创粉丝点击