Material Designer设计(中)

来源:互联网 发布:厨师机 知乎 编辑:程序博客网 时间:2024/06/06 03:12

本文由小码哥出品,博文原创地址!

上一节主要是讲解MaterialDesign的一些简单案例,接下来要讲的是一个比较复杂的案例:CoordinatorLayout.实际上,它就是一个类似于5大布局的viewgroup.下面我们要实现的案例如下:

这里写图片描述

1.要展示上面的界面 需要在app的build.gradle中添加依赖脚本:

compile 'com.android.support:design:25.3.1'

2.找到对应的布局,添加代码:

<?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"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <!-- 创建顶部图片控件 AppBarLayout其父类是LinearLayout -->    <android.support.design.widget.AppBarLayout        android:layout_width="match_parent"        android:layout_height="wrap_content">        <!-- 这是内部的一个可以帮助我们上拉折叠的界面 -->        <android.support.design.widget.CollapsingToolbarLayout            android:layout_width="match_parent"            android:layout_height="wrap_content">            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:scaleType="fitXY"                android:src="@drawable/lf" />        </android.support.design.widget.CollapsingToolbarLayout>    </android.support.design.widget.AppBarLayout>    <!-- 创建底部可以滑动的文本界面 -->    <android.support.v4.widget.NestedScrollView        android:layout_width="match_parent"        android:layout_height="match_parent">        <TextView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:text="@string/content"/>    </android.support.v4.widget.NestedScrollView></android.support.design.widget.CoordinatorLayout>

如果细心一点你会发现我们的界面是没有ActionBar的 于是在styles.xml中修改如下:

<resources>    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">        <!-- Customize your theme here. -->    </style></resources>

于是界面展示如下,:

这里写图片描述

有没发现 文本被前面的图片控件隐藏掉了,显示不全,我们希望文字就显示在图片控件下。点击外部布局 可以看到CoordinatorLayout实际上是ViewGroup的子类。此时只需要在标签中添加一个属性layout_behavior即可达到想要的效果:

<android.support.design.widget.CoordinatorLayout    xmlns:app="http://schemas.android.com/apk/res-auto"  >    <android.support.v4.widget.NestedScrollView        app:layout_behavior="@string/appbar_scrolling_view_behavior" >    </android.support.v4.widget.NestedScrollView></android.support.design.widget.CoordinatorLayout>

现在效果差不多了 然后滑动的时候发现只有底部的文本控件才能滑动,为了让顶部的界面也可以跟着滑动,需要可折叠的控件CollapsingToolbarLayout添加一个属性:

app:layout_scrollFlags="scroll"

layout_scrollFlags的几个属性

  1. 除了scroll可以实现滑动之外,还有一个属性值enterAlways,添加了该属性后,如果你上面的图片被隐藏了,并且字体的上部分也被隐藏了,此刻下拉,不会按着顺序展示出来,而是每次都先展示完图片,再显示被隐藏的字体。

    app:layout_scrollFlags=”scroll|enterAlways”

这里写图片描述

2.还有一个属性,叫enterAlwaysCollapsed,该属性需要配合enterAlways一起属性,并且需要指定minHeight.代码如下:

    <android.support.design.widget.CollapsingToolbarLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:minHeight="100dp"        app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed" />

上面的代码运行效果是如下,下拉显示的时候 先显示特定的高度的图片,在慢慢显示文字,当文字显示到顶部的时候如下还往下拉,则会完全显示图片:

这里写图片描述

3.这里还有另外一个属性值exitUntilCollapsed。他可以帮助我们在上拉的过程中隐藏图片控件的只一部分。如下的代码,我们在上拉过程中图片会被部分隐藏,直到剩下高度的100dp位置可以停止隐藏,接着隐藏文字。

   <android.support.design.widget.CollapsingToolbarLayout       android:layout_width="match_parent"       android:layout_height="wrap_content"       android:minHeight="100dp"       app:layout_scrollFlags="scroll|exitUntilCollapsed" >

当然,为了达到我们上面案例的样子,需要去掉android:minHeight属性。

视差

在上拉的过程中,你会发现滑动的距离远大于图片被隐藏的距离。也就是图片是按着我们往上滑的距离进行比例隐藏的,这就是视差,如何设置才属性了,找到对应的图片添加属性即可 代码如下:

 <ImageView     android:layout_width="match_parent"     android:layout_height="200dp"     android:scaleType="fitXY"     android:src="@drawable/lf"     app:layout_collapseMode="parallax"     app:layout_collapseParallaxMultiplier="0.8" />

layout_collapseMode设置了parallax属性值代表以视差的方式滑动 下面的layout_collapseParallaxMultiplier属性指定了视差值的比例为0.8。

添加工具栏

为了让界面在上拉的过程中展示工具栏 这里需要给它添加一个ToolBar,因为CollapsingToolbarLayout是FrameLayout的子类,所以只需要在ImageView后面添加一个ToolBar则会覆盖在图片上面显示。?android:attr/actionBarSize高度指定的是工具栏的高度为系统ActionBar高度。

<android.support.design.widget.CollapsingToolbarLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            app:layout_scrollFlags="scroll|exitUntilCollapsed" >            <ImageView                android:layout_width="match_parent"                android:layout_height="200dp"                android:scaleType="fitXY"                android:src="@drawable/lf"                app:layout_collapseMode="parallax"                app:layout_collapseParallaxMultiplier="0.8" />            <android.support.v7.widget.Toolbar                android:layout_width="match_parent"                android:layout_height="?android:attr/actionBarSize"                android:background="@color/colorPrimary" />        </android.support.design.widget.CollapsingToolbarLayout>

上面的代码运行后,会发现工具栏跟着滑动一起被隐藏了实际上我们希望他置顶,那么应该添加滑动置顶的属性。那么你会想到的就是layout_collapseMode。pin值就是让某个控件可以在滑动的时候置顶的。并且一开始ToolBar是没有显示出来的,所以应该将颜色去掉。代码如下:

    <android.support.v7.widget.Toolbar        android:layout_width="match_parent"        android:layout_height="?android:attr/actionBarSize"        app:layout_collapseMode="pin" />

为了让图片在向上拉的过程中,逐渐渐变成某单一色块,那么我们需要为CollapsingToolbarLayout添加一个新的属性contentScrim并指定一个颜色值:

  <android.support.design.widget.CollapsingToolbarLayout      android:layout_width="match_parent"      android:layout_height="wrap_content"      app:layout_scrollFlags="scroll|exitUntilCollapsed"      app:contentScrim="@color/colorPrimary">

添加字体

图片中间本来是有字体的,那么他是如何实现的呢?

    <android.support.design.widget.CollapsingToolbarLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:layout_scrollFlags="scroll|exitUntilCollapsed"        app:contentScrim="@color/colorPrimary"        app:title="I like Lufu !"        app:expandedTitleMarginStart="200dp"        app:expandedTitleMarginEnd="0dp" >
  1. title指定标题文本
  2. expandedTitleMarginStart指定文本还没上滑时距离左边的间距
  3. expandedTitleMarginEnd指定滑动后距离左边的间距

字体是黑色的是不是很难看,可以指定字体样式 首先在style.xml文件中定义样式:

<style name="TextStyle" parent="TextAppearance.Design.CollapsingToolbar.Expanded">    <item name="android:textColor">@android:color/white</item>    <item name="android:textSize">18sp</item></style>

在CollapsingToolbarLayout控件中指定属性:

app:expandedTitleTextAppearance="@style/TextStyle"

添加FloatingActionButton

从图中可以看出该控件是在两个大的容器中间,也是在CoordinatorLayout的内部。实际上他有一个锚点的概念,就是根据界面存在的某个控件来布局的。代码如下:

<android.support.design.widget.CoordinatorLayout  >    <!-- 创建顶部图片控件 AppBarLayout其父类是LinearLayout -->    <android.support.design.widget.AppBarLayout        ...        android:id="@+id/appbar">    </android.support.design.widget.AppBarLayout>    <android.support.design.widget.FloatingActionButton        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:fabSize="mini"        android:src="@mipmap/ic_launcher"        app:backgroundTint="@color/colorPrimary"        app:layout_anchor="@id/appbar"        app:layout_anchorGravity="bottom|center_horizontal" /></android.support.design.widget.CoordinatorLayout>
  1. layout_anchor指定以某一个控件来布局
  2. layout_anchorGravity指定在该控件的某个位置。

自定义布局依赖

接下来我们要重新回去理解scrollView的layout_behavior属性。该属性接收一个字符串,帮我们滑动scrollView的时候,顶部的appbarlayout也跟着移动。接下来我们学习下如何自定义一个layout_behavior。

这里写图片描述

实际上,这里我们要做的就是让图片移动,只要图片一移动 文本也跟着一起移动。这个操作如何实现呢,首先看下布局,这里我们还是使用CoordinatorLayout布局(翻译过来叫协调者布局 通过他来协调内部的操作)。

<?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"    android:layout_width="match_parent"    android:layout_height="match_parent">    <ImageView        android:id="@+id/iv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@mipmap/ic_launcher" />    <TextView        android:id="@+id/tv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:layout_behavior="com.example.demo.MyBehavior"        android:text="aaaaaaaaaa" /></android.support.design.widget.CoordinatorLayout>

注意到了上面的图片控件,随着手指的移动而移动,我们的代码很简单,这里不做过多解释,至于TextView的layout_behavior属性如何配置,后面会讲到:

public class BehaviorActivity extends AppCompatActivity implements View.OnTouchListener {    private ImageView iv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_behavior);        iv = (ImageView) findViewById(R.id.iv);        iv.setOnTouchListener(this);    }    @Override    public boolean onTouch(View v, MotionEvent event) {        if (event.getAction()==MotionEvent.ACTION_MOVE){            iv.setX(event.getRawX());            iv.setY(event.getRawY());        }        return true;    }}

现在的重点来了,怎么让文本控件跟图片控件一起移动呢,经过分析:

文本控件:时刻观察图片控件的行为(观察者)
图片控件:被文本控件监听的对象(被观察者)

接下来我们需要创建一个类,用来绑定这2个对象。

/** * Behavior<TextView> 内部的泛型就是观察者的类型 */public class MyBehavior extends CoordinatorLayout.Behavior<TextView> {    /**     * 默认需要实现如下两个构造器     * */    public MyBehavior() {    }    public MyBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    /**     * 告诉系统我们要监听的对象是ImageView的图片控件     * 实际上一个容器可能有多个图片控件 我更愿意使用tag属性来区别某个具体的控件     * @param dependency 被观察者对象     * @param child 观察者对象             * */    @Override    public boolean layoutDependsOn(CoordinatorLayout parent, TextView child, View dependency) {        return dependency instanceof ImageView;    }    /**     * 拿到被观察者对象的x y坐标,并计算出观察者的x y坐标     *      * @param dependency 被观察者对象     * @param child 观察者对象             * */    @Override    public boolean onDependentViewChanged(CoordinatorLayout parent, TextView child, View dependency) {        float x = dependency.getX();        float y = dependency.getY();        child.setX(x);        child.setY(y+10+dependency.getHeight());        return true;    }}

写完该类后,需要将该类配置到布局文件中,实际上也就是将类的全路径的字符串添加到观察者的标签中,这里指的就是TextView.

<TextView    android:id="@+id/tv"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    app:layout_behavior="com.example.demo.MyBehavior"    android:text="aaaaaaaaaa" />

说到这里已经把该Demo写完了。接下来再来看看第一个Demo中为何添加一个字符串就能让头部的AppBarLayout跟着一起移动的。

app:layout_behavior="@string/appbar_scrolling_view_behavior"<string name="appbar_scrolling_view_behavior" translatable="false">android.support.design.widget.AppBarLayout$ScrollingViewBehavior</string>

实际上该字符串指定的就是ScrollingViewBehavior类。让我们看看该类2个重要的方法吧,从下面可以看出,被观察者实际上就是AppBarLayout,也就是系统内部会根据AppBarLayout做出对应的调整。

@Overridepublic boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {    // We depend on any AppBarLayouts    return dependency instanceof AppBarLayout;}@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, View child,        View dependency) {    offsetChildAsNeeded(parent, child, dependency);    return false;}
1 0
原创粉丝点击