coordinatorlayout_一篇文章学会Coordinatorlayout+AppbarLayout

点击上方蓝字关注 ??

418919ed31f96d216cf4c2acc6d8c563.gif

来源:  奔跑吧李博

https://www.jianshu.com/p/cd93da2b7a24

前言

现如今,折叠式布局在App中相当常见,给人一种科技感,充满良好的用户体验。Coordinatorlayout+AppbarLayout+CollapsingToolbarLayout这三个臭皮匠联合起来用千变万化,啊,我重来没有见过如此超凡脱俗之效果。
网上大多来不来就将这仨揉在一起,布局也是直接全部嵌套完成搬上来,但是你真的理解它们之间的协作关系吗?相互联动的原理是什么呢?一个个控件都没整明白写出这个功能也没有意义呀。那我就一个一个拆开来讲,分别来个功能,再一个接一个拼接。接下来,让我们一起走进它们的内心世界。

先上效果图:

8cc4278cf7c6e0730a110b08f77cbed9.gif

ToolBar(因为涉及到,所以讲一下)

从Android3.0后出现ActionBar,但是这效果,谁用谁知道啊。颜色不好看不说,布局也是无法订制,都不如自定义ActionBar的好。使用方式:1.首先在Activity主题里面将默认Actionbar改为NoActionbar

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

2.绑定toolbar ,setSupportActionBar(toolbar) 设置toolbar为标题栏3.设置常用属性:

toolbar.setNavigationIcon(int resId);toolbar.setLogo(int resId);toolbar.setTitle("");toolbar.setSubtitle("");toolbar.setOnMenuItemClickListener(Toolbar.OnMenuItemClickListener listener);

4.引用菜单

@Overridepublic boolean onCreateOptionsMenu(Menu menu) {//引入options菜单
getMenuInflater().inflate(R.menu.menu,menu);return true;
}

5.在menu文件夹中设置菜单

xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><item android:id="@+id/menu_1"android:title="菜单1"android:icon="@mipmap/make_music_voice_changer_female"app:showAsAction="collapseActionView"/><item android:id="@+id/menu_2"android:title="菜单2"android:icon="@mipmap/make_music_voice_changer_female"app:showAsAction="collapseActionView"/><item android:id="@+id/menu_3"android:title="菜单3"android:icon="@mipmap/make_music_voice_changer_female"app:showAsAction="collapseActionView"/><item android:id="@+id/menu_4"android:title="菜单4"android:icon="@mipmap/make_music_voice_changer_female"app:showAsAction="collapseActionView"/>menu>

或者直接在布局中添加子view使用

<android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:layout_collapseMode="pin"app:popupTheme="@style/ThemeOverlay.AppCompat.Light" ><TextViewandroid:id="@+id/tv1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="返回"android:textSize="13sp"android:textColor="@android:color/white" /><TextViewandroid:id="@+id/tv2"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_gravity="right"android:layout_centerHorizontal="true"android:layout_marginRight="6dp"android:gravity="center"android:padding="4dp"android:textColor="#fff"android:textSize="14sp"android:text="菜单"/>android.support.v7.widget.Toolbar>

cca401f6a99e671236c4a397742486e0.png

  • ifRoom    会显示在Item中,空间不足会将后面item收起来,如果已经有4个或者4个以上的Item时会隐藏在溢出列表中。

  • never    永远不会显示。只会在藏出列表中显示,而且只显示标题,所以在定义item的时候,最好把标题都带上。

  • always    无论是否超出空间,总会显示。

  • withText    withText值示意Action bar要显示文本标题。Action bar会尽可能的显示这个标题,但是,如果图标有效并且受到Action bar空间的限制,文本标题有可能显示不全。

  • collapseActionView      声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。否则,这个操作视窗在默认的情况下是可见的,并且即便在用于不适用的时候,也要占据操作栏的有效空间。
    例如效果:

a806b80175897cfabfa465b6c56298ad.png

11dc6cb70e13918eb5232992f912ceda.png

Coordinatorlayout

定义:is a super-powered Framelayout
是一个超级有力量的爸爸,官方给的定义就足以证明它的强大。
作用:协调子view的相互关系,比如位置、大小,就像有几个调皮孩子的爸爸,要管管孩子的行为。

Behavior:

dc8fb82d7c0654851632b6ad1b163697.png

打开Coordinatorlayout看,Behavior是CoordinatorLayout的一个泛型抽象内部类(这么长累不累呀),所以给子view添加layout_behavior属性是来自于它。

我写了一个例子来理解CoordinatorLayout的工作原理:

091cfd1143bed1e96f4cb7ef14914d09.gif

这是一个大叔跟随女孩的故事

s:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/coordinatorLayout"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.example.md.mdview.CoordinatorLayoutActivity">

android:id="@+id/view_girl"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginLeft="200dp"
android:background="@mipmap/make_music_voice_changer_female" />

android:id="@+id/view_uncle"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@mipmap/make_music_voice_changer_uncle"
app:layout_behavior="com.example.md.mdview.RunBehavior"/>

布局:两个子view,操作viewgirl,viewuncle也会相应跟着走,这就要写一个联动关系,用自定义Behavior实现

public class RunBehavior extends CoordinatorLayout.Behavior<View>{public RunBehavior(Context context, AttributeSet attrs) {super(context, attrs);
}@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {int top = dependency.getTop();int left = dependency.getLeft();
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) child.getLayoutParams();
params.topMargin = top - 400;
params.leftMargin = left;
child.setLayoutParams(params);return true;
}@Overridepublic boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {return true;
}
}

public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency)  方法:
根据条件过滤判断返回值,返回true联动,返回flase不联动,即behavior不生效

public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency)
当 dependency这个哥哥发生变化时, 另一个child弟弟也要跟着去玩
一个view根据另一个view的变化而变化,  dependency被 child监听
功能是child的y值永远比dependency大400像素(废话,还用说吗)

app:layout_behavior="com.example.md.mdview.RunBehavior"

这里一定要写上带参数的构造方法,因为coordinatorlayout是根据反射(所以是包名.类名路径)获取这个behavior,是从这个构造方法获得对象的,否则会报

08c82a8cb6402fbf3e9d7aac9fd48aaf.png

@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:params.leftMargin = (int) (event.getX() - viewGirl.getMeasuredWidth() / 2);params.topMargin = (int) (event.getY() - viewGirl.getMeasuredHeight() / 2);
viewGirl.setLayoutParams(params);break;case MotionEvent.ACTION_MOVE:params.leftMargin = (int) (event.getX() - viewGirl.getMeasuredWidth() / 2);params.topMargin = (int) (event.getY() - viewGirl.getMeasuredHeight() / 2);
viewGirl.setLayoutParams(params);break;
}return true;
}

最后是在界面监听手指的位置,给viewGirl设置手指的位置,viewgril变化了,viewuncle也就随之变化了。

好,在会了Coordinatorlayout的用法,最外层父布局有了,该添加两个子view了。这里里面分别加入AppbarLayout和NestedScrollView作子view,给NestedScrollView加上behavior,就可以让AppbarLayout跟随NestedScrollView的Behavior联动。Android已经自带了app:layout_behavior="@string/appbar_scrolling_view_behavior",只要滚动发生,就会给自己的子view(if
instance of Appbarlayout)添加滚动事件。不明白这俩控件紧接着看后面讲解。当前布局变为:

<android.support.design.widget.CoordinatorLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="50dp"android:background="#0e932e"app:layout_collapseMode="pin"/>android.support.design.widget.CollapsingToolbarLayout>android.support.design.widget.AppBarLayout><android.support.v4.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"app:layout_behavior="@string/appbar_scrolling_view_behavior"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20sp"android:textColor="#000"android:padding="10dp"android:text=""/>android.support.v4.widget.NestedScrollView>android.support.design.widget.CoordinatorLayout>

NestedScrollView(viewgirl的角色)

NestedScrolling机制能够让父View和子View在滚动式进行配合,其基本流程如下:

当子view开始滚动之前,可以通知父View,让其先于自己进行滚动;
子View自己进行滚动;子view滚动之后,还可以通知父view继续滚动。
而要实现这样的交互机制,首先父view要实现NestedScrollingParent接口,而子View需要实现NestedScrollingChild接口,在这套机制中子View是发起者,父view是接受回调并做出响应的。
以下是几个关键的类和接口

/**
* NestedScrollView is just like {@link android.widget.ScrollView}, but it supports acting
* as both a nested scrolling parent and child on both new and old versions of Android.
* Nested scrolling is enabled by default.
*/public class NestedScrollView extends FrameLayout implements NestedScrollingParent,NestedScrollingChild, ScrollingView {static final int ANIMATED_SCROLL_GAP = 250;static final float MAX_SCROLL_FACTOR = 0.5f;private static final String TAG = "NestedScrollView";/**
* Interface definition for a callback to be invoked when the scroll
* X or Y positions of a view change.
*
*

This version of the interface works on all versions of Android, back to API v4.


*
* @see #setOnScrollChangeListener(OnScrollChangeListener)
*/public interface OnScrollChangeListener {/**
* Called when the scroll position of a view changes.
*
* @param v The view whose scroll position has changed.
* @param scrollX Current horizontal scroll origin.
* @param scrollY Current vertical scroll origin.
* @param oldScrollX Previous horizontal scroll origin.
* @param oldScrollY Previous vertical scroll origin.
*/void onScrollChange(NestedScrollView v, int scrollX, int scrollY,int oldScrollX, int oldScrollY);
}private long mLastScroll;private final Rect mTempRect = new Rect();private OverScroller mScroller;private EdgeEffect mEdgeGlowTop;private EdgeEffect mEdgeGlowBottom;
······

//主要接口NestedScrollingChildNestedScrollingParent//帮助类NestedScrollingChildHelperNestedScrollingParentHelper

AppbarLayout(viewuncle的角色)

继承自Linearlayout,且方向是vertical,它可以让你定制当某个可滚动View的滚动手势发生变化时,其内部的子View实现何种动作。

AppBarLayout子View的动作内部的子View通过在布局中加app:layout_scrollFlags设置执行的动作
  • ·scroll  :子view会跟随滚动事件一起滚动,相当于添加到scrollview头部

  • ·enterAlways  :只要屏幕下滑,view就会立即拉下出来。

  • ·snap :这个属性让控件变得有弹性,如果控件下拉了75%的高度,就会自动展开,如果只有25%显示,就会反弹回去关闭。(去试试支付宝首页吧,就是加了弹性这个效果)

  • ·exitUntilCollapsed  :当scrollview滑到订部,再将子view折叠起来

可以给ViewPager设置行为,就不需要使用NestedScrollView的滑动,实现与AppBarLayout联动。
app:layout_behavior="@string/appbar_scrolling_view_behavior"

setExpande(boolean )  设置展开和关闭状态,默认有开关动画

使用示例:

899d6e1591fbf90cecb3d4d860b383f8.gif

CollapsingToolbarLayout

CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承自FrameLayout。
CollapsingToolbarLayout属性   含义
app:title   设置标题
app:collapsedTitleGravity="center"  设置标题位置
app:contentScrim    设置折叠时toolbar的颜色,默认是colorPrimary的色值
app:statusBarScrim  设置折叠时状态栏的颜色 ,默认是colorPrimaryDark的色值
app:layout_collapseParallaxMultiplier   设置视差
app:layout_collapseMode="parallax"  视差模式,在折叠的时候会有个视差折叠的效果
app:layout_collapseMode="pin"   固定模式,在折叠的时候最后固定在顶端

使用示例:让图片折叠,让toolbar固定

<android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><android.support.design.widget.CollapsingToolbarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:layout_scrollFlags="scroll|exitUntilCollapsed"><ImageViewandroid:layout_width="match_parent"android:layout_height="200dp"android:background="@mipmap/bg"app:layout_collapseMode="parallax"/><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:minHeight="50dp"android:background="#000"app:layout_collapseMode="pin"/>android.support.design.widget.CollapsingToolbarLayout>android.support.design.widget.AppBarLayout>

8ad70d6ff4211fe307c0a87cd7b86c0a.gif

添加flags可以设置系统状态栏为透明,如果最顶上是背景这样用效果更佳
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);setContentView(R.layout.activity_main);

实现toolbar渐变颜色:AppbarLayout提供了滑动偏移监听,偏移量除以appbar总高度可以得到当前滑动百分比。注意:这个verticalOffset是0或者负数,需要转绝对值。
appbarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {@Overridepublic void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {//verticalOffset始终为0以下的负数float percent = (Math.abs(verticalOffset * 1.0f)/appBarLayout.getTotalScrollRange());
}
});
这Matial Design的设计真好,但是这名取得,一个个儿的也忒长了吧,google什么时候把名字精简了啊?
好了,以后会持续更新的!

github代码直通车: https://github.com/18380438200/CoordinatorlayoutFull

—————END—————

571c683935a3c6286464f807f9ae831c.png     

   创作不易,点个“在看e615e9ee64ae7d644c28ccf11973b48d.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/562685.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一行python代码值多少钱_一行python代码

Life is short, just use Python. 自从08年接触Python&#xff0c;就有爱不释手的感觉&#xff0c;逐渐地&#xff0c;有些不忍地疏远了Perl 和Shell编程&#xff0c;因为python 的优雅么&#xff1f; 不全是&#xff0c;主要是可以高效开发吧。 那一行代码可以干什么呢&#x…

数据库MySQL相关操作||创建数据库、显示所有数据库、切换数据库、显示数据库下的数据库表、删除数据库

数据库MySQL相关操作||创建数据库、显示所有数据库、切换数据库、显示数据库下的数据库表、删除数据库 1&#xff0c;创建数据库 create databases mydb&#xff1b; 记得加&#xff1b;&#xff08;分号&#xff09; 2&#xff0c;显示所有数据库 show databases; 3&…

在yuv域如何降低画面亮度_家庭影院投影机错误地调节了亮度和对比度会得到怎么样的画面?...

家有影院&#xff0c;可以跟据你的房间和使用习惯设计家庭影院方案&#xff0c;并且还能让你以最优惠的价格买到它们。总之&#xff0c;一切关于家庭影院的问题&#xff0c;我们都可以帮你搞定。解决问题的方式从一对一咨询开始&#xff0c;如有需要&#xff0c;添加家有影院设…

MySQL创建数据库表student

MySQL创建数据库表student 1&#xff0c;创建数据库 create database mydb&#xff1b; 2&#xff0c;查看所有数据库 show databases; 3&#xff0c;使用数据库 use mydb; 4&#xff0c;创建数据库表student create table student(sno int(6),name varchar(12),sex char(2)…

java遍历数组练习(for循环、foreach)

java遍历数组练习&#xff08;for循环、foreach&#xff09; /* * 遍历数组 for循环 foreach * */ public class Test01 {public static void main(String[] args) {int[] arr {11,3,45,6,78,89,23,4};//for循环遍历数组for (int index 0;index<arr.length;index){Sys…

mybatis generator 打印出来表了 但是没有生成未见_Python丨深度学习中使用生成器加速数据读取与训练...

1、什么是生成器我们可以把生成器理解为一个高端的列表。生成器就是一个集算法和列表还有依次读取于一体的功能。因为如果列表存储的内容过多就会造成内存的浪费。但是如果“列表”内的元素可以通过某种规则展示出来、且我们只需要前几项的元素&#xff0c;我们就可以通过使用生…

从键盘上录入10科考试分数,输出最高分最高分输入的序号

从键盘上录入10科考试分数&#xff0c;输出最高分最高分输入的序号 import java.util.Scanner;/* * 从键盘上录入10科考试分数&#xff0c;输出最高分最高分输入的序号 * */ public class Test02 {public static void main(String[] args) {Scanner sc new Scanner(System.in…

pycharm项目目录结构_「Actix-web项目」-项目整体目录结构

前言完成一个前后端分离项目&#xff0c;后端技术选型Rust的框架Actix-web&#xff0c;那么用这个框架完成后端代码它的项目目录很重要&#xff0c;今天就来着重介绍一下。目录结构下面是自己用Rust Actix-web框架写web后端的目录结构&#xff0c;如图所示&#xff1a;目录结构…

java查询数组中元素的索引

java查询数组中元素的索引 /*** java查询数组中元素的索引*/ public class Test03 {public static void main(String[] args) {int[] arr {5,7,4,9,5,7,2,8,1,5,0};//查询元素 2 的索引int value 2;//准备一个变量用于存储目标元素的索引int index -1;//查找元素在数组中第…

完善三个数字对象排序程序。MOOC,Java第四章 面向对象和类 第一次作业

题目内容&#xff1a; 完善以下程序&#xff0c;利用swap函数&#xff0c;完成数字按从小到大的顺序输出。例如输入5 4 3 输出3,4,5。 输入格式: 输入3个数字。 输出格式&#xff1a; 数字从小到大排列 输入样例&#xff1a; 5 4 3 输出样例&#xff1a; 3,4,5 代码…

触发器及其应用实验报告总结_双面喷绘材料的分类及其应用,超全总结!(建议收藏)...

▲ 东川 | 点击图片获取更多信息▲ 东川 | 点击图片获取更多信息双面喷绘材料&#xff0c;有适合水性机器喷的双面摭光画布&#xff0c;有适合弱溶剂和UV喷绘的PVC双喷、PET双喷、双喷网格布、双面牛筋布&#xff0c;它们有个共同的特点就是&#xff0c;即可以单面打画面&#…

java实现程序输出以下5*5数字方格

请实现程序输出以下5*5数字方格。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 需要在main函数的输入参数中设置5&#xff0c;输出5*5的数字方格。如果是输入7&#xff0c;则是7*7的数字方格。 代码如下&#xff1…

java请实现程序输出以下星塔||输出菱形

java请实现程序输出以下星塔||输出菱形 请实现程序输出以下星塔。 * *** ***** *** * 需要在main函数的输入参数中设置5&#xff0c;输出5层星塔。如果是输入7&#xff0c;则是7层星塔。假设输入参数都是奇数&#xff0c;且都大于等于5&#xff0c;小于等于11。 第一种写法&a…

为什么自己编写的页面总是在那里抖动_别克威朗为什么销量不佳?

汽车发展到现在有些车企经历了几十年&#xff0c;而有些车企则是经历了上百年&#xff0c;所以在历史长河的积淀当中&#xff0c;总会有大起大落&#xff0c;混得好的就成为了百年车企&#xff0c;混得不好的就早早退市。而对于车型而言&#xff0c;同样也是如此&#xff0c;有…

java数组的扩容,将两个数组合并成一个数组

java数组的扩容&#xff0c;将两个数组合并成一个数组 //将下列两个数组合成一个数组 public class Test04 {public static void main(String[] args) {int[] a {1,3,4,56,7,8,9,3};int[] b {12,34,56,43,78,74,36};int[] c new int[a.lengthb.length];//将数组a中的元素方…

java开发项目实例_学java开发,项目经验最重要

不想做将军的士兵不是好士兵&#xff01;相信没有人一开始学java&#xff0c;就是为了将来一直做一名初级java开发工程师。只需掌握一些简单代码技巧&#xff0c;别人告诉想要实现的效果&#xff0c;然后自己能用代码堆砌来实现。更何况&#xff0c;现在企业对java开发工程师的…

java在原数组中追加一个元素

java在原数组中追加一个元素 /* * 在原数组中追加一个元素 * */ public class Test05 {public static void main(String[] args) {//在下面这个数组中追加一个元素9int[] a {1,2,3,4,5,6,7,8};int b 9;int[] c new int[a.length1];//复制旧数组到新数组中去for (int i 0;i…

java组件是什么意思_年前面试京东3面凉经~ 面试过程与真题全分享+备战春招(java)...

1月4号得到通知&#xff0c;京东无望了&#xff0c;哭晕在厕所&#xff0c;现在给大家把这些面试题分享出来&#xff0c;希望给想要进京东的一些程序员点点帮助&#xff01;接下来开始分享我去面试的时候面试官问我的那些面试题京东java一面记录简单介绍下自己介绍主要用到的技…

java如何在指定索引位置插入新元素

在arr数组中索引为3的位置&#xff0c;插入一个元素 10 /* * 在arr数组中索引为3的位置&#xff0c;插入一个元素 10 * */ public class Test06 {public static void main(String[] args) {int[] arr {2,6,8,4,9,5,1,3};//要插入索引的位置int x 3;//创建新数组int[] newArr…

java从数组中删除元素(数组的缩容)

java从数组中删除元素&#xff08;数组的缩容&#xff09; 1&#xff0c;解决方案一 /* * 数组的缩容&#xff08;删除元素&#xff09; * 第一种解决方案 * 移动元素&#xff0c;被删除元素后面的元素往前移一位 * 优点&#xff1a;不需要创建新数组&#xff0c;省内存&…