Material Design

作者: kim_liu | 来源:发表于2018-05-31 13:06 被阅读43次

    关于Material Design 的各种详细的介绍,极客学院的wiki写的非常清楚了:
    http://wiki.jikexueyuan.com/project/material-design/
    那么我们现在就开始撸代码

    1.控制项目全局样式

    1.1 无论是使用AS还是ADT,都要引入appcompat-v7,AS使用下面这一句代码引入,解决Android碎片化开发的问题,碎片化开发,就是在不同版本上的UI,看起来不会有太大的区别。

    implementation 'com.android.support:appcompat-v7:26.1.0'
    

    1.2 写自己的全局样式:

     <!--
            Base application theme, dependent on API level. This theme is replaced
            by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
        -->
    
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
     <!--
                Theme customizations available in newer API levels can go in
                res/values-vXX/styles.xml, while customizations related to
                backward-compatibility can go here.
            -->
      </style>
    
      <!-- Application theme. -->
        <style name="AppTheme" parent="AppBaseTheme">
            <!-- All customizations that are NOT specific to a particular API-level can go here. -->
            <item name="android:textColor">@color/mytextcolor</item>
            <item name="colorPrimary">@color/colorPrimary_pink</item>
            <item name="colorPrimaryDark">@color/colorPrimary_pinkDark</item>
            <item name="android:windowBackground">@color/background</item>
        <item name="colorAccent">@color/accent_material_dark</item>
            <!-- 设置虚拟导航栏背景颜色  5.x新特性-->
            <item name="android:navigationBarColor">@color/colorPrimary_pink</item>
        </style>
    
    

    AppTheme相当于AppBaseTheme的子类,在AppTheme中设置各种颜色,样式的配置。其中:
    colorPrimary:主色,
    colorPrimaryDark:主色--深色,一般可以用于状态栏颜色、底部导航栏
    colorAccent:代表各个控件的基调颜色--CheckBox、RadioButton、ProgressBar等
    android:textColor:当前所有的文本颜色

    2. v7包中有很多控件,都是为兼容而生的,在各个版本中运行的外观并没有太大的区别。

    2.1 AlertDialog:
    android.app包中的AlertDialog:在不同的版本上显示样式是不一样的,在4.1下显示是这样的:


    传统对话框

    8.0下显示是这样的:


    传统对话框

    而android.support.v7.app包下的AlertDialog,在4.1和8.0下显示基本相同。


    Android 8.0下V7对话框
    Android 4.1下 V7对话框

    可以看到,基本上是一样的。

    2.2 下拉刷新 SwipeRefreshLayout

     srl.setColorSchemeColors(Color.YELLOW,Color.RED,Color.GREEN);//设置进度条的颜色
            srl.setProgressBackgroundColorSchemeColor(Color.WHITE);//设置背景颜色
            srl.setDistanceToTriggerSync(100);//下拉多少距离开始刷新
            srl.setSize(SwipeRefreshLayout.DEFAULT);//设置进度条的大小
            srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    //下拉完毕
                    srl.setRefreshing(false);//消失
                }
            });
    

    2.3 PopWindow,ListPopupWindow,PopupMenu
    ListPopupWindow:

     final ListPopupWindow listPopupWindow = new ListPopupWindow(this);
            listPopupWindow.setAdapter(adapter);
            listPopupWindow.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
            listPopupWindow.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
            listPopupWindow.setAnchorView(view);//设置锚点,弹出的位置相对于View
            listPopupWindow.show();
    
            listPopupWindow.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(getApplicationContext(),"点击了"+position,Toast.LENGTH_SHORT).show();
    
                    listPopupWindow.dismiss();
                }
            });
    

    PopupMenu:

    android.support.v7.widget.PopupMenu popupMenu
                    = new android.support.v7.widget.PopupMenu(this,view);
            popupMenu.getMenuInflater().inflate(R.menu.menu,popupMenu.getMenu());
            popupMenu.show();
    

    2.4 LinearLayoutCompat :在该控件中添加属性:
    app:divider="@drawable/abc_list_divider_mtrl_alpha"
    app:showDividers="beginning|middle"
    可以给LinearLayout中的控件都加上divider

    <android.support.v7.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:divider="@drawable/abc_list_divider_mtrl_alpha"
        app:showDividers="beginning|middle"
       >
    
    <!--子控件-->
    
    
    </android.support.v7.widget.LinearLayoutCompat>
    

    其他的控件,如Button,TextView,EditText等,V7包中的都是这样的包名:
    android.support.v7.widget.AppCompatButton android.support.v7.widget.AppCompatTextView等。

    查看源码:分析LinearLayoutCompat是怎么给其中的每个控件添加分割线的?

    1.在xml文件中app:设置分割线,那么就从自定义属性入手,发现源码中有这样一句:

    setDividerDrawable(a.getDrawable(R.styleable.LinearLayoutCompat_divider));
    

    其中

    a.getDrawable(R.styleable.LinearLayoutCompat_divider)
    

    这句代码的意思是获取用户输入的drawable,那么setDividerDrawable()就是设置分割线了。

    3. RecyclerView

    RecyclerView内容很多,现在暂时没有时间去整理,以后再整理
    RecyclerView也是v7包中的控件,因为使用的很多,所以专门拿出来说,RecyclerView最低可兼容到3.0。引入方法:

       implementation 'com.android.support:recyclerview-v7:26.1.0
    

    用法:Adapter 继承自 RecyclerView.Adapter<RecyclerView.ViewHolder>
    设置adapter和LayoutManager给RecyclerView。

    简单封装
    绘制间隔线:
    1在getItemOffset()中绘制矩形 在该矩形中绘制间隔线
    2 拿到系统的属性的方法

    4.侧滑

    在Material Design出来之前,一般都是使用SlidingMenu进行侧滑,MD出来之后,Google收录了很多民间项目,并改编,放入了support包中,供开发者使用,DrawerLayout就是其中之一。

    4.1 DrawerLayout :

    1.来自support-v4包中的weidget包
    2.继承自ViewGroup,可以看成是一个帧布局
    3.里面包含两块内容,一个是内容布局,一个是侧滑布局,侧滑布局是在内容布局的上面显示,因此是写在内容布局的下面,并且需要设置android:layout_gravity="start" 如果设置成end 则是右侧滑动菜单

    DrawerLayout和ToolBar结合使用:

    1.在布局中添加ToolBar
    2.在代码中用ToolBar替换ActionBar:setSupportActionBar(toolbar);
    3.使用ActionBarDrawerToggle把DrawerLayout和ToolBar联系起来

            toolbar = findViewById(R.id.toolbar);
            //用toolbar替换actionBar
            setSupportActionBar(toolbar);
            drawerlayout = findViewById(R.id.drawerlayout);
            //最后两个参数是两个资源文件的名称,int类型 并无实际意义,只要填上即可
            ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this,
            drawerlayout,toolbar,R.string.drawer_open,R.string.drawer_close);
            //状态同步
            drawerToggle.syncState();
           //给DrawerLayout设置监听
            drawerlayout.setDrawerListener(drawerToggle);
    

    4 如果要自定义DrawerLayout打开关上的动画,只需要重写DrawerListener即可

           drawerlayout.addDrawerListener(new DrawerLayout.DrawerListener() {
    
                /**
                 * Called when a drawer's position changes.
                 * @param drawerView The child view that was moved
                 * @param slideOffset The new offset of this drawer within its range, from 0-1
                 */
                @Override
                public void onDrawerSlide(View drawerView, float slideOffset) {
                    //drawerView :侧滑布局
                    //slideOffset :滑动时的偏移量
                }
                /**
                 * Called when a drawer has settled in a completely open state.
                 * The drawer is interactive at this point.
                 *
                 * @param drawerView Drawer view that is now open
                 */
                @Override
                public void onDrawerOpened(View drawerView) {
                    //打开时调用
    
                }
                /**
                 * Called when a drawer has settled in a completely closed state.
                 *
                 * @param drawerView Drawer view that is now closed
                 */
                @Override
                public void onDrawerClosed(View drawerView) {
                    //关闭时调用
    
                }
                /**
                 * Called when the drawer motion state changes. The new state will
                 * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
                 *
                 * @param newState The new drawer motion state
                 *
                 *  STATE_IDLE:空闲 Indicates that any drawers are in an idle, 
                 *                 settled state. No animation is in progress.
                 *  STATE_DRAGGING:正在拖拽 Indicates that a drawer is currently 
                 *                 being dragged by the user.
                 *  STATE_SETTLING:拖拽完成 Indicates that a drawer is in 
                 *                 the process of settling to a final position.
                 *
                 */
                @Override
                public void onDrawerStateChanged(int newState) {
                    //拖拽状态改变时调用
    
                }
            });
    
            //方法内容为空,也可以点击ToolbarNavigation 打开关闭DrawerLayout
            drawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                }
            });
    
    
    

    4.2 NavigationView

    1.是对DrawerLayout更完善的封装
    2.是谷歌在侧滑的MaterialDesign的一种规范,用来规范侧滑的基本样式。
    NavigationView就是封装好的侧滑区域的布局,它有几个属性
    app:headerLayout 和 app:menu 是头布局和头布局底下的菜单布局
    在使用NavigationView时也需要将其android:layout_gravity 设置成start


    插播:自定义Toast

           Toast result = new Toast(this);
            LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View v = inflate.inflate(自定义Toast的layout, null);
            TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
            tv.setText("我是自定义吐司");
    
            result.setView(v);
            result.setDuration(Toast.LENGTH_SHORT);
    
            result.show();
    

    5.SnackBar

    一种新的吐司,介于Toast和Dialog之间的产物:即做到提示用户,又不会打断用户操作,并且还能与用户交互。
    使用:

          //无穷时间 Snackbar.LENGTH_INDEFINITE  view :为了找到父控件,获取上下文 
            Snackbar snackbar = Snackbar.make(view,"SnackBar",Snackbar.LENGTH_INDEFINITE);
            snackbar.setAction("确定", new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(DrawerlayoutActivity.this,"点击了",Toast.LENGTH_SHORT).show();
                }
            });
            snackbar.setActionTextColor(Color.WHITE);
            snackbar.addCallback(new Snackbar.Callback(){
                @Override
                public void onShown(Snackbar sb) {
                    super.onShown(sb);
                }
    
                @Override
                public void onDismissed(Snackbar transientBottomBar, int event) {
                    super.onDismissed(transientBottomBar, event);
                }
            });
            snackbar.show();
    

    6.TextInputLayout

    MD风格的带有提示的EditText
    1.使用:

             <android.support.design.widget.TextInputLayout
                    android:id="@+id/text_input"
                    app:errorEnabled="true"
                    app:errorTextAppearance="@android:color/holo_red_dark"
                    app:hintTextAppearance="@android:color/darker_gray"
                    app:counterTextAppearance="@android:color/holo_green_dark"
                    app:counterOverflowTextAppearance="@android:color/holo_orange_dark"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
    
                    <EditText
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="请输入"/>
    
                </android.support.design.widget.TextInputLayout>
    

    其中TextInputLayout属性:
    app:errorEnabled="true" 是否开启错误提示
    app:errorTextAppearance="@android:color/holo_red_dark" 自定义错误提示字体的颜色和大小等 app:hintTextAppearance="@android:color/darker_gray" 自定义hint字体的样式
    app:counterTextAppearance="@android:color/holo_green_dark" 自定义计数字体的样式
    app:counterOverflowTextAppearance="@android:color/holo_orange_dark"自定义字数超过最大值时 字体的样式
    app:counterEnabled="true" 是否开启计数
    app:counterMaxLength="20" 能输入的最大值
    app:hintAnimationEnabled="true" hint移动到EditText上方时的动画是否开启
    app:hintEnabled="false" 是否允许hint移动到EditText上方

    1. 自定义EditText错误监听
           text_input.getEditText().addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    String string = text_input.getEditText().getText().toString();
                    if(!TextUtils.isEmpty(string)){
                        if(string.length() <= 6 ){
                            text_input.setErrorEnabled(false);
                        }else{
                            text_input.setErrorEnabled(true);
                            text_input.setError("长度不可大于6位");
                            
                        }
                    }
    
                }
            });
    

    7.Toolbar

    顶部导航:显示标题、返回键、快捷操作、菜单等。Toolbar不一定要放在顶部,也可以放底部。
    使用时要注意,把主题设置成NoActionBar.
    在ToolBar上设置菜单

       //重写 oncreateOptionsMenu
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main,menu);
            return true;
        }
    

    app:popupTheme 弹出菜单样式
    菜单中设置:
    orderInCategory:设置菜单项的排列顺序,必须设置大于等于0的整数值。数值小的排列在前,如果值相等,则按照xml中的顺序展现。
    showAsAction
    该属性有五个值,可以混合使用。
    always
    总是显示在Toolbar上。
    ifRoom
    如果Toolbar上还有空间,则显示,否则会隐藏在溢出列表中。
    never
    永远不会显示在Toolbar上,只会在溢出列表中出现。
    withText
    文字和图标一起显示。
    collapseActionView
    声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。一般要配合ifRoom一起使用才会有效。

    8 SearchView

    1.在xml中使用,在menu中设置

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item
            android:id="@+id/action_search"
            android:orderInCategory="100"
            app:showAsAction="always"
            app:actionViewClass="android.support.v7.widget.SearchView"
            android:title="搜索"
            />
    
        <item
            android:id="@+id/action_share"
            android:orderInCategory="100"
            app:showAsAction="ifRoom"
            android:title="分享"
            />
    </menu>
    

    在代码中对searchView进行操作

      //重写 oncreateOptionsMenu
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main,menu);
            
            //1.找到SearchView
            MenuItem item = menu.findItem(R.id.action_search);
            SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
    
            //2. 使用官方api设置searchView
            //设置一出来就直接呈现搜索框---SearchView
            searchView.setIconified(false);
            //进来就呈现搜索框并且不能被隐藏
            searchView.setIconifiedByDefault(false);
            //设置提交按钮是否可用(可见)
            searchView.setSubmitButtonEnabled(true);
            //监听焦点改变
            searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
    
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    // TODO Auto-generated method stub
    
                }
            });
            //searchView的关闭监听
            searchView.setOnCloseListener(new SearchView.OnCloseListener() {
    
                @Override
                public boolean onClose() {
                    // TODO Auto-generated method stub
                    return false;
                }
            });
            searchView.setOnSearchClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    Toast.makeText(DrawerlayoutActivity.this, "提交", 0).show();
                }
            });
            //监听文本变化,调用查询
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    
                @Override
                public boolean onQueryTextSubmit(String text) {
                    //提交文本
                    Toast.makeText(DrawerlayoutActivity.this, "提交文本:"+text, 0).show();
                    return false;
                }
    
                @Override
                public boolean onQueryTextChange(String text) {
                    // 文本改变的时候回调
                    System.out.println("文本变化~~~~~"+text);
    
                    return false;
                }
            });
    
            //3.自定义一些需要的样式  查看源码v7包中的abc_search_view.xml
            // 找到id 通过findViewById找到控件,进行自定义
    
            //自定义go_btn按钮
            ImageView icon = (ImageView) searchView.findViewById(R.id.search_go_btn);
            icon.setImageResource(R.drawable.ic_event);
            icon.setVisibility(View.VISIBLE);
    
            //自定义EditText
            SearchView.SearchAutoComplete et =  searchView.findViewById(R.id.search_src_text);
            et.setHint("输入商品名或首字母");
            et.setHintTextColor(Color.WHITE);
    
            
            return true;
        }
    

    9.Palette 调色板

    使用之前添加:

     implementation 'com.android.support:palette-v7:27.1.1'
    

    分析已有图片的色彩特性:主色调、鲜艳的颜色、柔和颜色等等
    用法:

            BitmapDrawable drawable = (BitmapDrawable) iv.getDrawable();
            Bitmap bitmap = drawable.getBitmap();
            //得到bitmap里面的的一些色彩信息---通过Palette类分析出来的
    //异步任务---可能分析的图片会比较大或者颜色分布比较复杂,会耗时比较久,防止卡死主线程。
            Palette.from(bitmap).generate(new PaletteAsyncListener() {
                
                @Override
                public void onGenerated(Palette palette) {
                    //暗、柔和的颜色
                    int darkMutedColor = palette.getDarkMutedColor(Color.BLUE);//如果分析不出来,则返回默认颜色
                    //亮、柔和
                    int lightMutedColor = palette.getLightMutedColor(Color.BLUE);
                    //暗、鲜艳
                    int darkVibrantColor = palette.getDarkVibrantColor(Color.BLUE);
                    //亮、鲜艳
                    int lightVibrantColor = palette.getLightVibrantColor(Color.BLUE);
                    //柔和
                    int mutedColor = palette.getMutedColor(Color.BLUE);
                    //鲜艳
                    int vibrantColor = palette.getVibrantColor(Color.BLUE);
                    //获取某种特性颜色的样品
    //              Swatch lightVibrantSwatch = palette.getLightVibrantSwatch();
                    Swatch lightVibrantSwatch = palette.getVibrantSwatch();
                    //谷歌推荐的:图片的整体的颜色rgb的混合值---主色调
                    int rgb = lightVibrantSwatch.getRgb();
                    //谷歌推荐:图片中间的文字颜色
                    int bodyTextColor = lightVibrantSwatch.getBodyTextColor();
                    //谷歌推荐:作为标题的颜色(有一定的和图片的对比度的颜色值)
                    int titleTextColor = lightVibrantSwatch.getTitleTextColor();
                    //颜色向量
                    float[] hsl = lightVibrantSwatch.getHsl();
                    //分析该颜色在图片中所占的像素多少值
                    int population = lightVibrantSwatch.getPopulation();
                    
                    //使用分析出的颜色
                    tv_title.setBackgroundColor(getTranslucentColor(0.6f,rgb));
                    tv_title.setTextColor(titleTextColor);
                    
                    tv1.setBackgroundColor(darkMutedColor);
                    tv1.setText("darkMutedColor");
                    tv2.setBackgroundColor(lightMutedColor);
                    tv2.setText("lightMutedColor");
                    tv3.setBackgroundColor(darkVibrantColor);
                    tv3.setText("darkVibrantColor");
                    tv4.setBackgroundColor(lightVibrantColor);
                    tv4.setText("lightVibrantColor");
                    tv5.setBackgroundColor(mutedColor);
                    tv5.setText("mutedColor");
                    tv6.setBackgroundColor(vibrantColor);
                    tv6.setText("vibrantColor");
                    
                }
            });
            
            
        }
    
        protected int getTranslucentColor(float percent, int rgb) {
            // 10101011110001111
            int blue = Color.blue(rgb);
            int green = Color.green(rgb);
            int red = Color.red(rgb);
            int alpha = Color.alpha(rgb);
    
    //      int blue = rgb & 0xff;
    //      int green = rgb>>8 & 0xff;
    //      int red = rgb>>16 & 0xff;
    //      int alpha = rgb>>>24;
            
            alpha = Math.round(alpha*percent);
            return Color.argb(alpha, red, green, blue);
        }
    

    10.TabLayout

    1.TabLayout和ViewPager一起用:
    tablayout.setupWithViewPager(mViewPager);
    tablayout.setTabMode(TabLayout.MODE_FIXED);
    在xml文件中:
    app:tabMode 与 app:tabGravity 一起使用 可以改变标签的位置
    tabMode :fixed 适应屏幕填充,不能滑动 SCROLLABLE:标签可以滑动
    tabGravity:fill tab平均填充整个宽度 center tab居中显示
    2.自定义Tab

           for(int i = 0;i< tablayout.getTabCount();i++){
                TabLayout.Tab tab = tablayout.getTabAt(i);
                View view = View.inflate(this,layoutId,null);
                TextView tv_title =  view.findViewById(R.id.tv_title);
                tv_title.setText(titles[i]);
                tab.setCustomView(view);//自定义Tab
            }
    
    

    11 沉浸式设计

    官方的沉浸式: 就是让整个App充满了整个屏幕,没有显示状态栏,没有显示底部导航栏,而现在我们常说的沉浸式就是状态栏和ToolBar颜色一致。
    沉浸式开发, Api必须 > 4.4 Api低于4.4的官方系统无法做到沉浸式,但有些品牌的系统做了处理,Api < 4.4也可以做到沉浸式 所以在做沉浸式开发时,需要判断手机品牌和系统。
    做沉浸式兼容时,需要判断当前SDK版本,4.4 和5.0是两个分割线

    
    

    沉浸式ToolBar

    1.Android5.0之后,

    系统已经实现了沉浸式设计,想要修改状态栏的颜色可以有几种办法:

    1)

    直接修改主题中的colorPrimaryDark ,但这种方式会使整个App的主题都是这个颜色

    2)

    修改<item name="android:navigationBarColor">@color/colorPrimary</item>
    这个属性需要写在style-21文件中

    3)

    代码中修改:
    getWindow().setStatusBarColor(getResources().getColor(R.color.cardview_dark_background));

    2.Android4.4 设置沉浸式状态栏

    方法1:

    在主题中设置:<item name="android:windowTranslucentStatus">true</item>

    方法2:

    1)设置状态栏透明
    2)在toolbar中添加属性 android:fitsSystemWindows="true"
    但是这种办法在布局中有scrollView时会有bug,布局中没有scrollView时可以使用。
    如果非要使用的话,需要在最外层的布局中添加属性
    android:fitsSystemWindows="true"
    android:clipToPadding="true"
    android:background="@color/colorPrimary"
    把最外层布局的背景设置成和toolbar相同的颜色,再把状态栏和ToolBar之外的部分设置成背景色。

    方法3:

    1)设置状态栏透明
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    2)获取状态栏高度,把toolbar用一个布局包裹,布局的高度为toolbar.height+status.height 或者直接修改ToolBar的高度
    给Toolbar设置 android:fitsSystemWindows="true"
    第2步还可以设置ToolBar的paddingTop:
    toolbar.setPadding(toolbar.getPaddingLeft(),toolbar.getPaddingTop()+getStatusBarHeight(this), toolbar.getPaddingRight(),toolbar.getPaddingBottom());

    沉浸式NavigationBar 底部虚拟导航

    1 Android5.0之后

    1) 属性解决
    在主题中设置
    <item name="android:navigationBarColor">@color/colorPrimary</item>
    在style-21上设置
    2)代码解决
    在setContentView之前设置
    getWindow().setNavigationBarColor(color);

    2 Android 4.4 - Android5.0

    方法1

    1.虚拟导航栏设置为透明
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    2.反射拿到底部导航栏的高度:

         /**获取底部导航栏的高度*/
         private int getNavigationBarHeight(Context context) {
            return getSystemComponentDimen(this, "navigation_bar_height");
          }
    
        /**
         * 获取状态栏的高度
         * @param context
         * @return
         */
        private int getStatusBarHeight(Context context) {
            // 反射手机运行的类:android.R.dimen.status_bar_height.
            return getSystemComponentDimen(this, "status_bar_height");
        }
        
        public static int getSystemComponentDimen(Context context, String dimenName){
            // 反射手机运行的类:android.R.dimen.status_bar_height.
            int statusHeight = -1;
            try {
                Class<?> clazz = Class.forName("com.android.internal.R$dimen");
                Object object = clazz.newInstance();
                String heightStr = clazz.getField(dimenName).get(object).toString();
                int height = Integer.parseInt(heightStr);
                //dp--->px
                statusHeight = context.getResources().getDimensionPixelSize(height);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return statusHeight;
        }
    

    3.使用一个View放在底部,设置高度为1dp,如果能够获取到navigationBar的高度,就把高度设置给View view的颜色设置成想要设置成的颜色即可。

    12.CardView

    兼容性开发,准备两套布局,一套放在layout文件夹下,一套放在layout-v21文件夹下。5.0以上不需要设置contentPadding属性 而 4.x需要设置contentPadding属性
    5.0以上
    1.阴影一般为16dp
    2.点击cardView有水波纹效果:android:foreground="?attr/selectableItemBackground"
    android:clickable="true"
    3.按下z轴位移效果
    自定义动画 z轴平移动画

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item
            android:state_pressed="true">
            <objectAnimator
                android:duration="@android:integer/config_shortAnimTime"
                android:propertyName="translationZ"
                android:valueTo="15dp"
                android:valueType="floatType"
                />
        </item>
    
        <item>
            
            <objectAnimator
                android:duration="@android:integer/config_shortAnimTime"
                android:propertyName="translationZ"
                android:valueTo="0dp"
                android:valueType="floatType"
                />
        </item>
    
    
    </selector>
    
    
    使用:android:stateListAnimator="@drawable/z"
    

    13.FloatingActionButton 悬浮动作按钮

    兼容性开发:fab的宽高是58dp
    1.需要写两个layout/layout-v21
    layout-v21:添加layout_margin="16dp"
    layout: 添加layout_margin="0dp"
    2.水波纹效果
    5.0以上才有水波纹的效果:
    app:rippleColor="#f00"//水波纹的颜色
    android:clickable="true"//注意 要设置该属性才会有水波纹效果
    3.按下Z轴移动动画
    app:pressedTranslationZ="12dp"//z轴动画
    其他:
    app:srcCompat="@android:drawable/ic_dialog_email"//设置src
    android:backgroundTint="@color/colorAccent"//设置FAB
    背景色
    app:fabSize="mini" fab的大小
    4.锚:anchor
    app:layout_anchor=”@id/appbar”
    app:layout_anchorGravity=”end|bottom|right”
    app:layout_anchor设置这个属性可以让FloatingActionButton以某一个控件为基准调整位置,我们这里设置这个控件就是appbar
    app:layout_anchorGravity
    设置基于appbar控件的位置,我们这里设置了end|bottom|right
    这样两行代码就可以将FloatingActionButton设置在appbar的右下角,并且行为会和appbar的滚动行为协作。

    传统方式滑动RecyclerView实现ToolBar和Fab的显示和隐藏

    14. CoordinatorLayout

    继承自ViewGroup。
    通过协调并调度里面的子控件或者布局来实现触摸(一般是指滑动)产生一些相关的动画效果。
    可以通过设置view的Behavior来实现触摸的动画调度。
    点击Fab弹出SnackBar,SnackBar弹出后会遮挡住Fab,需要把最外层的布局更改为CoordinatorLayout即可。

    使用CoordinatorLayout 和 beHavior来实现随RecyclerView的滑动ToolBar和fab显示和隐藏效果。
    原理:fab需要监听RecyclerView的滑动,给fab设置behavior,在behavior中有几个回调方法,当RecyclerView滑动时,就会回调那几个方法,把滑动状态告诉fab,我们一般所写的behavior都是继承自CoordinatorLayout.Behavior,而CoordinatorLayout位于最外层,当触摸事件发生时,CoordinatorLayout负责事件分发和传递,CoordinatorLayout可以通过behavior把事件传递给fab,同时作用到fab。
    简单的说,CoordinatorLayout的作用就是监听滑动控件的滑动通过Behavior反馈到其他子控件并执行一些动画。滑动控件是指:
    RecyclerView/NestedScrollView/ViewPager 而ListView/ScrollView不可以。

    1# fab的显示和隐藏。
    xml中 编写xml时要注意:
    1.最外层控件使用CoordinatorLayout
    2.fab要设置app:layout_behavior=“com.kimliu.materialdesign.behavior.FabBehavior”
    属性值为自定义behavior

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        >
    
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:clipChildren="false"
            android:paddingTop="?attr/actionBarSize"/>
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@android:color/white"
            app:title="ToolBar"
            />
    
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:layout_margin="16dp"
            app:layout_behavior="com.kimliu.materialdesign.behavior.FabBehavior"
            android:layout_gravity="bottom|end"
            android:src="@android:drawable/ic_delete"/>
        
    </android.support.design.widget.CoordinatorLayout>
    

    代码:只需要写一个自定义behavior即可

    public class FabBehavior extends FloatingActionButton.Behavior {
    
        public FabBehavior() {
    
        }
    
        public FabBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        private boolean visible = true;
    
        @Override
        public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                           @NonNull FloatingActionButton child,
                                           @NonNull View directTargetChild,
                                           @NonNull View target, int axes, int type) {
            return
                    super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
        }
    
        @Override
        public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                           @NonNull FloatingActionButton child,
                                           @NonNull View directTargetChild,
                                           @NonNull View target, int axes) {
            return axes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes);
        }
    
        @Override
        public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                   @NonNull FloatingActionButton child,
                                   @NonNull View target, int dxConsumed,
                                   int dyConsumed, int dxUnconsumed,
                                   int dyUnconsumed, int type) {
            super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
            // 当观察的view滑动的时候回调的
            //根据情况执行动画
            if(dyConsumed>0&&visible){
                //向上滑动 且可见 隐藏
                visible = false;//不可见
                onHide(child);
            }else if(dyConsumed<0){
                //向下滑动
                visible = true;
                onShow(child);
            }
        }
    
    
        public void onHide(FloatingActionButton fab) {
            // 隐藏动画--属性动画
    //      toolbar.animate().translationY(-toolbar.getHeight()).setInterpolator(new AccelerateInterpolator(3));
            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) fab.getLayoutParams();
    
            fab.animate().translationY(fab.getHeight()+layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));
    //        ViewCompat.animate(fab).scaleX(0f).scaleY(0f).start();
        }
    
        public void onShow(FloatingActionButton fab) {
            // 显示动画--属性动画
    //      toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
    
            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) fab.getLayoutParams();
            fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
    //        ViewCompat.animate(fab).scaleX(1f).scaleY(1f).start();
        }
    }
    

    2 Toolbar的滑动和隐藏

    只需要在xml中设置,关键点:
    1.ToolBar需要包裹在AppBarLayout中
    2.AppBarLayout中的控件都有一个属性layout_scrollFlags
    这个属性有5个值,分别是:
    scroll:所有想滚动出屏幕的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。
    enterAlways:这个flag让任意向下的滚动都会导致该view变为可见,启用快速“返回模式”。
    enterAlwaysCollapsed:假设你定义了一个最小高度(minHeight)同时enterAlways也定义了,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
    exitUntilCollapsed:当你定义了一个minHeight,此布局将在滚动到达这个最小高度的时候折叠。
    snap:当一个滚动事件结束,如果视图是部分可见的,那么它将被滚动到收缩或展开。例如,如果视图只有底部25%显示,它将折叠。相反,如果它的底部75%可见,那么它将完全展开。
    3.RecyclerView 要设置一个behavior app:layout_behavior="@string/appbar_scrolling_view_behavior"

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        >
        
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            />
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize">
    
        <android.support.v7.widget.Toolbar
            app:layout_scrollFlags="scroll|enterAlways"
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@android:color/white"
            app:title="ToolBar"
            />
        </android.support.design.widget.AppBarLayout>
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:layout_margin="16dp"
            app:layout_behavior="com.kimliu.materialdesign.behavior.FabBehavior"
            android:layout_gravity="bottom|end"
            android:src="@android:drawable/ic_delete"/>
    
    </android.support.design.widget.CoordinatorLayout>
    

    3.AppBarLayout和NestedScrollView结合使用

    要在NestedScrollView上添加属性:
    app:layout_behavior="@string/appbar_scrolling_view_behavior"

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.ricky.materialdesign.fab.animation.MainActivity" >
    
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" >
    
            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
    
                <android.support.v7.widget.CardView
                    android:layout_width="300dp"
                    android:layout_height="200dp"
                    android:layout_margin="0dp"
                    app:cardCornerRadius="20dp"
                    app:cardElevation="10dp"
                    app:contentPadding="5dp" >
    
                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:scaleType="centerCrop"
                        android:src="@drawable/tulips2" />
                </android.support.v7.widget.CardView>
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize" >
    
            <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:background="?attr/colorPrimary" />
        </android.support.design.widget.AppBarLayout>
    
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            app:layout_behavior="com.ricky.materialdesign.fab.animation.FabBehavior"
            android:onClick="rotate"
            android:src="@drawable/ic_favorite_outline_white_24dp" />
    
    </android.support.design.widget.CoordinatorLayout>
    

    4.AppBarLayout和ViewPager结合使用

    在ViewPager上设置属性:app:layout_behavior="@string/appbar_scrolling_view_behavior"

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent" xmlns:app1="http://schemas.android.com/apk/res/com.ricky.materialdesign.tablayout">
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
    
            <android.support.v7.widget.Toolbar
                app1:layout_scrollFlags="scroll|enterAlways"
                 android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                >
            </android.support.v7.widget.Toolbar>
            <android.support.design.widget.TabLayout
                app1:layout_scrollFlags="scroll|enterAlways"
                android:id="@+id/tablayout"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                app1:tabBackground="@color/material_deep_teal_200"
                app:tabGravity="fill"
                app:tabIndicatorColor="@color/colorPrimary_pink"
                app:tabMode="scrollable"
                app:tabSelectedTextColor="@color/colorPrimary_pinkDark"
                app:tabTextColor="@color/colorPrimary_pink" />
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/vp"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    
    </android.support.design.widget.CoordinatorLayout>
    

    5.ToolBar的折叠与隐藏 CollapsingToolbarLayout的使用

    CollapsingToolbarLayout需要包裹在AppBarLayout中使用。

    注意:

    1.既然是需要折叠toolbar的高度,那么CollapsingToolbarLayout的高度应设置为match_parent
    2. AppBarLayout需要设置固定高度,要实现折叠效果,这个高度需要比toolbar的高度高
    3.要实现折叠效果,需要给CollapsingToolbarLayout设置属性: app:layout_scrollFlags="scroll|enterAlways"

    属性:

    1.在CollapsingToolbarLayout中的子控件都会有这个属性:
    app:layout_collapseMode="" 它有三个值:none/pin/parallax
    none:没有任何效果,往上滑动的时候toolbar会首先被固定并推出去。
    parallax:在滑动的时候这个View 会呈现 出 视觉特差效果
    layout_collapseParallaxMultiplier:值为0-1之间 与parallax结合使用,
    pin:当这个View到达 CollapsingToolbarLayout的底部的时候,这个View 将会被放置,即代替整个CollapsingToolbarLayout
    2.contentScrim :当CollapsingToolbarLayout完全折叠后的背景颜色。
    通常设置为:app:contentScrim=”?attr/colorPrimary”,这样当CollapsingToolbarLayout完全折叠后就会显示主题颜色。
    3.expandedTitleMarginStart :布局张开的时候title与左边的距离
    4.app:collapsedTitleGravity="center_horizonta"折叠后标题的gravity

    1. layout_scrollFlags: 设置滚动表现:
      1、 Scroll, 表示手指向上滑动的时候,CollapsingToolbarLayout也会向上滚出屏幕并且消失,这个属性必须要有。
      2、 exitUntilCollapsed: 表示这个layout会一直滚动离开屏幕范围,直到它收折成它的最小高度.
      (如果设置了该属性,toolbar最后会停留在最高处,如果没有设置,toolbar最终会滚出屏幕)
      3、enterAlways: 一旦手指向下滑动这个view就可见。
      4、enterAlwaysCollapsed: 这个flag定义的是已经消失之后何时再次显示。假设你定义了一个最小高度(minHeight)同时enterAlways也定义了, 那么view将在到达 这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
      即当你的视图设置了minHeight属性的时候,那么视图只能以最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="250dp">
    
    
            <android.support.design.widget.CollapsingToolbarLayout
                app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
                android:layout_width="match_parent"
                app:statusBarScrim="@android:color/white"
                app:contentScrim="@android:color/transparent"
                android:layout_height="200dp">
    
    
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:src="@drawable/mao"
                    android:scaleType="fitXY"
                    app:layout_collapseMode="parallax"/>
    
                <android.support.v7.widget.Toolbar
                    android:layout_width="match_parent"
                    app:title="nnn"
                    app:layout_collapseMode="pin"
                    app:navigationIcon="@drawable/ic_record"
                    app:titleTextColor="@android:color/white"
                    android:layout_height="?attr/actionBarSize">
                    
                </android.support.v7.widget.Toolbar>
                
            </android.support.design.widget.CollapsingToolbarLayout>
            
            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="TabLayout"
                android:textSize="20sp"
                android:textColor="@color/colorPrimary"
                android:gravity="center"
                />
            
        </android.support.design.widget.AppBarLayout>
    
    
        <android.support.v4.widget.NestedScrollView
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:text="NestedScrollView"
                    android:textSize="20sp"
                    android:textColor="@color/colorPrimary"
                    android:gravity="center"/>
              
            </LinearLayout>
            
        </android.support.v4.widget.NestedScrollView>
        
    </android.support.design.widget.CoordinatorLayout>
    

    15.自定义Behavior

    Behavior:抽象类,监听者,包裹在其中的所有子控件或者容器产生联动效果。
    Behavior可以做到两种情况:
    1.某个View需要监听另一个View的状态(比如:位置,大小,显示状态)
    (需要重写layoutDependsOn/onDependentViewChanged)
    demo: 当点击TextView时,另一个TextView跟着一起动
    xml:

    <?xml version="1.0" encoding="utf-8"?>
    <!--1.最外层 CoordinatorLayout-->
    <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"
        tools:context="com.kimliu.materialdesign.customBehavior.Main4Activity">
    
        <TextView
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="@android:color/holo_blue_dark"
            android:onClick="down"
            android:layout_gravity="left|top"
            android:text="被观察者----dependecy"/>
    
    
        <!--2.在观察者上设置behavior-->
        <TextView
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_gravity="right|top"
            app:layout_behavior="com.kimliu.materialdesign.customBehavior.CustomBehavior"
            android:background="@android:color/holo_orange_dark"
            android:text="观察者"/>
    
    </android.support.design.widget.CoordinatorLayout>
    

    java:

    public class CustomBehavior extends CoordinatorLayout.Behavior {
        
        public CustomBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        /**
         *用来决定需要监听那些控件或容器的状态
         * @param parent 父容器
         * @param child 子控件  监听别人的view 如果有多个,每个都要配置behavior 然后用id判断是谁
         * @param dependency 被观察者 被监听的view
         * @return 两种条件:1.知道监听的是哪个控件 2. 知道这个控件是什么状态改变 如果这两个条件都知道 return true
         *          如果返回true 会调 onDependentViewChanged()
         */
        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
    
            return dependency instanceof TextView || super.layoutDependsOn(parent, child, dependency);
        }
    
        /**
         *当被监听的view发生改变时回调,可以在其中做一些联动动画
         * @param parent
         * @param child
         * @param dependency
         * @return
         */
        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
            
            int offset = dependency.getTop() - child.getTop();
            ViewCompat.offsetLeftAndRight(child,-offset);
            //child垂直方向平移offset
            ViewCompat.offsetTopAndBottom(child,offset);
    
            return super.onDependentViewChanged(parent, child, dependency);
        }
    }
    

    2.某个View需要监听CoordinatorLayout里面所有控件的滑动状态。
    (需要重写方法:onStartNestedScroll / onNestedScroll / onNestedPreScroll )
    能被CoordinatorLayout捕获到滑动状态的控件有: NestedScrollView / RecyclerView / ViewPager
    跟1相似,只是重写的方法不同而已,就不再赘述。

    相关文章

      网友评论

        本文标题:Material Design

        本文链接:https://www.haomeiwen.com/subject/wtfqsftx.html