Material Design系列之自定义Behavior支持所有View
本文实例为大家分享了android自定义behavior支持所有view ,供大家参考,具体内容如下
一、实现效果图
这个右下角的fab,动画当然可以多种多样,可以放在界面的任何地方,我们这里只举个例子。但是v7包中提供的behavior目前只能是floatingactionbutton来用,所以今天我们实现的这个behavior是支持所有的view的,可以用在imageview、button、layout,只要是继承view的类都可以用。
二、自定义behavior和动画的封装
我们知道behavior是coordinatorlayout的一个子类,ctrl + t查看它的实现类目前有如下几个:
1. appbarlayout.behavior;
2. appbarlayout.scrollingviewbehavior;
3. floatingactionbutton.behavior;
4. snackbar.behavior;
5. bottomsheetbehaviro;
6. swipedismissbehavior;
7. headerbehavior;
8. viewoffsetbehavior;
9. headerscrollingviewbehavior;
其中第1、7是抽象类,8是package保护的类,9是8的一个子类,我们回头再说。
appbarlayout.scrollingviewbehavior我们经常用,也就是我们在layout xml中经常用的:app:layout_behavior="@string/appbar_scrolling_view_behavior"。
snackbar.behavior被用于snackbar,这个不用多说。
floatingactionbutton.behavior、bottomsheetbehaviro、swipedismissbehavior在文章开头的几个友情链接的博客中已经讲的很清楚了,大家可以回过头去再看看。
今天讲的是自定义behavior支持所有view作为fab,那么也就是floatingactionbutton.behavior了,但是它只支持floatingactionbutton,所以今天我们要自己继承behavior来写definebehavior。所以第一步就是打开floatingactionbutton.behavior的源码看。
实现basicbehavior
首先必须要知道的是coordinatorlayout.behavior这个基类是支持泛型的,看到floatingactionbutton.behavior后发先它是限制了引用它的view必须是floatingactionbutton罢了,那我们这里也来学它继承一下就ok了。
我们新建一个类basicbehavior,把floatingactionbutton.behavior的代码拷贝过来,把里面的泛型改为如下:
public class basicbehavior<t extends view> extends coordinatorlayout.behavior<t>;
也就是说只要引用实现basicbehavior的类是个view就可以,所以接着把basicbehavior里面拷贝的代码中把引用泛型为floatingactionbutton的地方改为view,嗯觉得打工告成的时候发现有几个类的包导不进来:
仔细一看,这几个类在android.support.design.widget包下,一想肯定这几个类是package保护的类,所以我们在我们的项目下新建一个android.support.design.widget包,把实现basicbehavior移到新建的包下,发现问题迎刃而解。
项目源码和basicbehavior的完整源代码下载链接请在文章开头或者末尾找。
动画的实现和简化
(没看之前博客的客观一定要回过头看看,一定会有不一样的收获。)
我们在之前的同系列博客中,实现view的缩放动画的时候,尤其是在view被隐藏时须用如下代码记录view移出动画是否执行完,因为在界面滑动的时候view移除会被behavior一直调用,所以不能重复执行,需要用一个值来记录:
// 记录view移出动画是否执行完。 private boolean isoutexecute = false; private viewpropertyanimatorlistener outanimatorlistener = new viewpropertyanimatorlistener() { @override public void onanimationstart(view view) { isoutexecute = true; } @override public void onanimationend(view view) { view.setvisibility(view.gone); isoutexecute = false; } @override public void onanimationcancel(view view) { isoutexecute = false; } };
为了不在每一个调用的地方都写这么长一段,我们把这端代码封装成一个类,简化如下:
public static class listeneranimatorendbuild { // 记录view移出动画是否执行完。 private boolean isoutexecute = false; private viewpropertyanimatorlistener outanimatorlistener; public listeneranimatorendbuild() { outanimatorlistener = new viewpropertyanimatorlistener() { @override public void onanimationstart(view view) { isoutexecute = true; } @override public void onanimationend(view view) { view.setvisibility(view.gone); isoutexecute = false; } @override public void onanimationcancel(view view) { isoutexecute = false; } }; } // view移出动画是否执行完。 public boolean isfinish() { return !isoutexecute; } // 返回viewpropertyanimatorlistener。 public viewpropertyanimatorlistener build() { return outanimatorlistener; } }
这样一来我们在用的时候就只是两行代码了:
listeneranimatorendbuild listeneranimatorendbuild = new listeneranimatorendbuild(); // 判断是否执行完动画: listeneranimatorendbuild.isfinish();
继承basicbehavior实现definebavior
前面定义好了basicbehavior,这里只需要继承basicbehavior实现我们的动画逻辑:
public class definebehavior extends basicbehavior<view> { private listeneranimatorendbuild listeneranimatorendbuild; public definebehavior(context context, attributeset attrs) { super(context, attrs); listeneranimatorendbuild = new listeneranimatorendbuild(); } @override public boolean onstartnestedscroll(coordinatorlayout coordinatorlayout, view child, view directtargetchild, view target, int nestedscrollaxes) { return nestedscrollaxes == viewcompat.scroll_axis_vertical; } @override public void onnestedscroll(coordinatorlayout coordinatorlayout, view child, view target, int dxconsumed, int dyconsumed, int dxunconsumed, int dyunconsumed) { // if (dyconsumed > 0 && dyunconsumed == 0) { // system.out.println("上滑中。。。"); // } // if (dyconsumed == 0 && dyunconsumed > 0) { // system.out.println("到边界了还在上滑。。。"); // } // if (dyconsumed < 0 && dyunconsumed == 0) { // system.out.println("下滑中。。。"); // } // if (dyconsumed == 0 && dyunconsumed < 0) { // system.out.println("到边界了,还在下滑。。。"); // } // 这里可以写你的其他逻辑动画,这里只是举例子写了个缩放动画。 if ((dyconsumed > 0 || dyunconsumed > 0) && listeneranimatorendbuild.isfinish() && child.getvisibility() == view.visible) {//往下滑 scalehide(child, listeneranimatorendbuild.build()); } else if ((dyconsumed < 0 || dyunconsumed < 0) && child.getvisibility() != view.visible) { scaleshow(child, null); } } }
你可能会很惊讶,哈哈,不要惊讶,封装的好久是这么简单就能实现所有的view支持。
三、如何使用
使用和google提供的behavior一样,引用完整包名就可以:
app:layout_behavior="com.yanzhenjie.definebehavior.behavior.definebehavior"
为了和google提供的behavior使用一样简单,我们可以string.xml中定义一下这个string:
<string name="define_behavior">com.yanzhenjie.definebehavior.behavior.definebehavior</string>
用的时候:
app:layout_behavior="@string/define_behavior"
现在我们把原来项目中的floatingactionbutton换成imageview:
<imageview android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="16dp" android:src="@mipmap/ic_launcher" app:layout_behavior="@string/define_behavior" app:layout_scrollflags="scroll|enteralways|snap" />
好吧,ok了,具体效果大家下载源码:http://xiazai.jb51.net/201609/yuanma/androiddefinebehavior(jb51.net).rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 深入解析java HashMap实现原理