MD风格之丰富多变Toolbar
来源:互联网 发布:ubuntu 16.04 syslog 编辑:程序博客网 时间:2024/06/04 22:47
一. 下载
compile 'com.android.support:design:23.4.0'
二. 详解
CoordinatorLayout继承自ViewGroup,实现了NestedScrollingParent接口,可以说是超级版FrameLayout。 CoordinatorLayout
的用途主要有两个:
- 作为最顶层的application decor或者chrome layout.
- 作为有特定交互的多个子View的容器.
可以通过给CoordinatorLayout
的子View指定Behaviors让子View之间产生不同的交互,也可是使用DefaultBehavior注解指定默认的交互行为。Behaviors
可以实现各种各样的交互和布局变化,如侧滑抽屉和面板的滑动隐藏、一个按钮“粘”在其它元素上并跟随其一起滑动。CoordinatorLayout
的子View可以有一个anchor锚,这个anchor的id必须是CoordinatorLayout
的子View,但不要求一定是固定View或固定View的子View。使用app:layout_anchor
和app:layout_anchorGravity
属性可以控制浮动View的相对位置。
简单点说,通过CoordinatorLayout
我们可以很好地控制容器中子View的交互行为,当然这离不开CoordinatorLayout
的静态抽象内部类Behavior
的作用,Behavior
作为CoordinatorLayout
子View的Behavior交互插件,实现了一到多个子View之间的交互,如drags,、swipes、 flings等手势。 CoordinatorLayout
常用于app bar(之前叫ActionBar,现在改用Toolbar,不过统称AppBar)与其它View的交互。在Toolbar
外面包裹一层AppBarLayout
以便Toolbar和其它子View能更好地响应滚动事件。
AppBarLayout继承自LinearLayout
,是一个vertical的LinearLayout
,并添加了@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
注解以响应滚动事件。其子View应该通过setScrollFlags(int)
或app:layout_scrollFlags
提供它们希望的滚动行为。AppBarLayout
最好作为CoordinatorLayout
的直接子View,否则它的很多方法将会失效。AppBarLayout
需要一个可滚动的兄弟View以便知道何时滚动,这就需要为滚动View设置一个AppBarLayout.ScrollingViewBehavior
实例(这里将RecyclerView的layout_behavior属性设置为AppBarLayout.ScrollingViewBehavior
):
<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.frank.mdtest.MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/abl" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_scrollFlags="scroll|enterAlways" /> <android.support.design.widget.TabLayout android:id="@+id/tl" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|enterAlways" /> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/rv_main" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /></android.support.design.widget.CoordinatorLayout>
这样,当用户滚动RecyclerView
时,AppBarLayout
就能响应滚动事件并根据其子View的layout_scrollFlags
属性控制其如何进入和退出屏幕,ScrollFlags包括:
- scroll: 所有想滚出屏幕的View都要设置这个flag,如果不使用该flag则会固定在屏幕顶端。
- exitUntilCollapsed: 该flag会使View在滚出屏幕前滚动直至“collapsed”状态(View的最小高度)。
- enterAlways: 该flag会确保任何向下的滚动都会导致该View可见,通常用于“快速返回”模式。
- enterAlwaysCollapsed: 当View设置了minHeight并使用该flag时,View只会在最小高度(“collapsed”)时进入,只会在滚动View滚到顶的时候重新展开直至完整高度。
- snap: 当滚动结束时,如果View只是部分可见,将会被拉住并滚动至它的最近的边缘。如:如果View仅仅底部25%可见,它将会被完全滚出屏幕。相反,如果它底部75%可见,它将滚动直至完全显示。
注意:使用
layout_scrollFlags
的View必须在不适用该属性的View之前定义,以确保这些View都能从上滚出屏幕,留下其后固定的View。
为了更详细的控制Toolbar
在“collapsing”过程中的元素交互,可以在Toolbar
外面包裹一层CollapsingToolbarLayout
。
CollapsingToolbarLayout继承自FrameLayout
,被设计为AppBarLayout
的直接子View并作为Toolbar
的容器,CollapsingToolbarLayout
包含以下特征:
- Collapsing title: 其Title会随布局完全展开可见而变大,随折叠而变小。可通过
setTitle(CharSequence)
方法设置Title,通过collapsedTextAppearance
和expandedTextAppearance
属性调整Title样式。 - Content scrim: 当滚动到”collapsed”阈值时显示或隐藏罩层。可通过
setContentScrim(Drawable)
方法设置罩层。 - Status bar scrim: 当滚动到”collapsed”阈值时在状态栏显示或隐藏罩层。可使通过
setStatusBarScrim(Drawable)
方法设置罩层并在LOLLIPOP设备上起作用,同时需要android:fitsSystemWindows="true"
。 - Parallax scrolling children: 其子View可以在该布局内做视差滚动,可以通过给子View(通常是Toolbar的兄弟ImageView)设置
app:layout_collapseMode="parallax"
和app:layout_collapseParallaxMultiplier="0.7"
实现。 - Pinned position children: 其子View可以固定在指定位置,可以通过对Toolbar的
app:layout_collapseMode="pin"
属性值设置确保滚动至被折叠后Toolbar能固定在屏幕顶端。
collapseMode包括:
- off: 没有任何scroll behavior的常规元素(默认属性值)。
- pin: View将会固定到
CollapsingToolbarLayout
的底端。 - parallax: View将会随着
CollapsingToolbarLayout
做视差滚动。
<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.frank.mdtest.MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/abl" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true"> <android.support.design.widget.CollapsingToolbarLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> <android.support.design.widget.TabLayout android:id="@+id/tl" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|snap" /> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/rv_main" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /></android.support.design.widget.CoordinatorLayout>
通过CollapsingToolbarLayout
的app:layout_collapseMode="pin"
属性值地设置确保滚动至被折叠后Toolbar能固定在屏幕顶端,更好的是,Toolbar
配合CollapsingToolbarLayout
使用时,Title的大小将随个展开和折叠调整自己的大小,不过在这种情况下需要调用CollapsingToolbarLayout
而不是Toolbar的setTitle()
方法设置Title。此外还可以通过给CollapsingToolbarLayout
子View(通常是Toolbar的兄弟ImageView)设置app:layout_collapseMode="parallax"
和app:layout_collapseParallaxMultiplier="0.7"
属性以实现视差滚动效果,然后给CollapsingToolbarLayout
设置app:contentScrim
属性以便在折叠时设置罩层颜色:
<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.frank.mdtest.MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/abl" android:layout_width="match_parent" android:layout_height="192dp" android:fitsSystemWindows="true" > <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/ctl" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" app:contentScrim="@color/colorPrimary" android:fitsSystemWindows="true" > <ImageView android:id="@+id/iv_toolbar_bg" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/skill_default_ow" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" app:layout_scrollFlags="scroll|enterAlways" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:contentInsetStart="0dp" > <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Title" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/rv_main" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <ImageView android:id="@+id/fab" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/group_in" android:elevation="10dp" android:layout_marginLeft="20dp" app:layout_anchor="@id/abl"</android.support.design.widget.CoordinatorLayout>
CoordinatorLayout.Behavior类是所有Behavior的基类,用来处理CoordinatorLayout
的直接子View之间的动作交互。该抽象类已知的子类包括AppBarLayout.Behavior, AppBarLayout.ScrollingViewBehavior, BottomSheetBehavior, FloatingActionButton.Behavior, SwipeDismissBehavior。 CoordinatorLayout.Behavior
的主要方法包括:
public Behavior()
.
无参构造器,以便用new关键字实例化public Behavior(Context context, AttributeSet attrs)
.
通过layout属性或@CoordinatorLayout.DefaultBehavior
注解间接实例化时,需要提供该构造器,以便CoordinatorLayout.LayoutParams
可以通过反射实例化该Behaviorpublic boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev)
.
在CoordinatorLayout
向内分发触摸事件之前进行处理。如果Behavior
想要拦截并接管事件流,需要返回true,默认返回false。但如果Behavior
拦截了触摸事件,那剩下的事件流将发送到onTouchEvent
方法public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev)
.
在Behavior
拦截触摸事件后接收和处理触摸事件,如果Behavior
处理了这次触摸事件并还想继续接收事件流的其它事件,需要返回true,默认返回falsepublic int getScrimColor(CoordinatorLayout parent, V child)
.
child view的罩层颜色,默认为Color.BLACK
public float getScrimOpacity(CoordinatorLayout parent, V child)
.
child view的罩层透明度,默认为0.f
public boolean blocksInteractionBelow(CoordinatorLayout parent, V child)
.
决定child view后面的view是否应该被阻塞,默认返回getScrimOpacity(parent, child) > 0.f
public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency)
.
判断给定的child view是否和其它某个兄弟view进行布局依赖。在请求layout时该方法至少要被调用一次,如果对于给定参数的(child,dependency)值对,该方法返回true,那么其父容器CoordinatorLayout将会:①总是在dependent view布局完成后才布局child view, 无论声明顺序如何②当dependency view的布局或位置变化时,会调用该方法。如果child view的布局依赖dependency view的布局则返回true,默认返回falsepublic boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency)
.
child view是否要对它所依赖的dependent view的改变做出响应。一旦dependent view在标准布局流中的大小和位置发生改变,该方法就会被调用。Behavior可以用该方法对child view进行更新操作,但如果Behavior通过该方法更改了child view的布局, 那它也应该在onLayoutChild(CoordinatorLayout, View, int)
方法中做出相应的更改。由于所有子view都是按依赖顺序进行布局的,所以在正常布局期间该方法将不会被调用。如果Behavior更改了child view的大小或位置, 应该返回true,默认返回falsepublic void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency)
.
在dependent view被从父布局中移除后会调用该方法,此时Behavior
可以对child view进行适当更新操作public boolean isDirty(CoordinatorLayout parent, V child)
.
告诉CoordinatorLayout
该child是否为dirty状态,默认返回falsepublic boolean onMeasureChild(CoordinatorLayout parent, V child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)
.
当CoordinatorLayout
要测量给定child view时调用。如果想要让Behavior
自己决定如何测量该child view,需要返回true,默认返回false(由CoordinatorLayout
测量)public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection)
.
当CoordinatorLayout
要布局给定child view时调用。如果Behavior
实现了onDependentViewChanged(CoordinatorLayout, View, View)
方法并更改了child view,那它也应实现该方法。如果Behavior
对child view进行了布局则返回true,默认返回falsepublic boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes)
.
当CoordinatorLayout
的一个子孙view尝试初始化嵌套滚动时调用。CoordinatorLayout
所有直接子view关联的Behavior
都可以响应该事件并返回true以表明CoordinatorLayout
作为该嵌套滚动的父容器,只有该方法返回了true的Behavior
才能接收嵌套滚动的事件流,默认返回falsepublic void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes)
.
当CoordinatorLayout
接受嵌套滚动时会回调该方法public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target)
.
当一次嵌套滚动结束时回调该方法public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)
.
当嵌套滚动已经更新并且target已经或试图滚动时调用,其中dxConsumed表示target作嵌套滚动过程中水平方向上消费的距离,dxUnconsumed表示用户期望的水平方向上的滚动距离public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed)
.
在嵌套滚动将要更新并且target消耗滚动距离之前调用,其中dx表示用户想要滚动的水平像素值,consumed[0]表示消耗的dx距离,consumed[1]表示消耗的dy距离public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed)
.
当嵌套滚动子view开始或想要fling时调用,如果Behavior消费了该fling则需要返回true,默认返回falsepublic boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY)
.
当嵌套滚动子view将要fling时调用,如果Behavior消费了该fling则需要返回true,默认返回false
关于Nested Scrolling(嵌套滚动/嵌套滑动),想了解更多可参考NESTED SCROLLING WITH COORDINATORLAYOUT ON ANDROID及NestedScrolling事件机制源码解析等blogs的简单介绍,或阅读相关源码:
- NestedScrollingParent
- NestedScrollingParentHelper
- NestedScrollingChild
- NestedScrollingChildHelper
References
Android Developers Blog
Android Open Source Project
CodePath Android Cliffnotes
- MD风格之丰富多变Toolbar
- MD风格(ToolBar+Theme)
- MD设计之ToolBar
- MD设计之Toolbar
- android MD新控件之toolbar
- MD风格
- Toolbar的使用.md
- Flutter学习之旅(二)----MD风格和点击事件
- Android-MD风格设置
- MD的配色风格
- Android 打造风格统一的导航之v7 ToolBar
- MaterialDesign设计风格之自定义toolbar的简单实现
- Android MD风格颜色汇总
- 自己设计MD风格侧滑栏
- ToolBar+DrawerLayout实现MD设计效果
- Toolbar 替换ActionBar(android MD 二)
- android练习项目之AS实现MD风格谈话管理系统
- Material Design系列风格控件之(一)----AppBarLayout实现上滑隐藏ToolBar
- 浅谈一类积性函数的前缀和
- Codeforces Round #306 (Div. 2) B DFS
- 贪心算法(2)
- view pe header on winhex
- TabLayout实现滑动导航栏
- MD风格之丰富多变Toolbar
- iOS之 改变日期显示样式
- Nginx反向代理Odoo并转为https
- 概率dp
- 初次邂逅sqlmap
- fck实现htm在线编辑
- 【杭电-oj】-1084-What Is Your Grade?(结构体)
- 【NOIP模拟】弄提纲
- shiro 整合spring