废话不多说,先看效果图,没有效果图就等于扯淡。

因为上传大小有限制,并且GIF有卡顿。所以大家下载源码可以看到更多效果

SnackBar

前两天创建新项目的activity的时候,不小心选择了ScrollingActivity,打开一看里面有一个SnackBar来显示出吐司。感觉跟Toast一样,于是研究了一番。先来简单的介绍一下SnackBar,Snackbar 是 Android 5.0 新特性——Material Design 中的一个控件,用来代替 Toast ,Snackbar与Toast的主要区别是:Snackbar可以滑动退出,也可以处理用户交互(点击)事件。总之Toast能做的它也可以做,而且部分功能做的更好。比如显示时长,Toast最多3s,SnackBar可以自定义时长。这一点比Toast强大很多。

Snackbar特性

  1. 屏幕上同时最多只能显示一个Snackbar;
  2. 可以在Snackbar中添加一个按钮,处理用户点击事件;
  3. Snackbar一般需要CoordinatorLayout来作为父容器,CoordinatorLayout保证Snackbar可以右滑退出;
  4. 出现时不会阻碍用户在屏幕上的输入;
  5. 可以自定义显示时长;
  6. 可以监听显示隐藏事件,便于用户操作更多。

扩展功能

因为SnackBar并不能完全支撑我们的开发需要,所以这里通过修改源码拓展了一些功能

  1. SnackBar展示位置(SnackBar默认只能在底部显示,并且动画也只是根据底部弹出的,所以如果想要在其他位置显示,需要通过修改源码在修改;具体代码在BaseTransientBottomBar.java中的445行设置,如果想要拓展的,可以直接修改此类)
  2. SnackBar展示动画(跟上面一样,动画默认是底部弹出。如果需要修改,可以在源码MySnackBar.java中的256行通过setGravity()方法来追踪,具体都有注释,想必不难理解。)

这里的拓展功能是我根据我当前项目需要,就只修改了这两处的源码。大家可以根据项目需求自行拓展

我修改的源码

1.MySnackBar.java(这个类没有修改,新增了一个方法,用来调用)

 /*** 自定义SnackBar显示位置* @param type*/public void setGravity(int type) {BaseTransientBottomBar.DISPLAY_LOCATION_TYPE = type;}

2.BaseTransientBottomBar.java(这个类里面修改了两处,一个是显示位置,一个是显示动画)

这里是显示位置修改的代码

 final void showView() {if (mView.getParent() == null) {final ViewGroup.LayoutParams lp = mView.getLayoutParams();if (lp instanceof CoordinatorLayout.LayoutParams) {// If our LayoutParams are from a CoordinatorLayout, we'll setup our Behaviorfinal CoordinatorLayout.LayoutParams clp = (CoordinatorLayout.LayoutParams) lp;final Behavior behavior = new Behavior();behavior.setStartAlphaSwipeDistance(0.1f);behavior.setEndAlphaSwipeDistance(0.6f);behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {@Overridepublic void onDismiss(View view) {view.setVisibility(View.GONE);dispatchDismiss(BaseCallback.DISMISS_EVENT_SWIPE);}@Overridepublic void onDragStateChanged(int state) {switch (state) {case SwipeDismissBehavior.STATE_DRAGGING:case SwipeDismissBehavior.STATE_SETTLING:// If the view is being dragged or settling, pause the timeoutSnackBarManager.getInstance().pauseTimeout(mManagerCallback);break;case SwipeDismissBehavior.STATE_IDLE:// If the view has been released and is idle, restore the timeoutSnackBarManager.getInstance().restoreTimeoutIfPaused(mManagerCallback);break;}}});clp.setBehavior(behavior);// Also set the inset edge so that views can dodge the bar correctlyclp.insetEdge = Gravity.BOTTOM;}//SnackBar源码为 mTargetParent.addView(mView),但是为了兼容动态显示的位置,这里使用了动态布局加载包裹,可以实现自由切换底部还是顶部LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);//此处相当于布局文件中的Android:layout_gravity属性if(DISPLAY_LOCATION_TYPE == 1){param.gravity = Gravity.TOP;} else if(DISPLAY_LOCATION_TYPE == 2){param.gravity = Gravity.BOTTOM;} else if(DISPLAY_LOCATION_TYPE == 3){param.gravity = Gravity.CENTER;}mView.setLayoutParams(param);LinearLayout linear = new LinearLayout(mContext);//注意,对于LinearLayout布局来说,设置横向还是纵向是必须的!否则就看不到效果了。linear.setOrientation(LinearLayout.HORIZONTAL);linear.addView(mView);mTargetParent.addView(linear);}mView.setOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View view) {}@Overridepublic void onViewDetachedFromWindow(View view) {if (isShownOrQueued()) {// If we haven't already been dismissed then this event is coming from a// non-user initiated action. Hence we need to make sure that we callback// and keep our state up to date. We need to post the call since// removeView() will call through to onDetachedFromWindow and thus overflow.sHandler.post(new Runnable() {@Overridepublic void run() {onViewHidden(BaseCallback.DISMISS_EVENT_MANUAL);}});}}});if (ViewCompat.isLaidOut(mView)) {if (shouldAnimate()) {// If animations are enabled, animate it inanimateViewIn();} else {// Else if anims are disabled just call back nowonViewShown();}} else {// Otherwise, add one of our layout change listeners and show it in when laid outmView.setOnLayoutChangeListener(new View.OnLayoutChangeListener() {@Overridepublic void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {mView.setOnLayoutChangeListener(null);if (shouldAnimate()) {// If animations are enabled, animate it inanimateViewIn();} else {// Else if anims are disabled just call back nowonViewShown();}}});}}

这里是显示动画修改的代码

 /*** 动画开始方法*/void animateViewIn() {if (Build.VERSION.SDK_INT >= 12) {final int viewHeight;if(DISPLAY_LOCATION_TYPE == 1){//顶部显示viewHeight = -mView.getHeight();}else{//底部显示viewHeight = mView.getHeight();}if (USE_OFFSET_API) {ViewCompat.offsetTopAndBottom(mView, viewHeight);} else {mView.setTranslationY(viewHeight);}final ValueAnimator animator = new ValueAnimator();animator.setIntValues(viewHeight, 0);animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);animator.setDuration(ANIMATION_DURATION);animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animator) {mContentViewCallback.animateContentIn(ANIMATION_DURATION - ANIMATION_FADE_DURATION,ANIMATION_FADE_DURATION);}@Overridepublic void onAnimationEnd(Animator animator) {onViewShown();}});animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {private int mPreviousAnimatedIntValue = viewHeight;@Overridepublic void onAnimationUpdate(ValueAnimator animator) {int currentAnimatedIntValue = (int) animator.getAnimatedValue();if (USE_OFFSET_API) {ViewCompat.offsetTopAndBottom(mView,currentAnimatedIntValue - mPreviousAnimatedIntValue);} else {mView.setTranslationY(currentAnimatedIntValue);}mPreviousAnimatedIntValue = currentAnimatedIntValue;}});animator.start();} else {final Animation anim = android.view.animation.AnimationUtils.loadAnimation(mView.getContext(),R.anim.design_snackbar_in);anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);anim.setDuration(ANIMATION_DURATION);anim.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationEnd(Animation animation) {onViewShown();}@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}});mView.startAnimation(anim);}}/*** 动画结束方法* @param event*/private void animateViewOut(final int event) {if (Build.VERSION.SDK_INT >= 12) {final ValueAnimator animator = new ValueAnimator();if(DISPLAY_LOCATION_TYPE == 1){//改成0,顶部显示才会生效(design_layout_snackbar.xml里的layout_gravity由bottom改为top)//如果要底部显示(注释这一行即可)mView.setTranslationY(0);//顶部显示animator.setIntValues(0, -mView.getHeight());}else{//底部显示animator.setIntValues(0, mView.getHeight());}animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);animator.setDuration(ANIMATION_DURATION);animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animator) {mContentViewCallback.animateContentOut(0, ANIMATION_FADE_DURATION);}@Overridepublic void onAnimationEnd(Animator animator) {onViewHidden(event);}});animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {private int mPreviousAnimatedIntValue = 0;@Overridepublic void onAnimationUpdate(ValueAnimator animator) {int currentAnimatedIntValue = (int) animator.getAnimatedValue();if (USE_OFFSET_API) {ViewCompat.offsetTopAndBottom(mView,currentAnimatedIntValue - mPreviousAnimatedIntValue);} else {mView.setTranslationY(currentAnimatedIntValue);}mPreviousAnimatedIntValue = currentAnimatedIntValue;}});animator.start();} else {final Animation anim = android.view.animation.AnimationUtils.loadAnimation(mView.getContext(),R.anim.design_snackbar_out);anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);anim.setDuration(ANIMATION_DURATION);anim.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationEnd(Animation animation) {onViewHidden(event);}@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}});mView.startAnimation(anim);}}

我修改的代码就上面这么多


以上就是所有的代码

附上demo源码。

源码:源码请点这里

如果下不了源码,可以加微信,手机号在下面。


Q:486789970(QQ现在很少用)
V:18588400509(如果着急,可以直接加微信)
email:mr.cai_cai@foxmail.com

如果有什么问题,欢迎大家指导。并相互联系,希望能够通过文章互相学习。

                                                                         ---财财亲笔

SnackBar源码解析及封装相关推荐

  1. 源码解析6-系统封装-QTableView实现

    Qt源码解析 索引 源码解析6-系统封装-QTableView实现源码 一个简单的模型/视图应用程序 如果你想开发一个模型/视图应用程序,你应该从哪里开始?我们建议从一个简单的示例开始,然后逐步扩展它 ...

  2. 谷歌BERT预训练源码解析(三):训练过程

    目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...

  3. Gin源码解析和例子——中间件(middleware)

    在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...

  4. Redis源码解析——字典基本操作

    有了<Redis源码解析--字典结构>的基础,我们便可以对dict的实现进行展开分析.(转载请指明出于breaksoftware的csdn博客) 创建字典 一般字典创建时,都是没有数据的, ...

  5. Redis源码解析——内存管理

    在<Redis源码解析--源码工程结构>一文中,我们介绍了Redis可能会根据环境或用户指定选择不同的内存管理库.在linux系统中,Redis默认使用jemalloc库.当然用户可以指定 ...

  6. VVeboTableView 源码解析

    原文链接:http://www.jianshu.com/p/78027a3a2c41 最近在看一些 iOS 性能优化的文章,我找到了 VVeboTableView 这个框架.严格来说这个不属于框架,而 ...

  7. 彻底理解OkHttp - OkHttp 源码解析及OkHttp的设计思想

    OkHttp 现在统治了Android的网络请求领域,最常用的框架是:Retrofit+okhttp.OkHttp的实现原理和设计思想是必须要了解的,读懂和理解流行的框架也是程序员进阶的必经之路,代码 ...

  8. 【vuejs深入三】vue源码解析之二 htmlParse解析器的实现

    写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. 昨天博主分析了一下在vue中,最为基础核心的api,parse函数,它的作用是将vue的模板字符串转换成ast,从而 ...

  9. Framework 源码解析知识梳理(5) startService 源码分析

    一.前言 最近在看关于插件化的知识,遇到了如何实现Service插件化的问题,因此,先学习一下Service内部的实现原理,这里面会涉及到应用进程和ActivityManagerService的通信, ...

最新文章

  1. hdu2147 kiki's game(巴什博弈java)
  2. 微信红利末期,新媒体运营除了打造10W+还应该做什么?
  3. 手机操作系统如何实现跨平台开发和使用
  4. oracle11管理员连接数据库,1.运行 cmd.exe;2.输入 sqlplus / as sysdba,以系统管理员(sysdba)身份连接数据库,进行数据库管理操作。3.连接成功后执...
  5. Keepalived+LVS
  6. 软件项目开发流程以及人员职责
  7. mysql字符类型总结及常用字符函数
  8. 运用ENVI bandmath对多波段进行计算
  9. 三班倒有害健康,建议六班倒
  10. 计算机连接无线网络的步骤,手机连接电脑wifi上网的方法步骤
  11. 【CMake】CMakeList编写整理
  12. 让 Code Review成为一种习惯
  13. SELinux audit2allow命令使用
  14. win8计算机休眠的区别,电脑的待机/关机/睡眠和休眠有什么区别?Win8开机为什么那么快?...
  15. 【网络基础知识】VLAN技术介绍(详细)
  16. 原神可莉、七七、迪奥娜、早柚、宵宫...模型下载(带骨骼贴图)
  17. Stanford Algorithms: Design and Analysis, Part 1 [Final Exam]
  18. Spring Web 编程详解
  19. 关于创建Word的实例化对象的80040154 没有注册类 解决方法。。。。求帮助求帮助
  20. 解读区块链技术中的“不可能三角”

热门文章

  1. matlab进行频谱分析
  2. 【干货书】遥感图像分析、分类与变化检测(第4版)
  3. (已解决)vue3使用axios报Uncaught TypeError: Cannot convert undefined or null to object axios.js:1308错误
  4. C#使用Managed Wifi API连接带密码的SSID .
  5. SPI W25Q128驱动
  6. Redis --- 学习 NoSQL 五大类型
  7. python123循环结构编程,第009课:常用数据结构之字符串.md
  8. python batch normalization_Batch Normalization的正确打开方式
  9. Python-OpenCV教程-1
  10. 操作系统学习笔记:进程同步与通信