欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Material Design系列之自定义Behavior支持所有View

程序员文章站 2024-03-06 17:04:56
本文实例为大家分享了android自定义behavior支持所有view ,供大家参考,具体内容如下 一、实现效果图 这个右下角的fab,动画当然可以多种多样,可以放在...

本文实例为大家分享了android自定义behavior支持所有view ,供大家参考,具体内容如下

一、实现效果图

这个右下角的fab,动画当然可以多种多样,可以放在界面的任何地方,我们这里只举个例子。但是v7包中提供的behavior目前只能是floatingactionbutton来用,所以今天我们实现的这个behavior是支持所有的view的,可以用在imageview、button、layout,只要是继承view的类都可以用。

Material Design系列之自定义Behavior支持所有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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。