Android Design Support Library( 四 )


static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {if (TextUtils.isEmpty(name)) {return null;}final String fullName;if (name.startsWith(".")) {// Relative to the app package. Prepend the app package name.fullName = context.getPackageName() + name;} else if (name.indexOf('.') >= 0) {// Fully qualified package name.fullName = name;} else {// Assume stock behavior in this package (if we have one)fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)? (WIDGET_PACKAGE_NAME + '.' + name): name;}try {Map> constructors = sConstructors.get();if (constructors == null) {constructors = new HashMap<>();sConstructors.set(constructors);}Constructor c = constructors.get(fullName);if (c == null) {final Class clazz = (Class) Class.forName(fullName, true,context.getClassLoader());c = clazz.getConstructor(CONSTRUCTOR_PARAMS);c.setAccessible(true);constructors.put(fullName, c);}return c.newInstance(context, attrs);} catch (Exception e) {throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);}}
可以看到用这种方式的系统会自动给我们加上包名 , 写太多反而显的累赘 , 这个自定义应该很好理解 , 效果就是随着的滑动FAB会隐藏/显示 , 是一个很常见的效果:

Android Design Support Library

文章插图
常见效果
只要向上滚动FAB就会消失 , 向下滚动FAB就是显示 , 这里要注意的是FAB可以与形成这种效果 , 但是暂时并不支持 , 没关系 , 反正当成来用就好 , 接下来仿照实现知乎的FAB效果的实现 , 先看一下知乎的效果:
Android Design Support Library

文章插图
知乎的效果
可以很清楚的看到FAB随着的滑动呈现出滚动推出的效果 , 并且点击FAB会出现旋转效果并且弹出一个蒙版 , 我们可以先自定义一个用于执行FAB旋转的 , 可以看到这里FAB是逆时针旋转135度 , 那么代码就可以这么写:
public class RotateBehavior extends CoordinatorLayout.Behavior {private static final String TAG = RotateBehavior.class.getSimpleName();public RotateBehavior() {}public RotateBehavior(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {return dependency instanceof Snackbar.SnackbarLayout;}@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {float translationY = getFabTranslationYForSnackBar(parent, child);float percentComplete = -translationY / dependency.getHeight();child.setRotation(-135 * percentComplete);child.setTranslationY(translationY);return true;}private float getFabTranslationYForSnackBar(CoordinatorLayout parent,FloatingActionButton fab) {float minOffset = 0;final List dependencies = parent.getDependencies(fab);for (int i = 0, z = dependencies.size(); i < z; i++) {final View view = dependencies.get(i);if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) {//view.getHeight()固定为144//ViewCompat.getTranslationY(view)从144-0 , 再从0-144minOffset = Math.min(minOffset,ViewCompat.getTranslationY(view) - view.getHeight());Log.d("TranslationY",ViewCompat.getTranslationY(view)+"");Log.d("Height",view.getHeight()+"");}}return minOffset;}}
这里可能就这段代码比较难理解:
minOffset = Math.min(minOffset,ViewCompat.getTranslationY(view) - view.getHeight());
我在上面打了两个Log , 分别得出了.(view) 和view.()  , 这样看代码就比较容易看懂 , 但是为什么.(view) 是正数呢 , 这里的的View我们都知道指的是 , 我们都知道向上移动的话 应该是负数啊 , 其实的源代码中有一个这样的动作: