MaterialDesign 笔记

TabLayout和TabLayout.Tab

  1. 使用场景
    在ViewPager的上方,通常我们都会放一个标签指示器与ViewPager进行联动; 以前通常使用开源的框架,或者自定义view;现在google提供的解决办法

  2. 使用方法

    通常我们调用TabLayout.setupWithViewPager和ViewPager进行关联, 每个Tab的内容从PagerAdapter.getPageTitle方法获取;

    也可以自己设置每个Tab的内容, 代码如下

     TabLayout tabLayout = ...;
     TabLayout.Tab tab = tabLayout.newTab();  // 创建tab
     tab.setText("Tab 1");       // 设置每个tab的属性
     tabLayout.addTab(tab);
    

    显示的模式有2种, 一种固定宽度TabLayout.MODE_FIXED, 一种可以滚动TabLayout.MODE_SCROLLABLE; 默认是MODE_FIXED, 可以通过代码,也可以通过xml属性设置

    常见属性

     @dimen/tab_max_width
     ?attr/colorAccent
     2dp
     12dp
     12dp
     ?attr/selectableItemBackground
     @style/TextAppearance.Design.Tab
     ?android:textColorPrimary
    

    https://guides.codepath.com/android/google-play-style-tabs-using-tablayout#design-support-library
    可以参考的链接

CoordinatorLayout AppbarLayout CollapsingToolbarLayout

  1. CoordinatorLayout作用
    CoordinatorLayout作用可以从名称看出,作为一个协调者; 主要用来协调调度子View; 分两个方面来协调, 协调子View的布局 和协调子View的事件分发

  2. 解决的问题

    • 子View事件分发的困境;
      在原先View的事件分发设计模型中, 事件由 dispatchTouchEvent分发, 然后由 onIntercepteTouchEvent负责拦截, 最后在onTouchEvent中处理, ActionDown事件一旦被接收, 后续事件将默认给此view处理, 其他view无法接收事件, 当有多个view需要同时处理一个滑动事件时, 原先的事件分发无法解决; 原先一旦遇到这种情况,只有自己去自定义view, 重写事件分发过程, 现在通过CoordinatorLayout可以优雅的解决这个问题;

      NestedScroll: 解决父子view的同时处理同一事件的流程
      CoordinatorLayout: 解决并列的兄弟View处理同一事件的流程

    • 子View布局的困境
      和子view的事件分发一样, 原先每个子View布局位置, 是在父ViewGroup的layout方法中确定; 而当需要子view的布局位置, 跟随另一个子view变化时,绝大部分情况, 需要自定义view; 而现在CoordinatorLayout也可以优雅的解决这个问题

  3. 使用
    使用很简单, 使用CoordinatorLayout作为父ViewGroup, 子view在xml中指定app:behavior; 指定的behavior都是继承于CoordinatorLayout.Behavior, Behavior类提供的接口中, 可以定义该子View需要和另外哪些子view关联, 关联的子view发生变化时, 自身怎么处理; 当父CoordinatorLayout接收到滑动事件时, 该子view怎么处理;

    Behavior需要自己去自定义, 不过系统默认提供几种常用的behavior; 具体介绍, 下面再说

  4. 原理

    • 子view接收处理的事件如何交给父CoordinatorLayout去分发
      上面说过,父子view协同处理滑动事件, google官方很早给出了NestedScroll; 同时也在v4包中提供了NestedScrillingChild, NestedScrollingChildHelper, NestedScrollingParentNestedScrollingParentHelper, 帮助我们解决嵌套的滚动问题;

      CoordinatorLayout实现的NestedScrollingParent接口, 因此当子view实现了NestedScrillingChild接口时,可以收到子view的滑动事件; 同时,原先系统的ScrollView, ListView都未实现NestedScrillingChild, 所以放在CoordinatorLayout中用于滚动的view一般是RecyclerView, NestedScrollView

    • 子view接收兄弟view的滑动事件并消耗掉
      上面说到子view把滑动事件交给CoordinatorLayout去处理, 子View接收消耗兄弟view的的事件,就是CoordinatorLayout接收到事件后, 调用兄弟view的behavior的方法, 由我们自定义behavior去处理

    • 子view跟随兄弟view变化而变化
      和上面一样, 布局原先是有layout方法决定, 而在CoordinatorLayout中, 在layout的过程中, 会调用behavior中的方法,以方便自己调整布局

    从RecyclerView开始, View设计思想有所转变; 组合优于继承, 约定优于配置,体现的很明显
    多组合而少继承; 推荐扩展指定的组件实现功能, 而不是通过自定义view去实现功能; eg: 使用behavior去控制CoordinatorLayout的事件分发;使用LayoutMananger去控制recyclerview的布局

和AppbarLayout, CollapsingToolbarLayout 结合使用

  1. 作用
    AppbarLayout一般放在CoordinatorLayout中使用, 可以使不具有处理滚动事件的view, 产生滚动效果; AppBarLayout会默认和AppBarLayout.Behavior关联, 而该behavior中会帮我们处理滚动事件

    CollapsingToolbarLayout提供视差滚动, 和调整滚动时 状态栏和toolbar颜色配置的功能

  2. AppbarLayout的使用
    AppBarLayout继承与LinearLayout, 可以为每个子view设置app:layout_scrollFlags属性, 用于去控制子view的滚动
    滚动属性有如下几种

    • scroll 该子view可以滚动
    • enterAlways 当有向下滚动事件时,改view就马上显示
    • scrollUntilCollpse 向上滚动搜索直至最小高度, 需要和minHeight一起用
    • snap 滚动只能在开始位置或者结束位置停下
     
    
         
    
             
    
         
    
         
    
             
    
             
    
         
    
     

一般在布局中, 遇到三段式布局, 并且布局布局要求滚动, 就可以考虑使用了

SnakeBar FloatActionButton

SnakeBar和Toast类似, 仅用于提示信息, 代码写法也和toast相似

Snackbar.make(mCoordinatorLayout, "显示snackBar", Snackbar.LENGTH_SHORT).show();

BottomSheetBehavior BottomSheetDialog

使View从底部弹出, 分两段显示的一个Coordinator.Behavior, 必须使用在CoordinatorLayout中;

对需要使用的的View,在布局中添加上app:layout_behavior="@string/bottom_sheet_behavior"属性即可

常用的有3中模式状态, 展开STATE_EXPANDED, 收缩STATE_COLLAPSED, 隐藏STATE_HIDDEN, 隐藏后,一般需要通过代码使其展开

在代码中使用

View view = ....;
final BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED)      // 设置状态

常用属性

app:behavior_hideable="true"        // 是否可以隐藏
app:behavior_peekHeight="100dp"     // 坍塌时的高度

BottomSheetDialog是BottomSheet的dialog实现形式; 实现比较巧妙, BottomSheetDialog继承于Dialog,在构造时,会创建CoordinatorLayout, 然后拿到dialog对应的window的decorView, 将其添加到CoordinatorLayout中, 从而实现BottomSheetBehavior

Ripple animattion

水波纹动画目前仅支持api>21的版本
属于view的背景效果,放在drawable文件下, 由于只支持21之上,一般需要针对不同的版本提供2套背景, drawable-v21目录使用水波纹悲剧, drawable目录使用普通背景

创建内容很简单

    
        
    

有无界unbounded和有边境之分, 如果ripple中间没有item, 就为unbounded的, 水波纹可以扩散到其他view的背景中去

Reveal animator

揭露动画, 目前也仅支持api>21

通过ViewAnimationUtils.createCircularReveal创建, 返回的是一个Animator对象;

    // 创建揭露动画, 
    Animator revealAnimator = ViewAnimationUtils.createCircularReveal( animatorView, x, y, 0, animatorView.getWidth() );

stateListAnimator

View的状态动画, 和view的状态背景相似
动画文件放在animator目录下,

参考链接

Transtions 转场动画

新的过渡动画,仍然只兼容api>21的版本
示例demo可以参考 https://github.com/lgvalle/Material-Animations

过渡动画

原先的过渡动画Activity.overridePendingTransition,只有进入,退出两种, 现在有了4种;

分别为以下4种;
EnterTransition <--> ReturnTransition
ExitTransition <--> ReenterTransition

假设Activity A 启动Activity B;
A退出时,触发ExitTransition; 跳转到B, 进入到B时, 触发EnterTransition;
从B点击返回键,退回到A时
B触发ReturnTransition, 返回到A时, 触发A的ReenterTransition

目前支持的动画, 有Explode, Fade, Slide几种, 动画支持在主题中配置,和使用代码设置, 和原先的过渡动画相似

  • 在主题中配置动画示例

    1. 创建动画文件

      android:duration="1000"/>
    2. 在主题中使用属性引用动画文件



  • 手动配置示例
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_transition);
    setupWindowAnimations();
    }

     private void setupWindowAnimations() {
         Slide slide = TransitionInflater.from(this).inflateTransition(R.transition.activity_slide);
         getWindow().setExitTransition(slide);
     }
    

如果只配置EnterTransition,没有配置ReturnTransition, 在返回时, 将会把EnterTransition反过来运行一遍

退出时需要运行ReturnTransition和ReenterTransition试, 不能直接调用Activity.finish方法, 要改为调用Activity.finishAfterTransition, 如果各版本要保持相同的代码, 可以调用ActivityCompactActivityCompat方法

共享元素的过渡动画

  1. 在主题中打开该功能, 如果使用的material design主题, 会默认打开

  2. 设置共享view的transition name; 2个共享view的android:transitionName属性必须一样
    android:id="@+id/small_blue_icon"
    style="@style/MaterialAnimations.Icon.Small"
    android:src="@drawable/circle"
    android:transitionName="@string/blue_name" />

  3. 使用新的api构建动画并启动actiivity
    blueIconImageView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    Intent i = new Intent(MainActivity.this, SharedElementActivity.class);

             View sharedView = blueIconImageView;
             String transitionName = getString(R.string.blue_name);
    
             ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
             startActivity(i, transitionActivityOptions.toBundle());
         }
     });
    

如果想要保持不同版本的代码一致, 可以使用v4包中的ActivityCompat.startActivity方法去启动activity

参考

https://developer.android.google.cn/training/material/index.html
http://wiki.jikexueyuan.com/project/material-design/whatis-material-design/environment.html
https://developer.android.google.cn/training/material/index.html

你可能感兴趣的:(MaterialDesign 笔记)