上一篇学习了 view 是怎样被组织显示的,这一次主要是学习怎样设计自己的 ContentView,首先我们要知道的知识有:android 的坐标系、常用的布局、LayoutParams 参数。
1.认识 android 的坐标系
就我所知,android 中主要有屏幕坐标系和 view 的坐标系两个概念,看下图:
上图左边的是屏幕坐标系,上一篇我们提及到的 DecorView(包括一个状态栏、内容区和导航栏)占据了整个屏幕,所以 DecorView 的坐标系,就等价于屏幕坐标系了,除了 DecorView 这个特殊的 View,其他 View 都是相对于父布局的,如上图左边,View 的坐标系是相对于其父布局的,要确定 View 的大小和位置,其实只要确定 View 的左上角和右下角的坐标即可,因为其实所有 View 都是矩形。 根据 DecorView 的构成,我们易知 ContentView,也就是 activity 对应的“根布局”的父布局就是 ContentFrameLayout,所以 ContentView 的坐标系的 Y 相对于屏幕坐标系的 Y 是要下移一个状态栏和标题栏的高度的。
在 View 中分别有四个属性:left、top、right、bottom , 分别代表左上角、右下角的横坐标、纵坐标,可以通过 left = view.getLfet() 获得,以此类推。值得注意的是,在 view 中也有四个这样的属性:x、y、translationX、transltionY。其中 x , y 代表 view 的左上角的位置(这个才是显示的位置),他们的关系如下:
x = left + translationX;
y = right + translationY;
在默认情况下 translationX 和 translationY 均是 0,即 x = left ,y = right ,因为此时 View 没有被移动,如果移动了 view , translationX 或 translationY 就不是 0 ,view 移动和 x , y 坐标变化是相对应的,x , y 才是真正确定 view 的显示位置的,这里会在 view 的滑动中进一步学习。
2.认识 LayoutParams
有了上面的坐标系,一个 view 要显示出来,如果不考虑如何绘制,最起码也要知道 view 的大小和位置,我们能不能动态的改变 view 的大小和位置呢,答案是肯定的,LayoutParams 就保存了 view 的各种参数信息,通过修改 LayoutParams 中的参数可以实现 View 的滑动。
LayoutParams 是布局参数,是 ViewGroup 的内部类,是 view 用来告知它的父布局自己需要怎样的摆放,MarginLayoutParams 是 LayoutParams 的直接子类,我们一般都是使用 MarginLayoutParams 的,获得:
MarginLayoutParams params=(MarginLayoutParams)view.getLayoutParams();
然后通过修改 MarginLayoutParams 中的参数信息,就可以得到更新 view 的属性参数信息了。
3. 常用布局
android 中的常用布局有:线性布局 LinearLayout、相对布局RelativeLayout、帧布局 FrameLayout、百分比布局 PercentRealativeLayout、PercentFrameLayout,对于这些常用布局的使用,比较简单,也没什么好说的,就记录一些自己觉得重要的属性。
属性 | 说明 | 可用布局 |
---|---|---|
layout_gravity | 控制在布局中的对齐方式 | LinearLayout、FrameLayout |
gravity | 控制 view 内部内容的对齐方式 | |
layout_weight | 把剩余布局空间按比例分配 | LinearLayout |
值得注意的是:在 LinearLayout 使用 layout_gravity 属性时,只作用于一个方向,如设定 orientation = “vertical”,则作用于 “horizontal” 方向,相反则反。
通过使用 layout_weight 属性可以做到以百分比来指定控件的大小,但是 layout_weight 只用于 LinearLayout ,为此 android 引入了一种全新的布局方式来解决RelativeLayout、FrameLayout 不能使用百分比确定控件大小的问题,引入的布局是百分比布局(分别继承相对布局和帧布局)。在 gradle 中添加 compile ‘com.android.support:percent:24.2.1’ 后同步一下,即可使用 PercentRealativeLayout、PercentFrameLayout。其中两个重要属性就是:app:layout_widthPercent 和 app:layout_heightPercent,控制控件占据父布局宽高的百分比。
4. material 布局与控件
1) 圆角化 CircleImageView
在 build.gradle 文件的 dependencies 闭包中添加库路径,并 Sync now 同步一下:
compile 'de.hdodenhof:circleimageview:2.1.0'
compile 'com.android.support:design:24.2.1'
同步后,就可以在 xml 文件中使用控件 CircleImageView , 使用方法和 imageView 一样。
<de.hdodenhof.circleimageview.CircleImageView
android:layout_centerInParent="true"
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
android:src="@drawable/dog"/>
效果:
2)FloatingActionButton
FloatingActionButton 是悬浮按钮,使用和 Button 一样,需要注意的是有几个重要属性:
属性 | 说明 |
---|---|
elevation | 按钮的立体高度值,单位为 dp,值越大,投影效果越深 |
layout_anchor | 锚点,值为 id ,选择悬浮在哪个布局中 |
layout_anchorGravity | 悬浮在布局中的哪个方位 |
(layout_anchor 和 layout_anchorGravity 属性在 CoordinatorLayout 中才适用)
<android.support.design.widget.FloatingActionButton
android:id="@+id/floating_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:elevation="80dp"
app:layout_anchor ="@id/linear_layout"
app:layout_anchorGravity="center"
android:src="@drawable/share"/>
效果:其中那个框框就是一个 LinearLayout ,根据效果图就容易理解锚点属性了。
4)CoordinatorLayout 是一个加强版的 FrameLayout ,可以监听所有子控件的事件,自动帮助我们做出最为合理的响应,经常会结合 ToolBar 使用,看下面的例子:
/*
* 在一个 FrameLayout 中放置一个 FloatingActionButton 并为其设置
* 点击响应监听,在监听中使用 SnackBar 做出点击提示
*/
<FrameLayout
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">
<android.support.design.widget.FloatingActionButton
android:id="@+id/floating_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:elevation="80dp"
android:layout_margin="15dp"
android:layout_gravity="bottom|end"
android:src="@drawable/share"/>
</FrameLayout>
效果:
/*
* 在一个 CoordinatorLayout 中放置一个 FloatingActionButton 并为其
* 设置点击响应监听,在监听中使用 SnackBar 做出点击提示
*/
<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">
<android.support.design.widget.FloatingActionButton
android:id="@+id/floating_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:elevation="80dp"
android:layout_margin="15dp"
android:layout_gravity="bottom|end"
android:src="@drawable/share"/>
</android.support.design.widget.CoordinatorLayout>
效果:
通过比较效果可以看出 CoordinatorLayout 对其子控件做了优化响应
5)CardView 是一个 FrameLayout , 提供了圆角和阴影效果,对应两个属性分别是: elevation 和 cardCornerRadius
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_margin="20dp"
app:elevation="10dp"
app:cardCornerRadius="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="hello word"/>
</android.support.v7.widget.CardView>
效果:
5)TextInputLayout
先看看介绍:
TextInputLayout 是一个 LinearLayout 布局,可以包裹一个 EditText及其子类(如 TextInputEditText ) ,主要功能有如下:
a.在用户输入文本覆盖默认文本时,会把默认文本标签移动到上方。
b.支持通过 setErrorEnabled(boolean) 和setError(CharSequence) 显示错误,并通过setCounterEnabled(boolean) 显示一个字符计数器。
c.通过 setPasswordVisibilityToggleEnabled(boolean) 和相关属性的设定,可以支持密码可见性切换。
我们可以通过在 xml 设定属性或者对应的方法设定属性就可以达到 a,b,c 的效果,结合sector 标签的 drawable 资源使用,效果更佳,下面记录一些常用的属性。
属性 | 对应方法 | 说明 |
---|---|---|
counterEnabled | setCounterEnabled(boolean) | 是否开启字符计数器 |
counterMaxLength | setMaxLength(int) | 计数器计算的最大字符数 |
errorEnable | setErrorEnabled(boolean) | 是否开启错误提示 |
errorTextAppearance | setError(cahrSequeue) | 错误提示内容 |
hintTextAppearance | setHintTextAppearance(int) | 设置提示语的风格 |
passwordToggleEnabled | setPasswordVisibilityToggleEnabled(boolean) | 是否开启密码可见开关,注意设置 editText 的 inputType 属性 |
passwordToggleDrawable | setPasswordVisibilityToggleDrawable(Drawable) | 设置密码可见开关的图标,可以引用一个 sector drawable 资源 |
passwordToggleTint | setPasswordVisibilityToggleTintList(ColorStateList) | 控制密码可见开关图标的颜色,可以引用一个 sector color 资源 |
// password 部分的 xml
<android.support.design.widget.TextInputLayout
android:id="@+id/psw_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleTint="@color/btn_sector">
<android.support.design.widget.TextInputEditText
android:id="@+id/password"
android:maxLines="1"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="password"/>
</android.support.design.widget.TextInputLayout>
效果:
6) TabLayout
TabLayout 是一个 HorizontalScrollview ,用作导航指示器,我们可以通过 tabLayout.newTab() 方法创建一个 Tab 对象然后添加到 TabLayout 中,可以通过 setText 和 setIcon 方法设置导航标题。一般结合 ViewPager 使用,这样会自动使 ViewPager 与 Tab 联动。
简单代码如下:
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
app:tabIndicatorColor="@android:color/white"
app:tabTextColor="@color/colorGray"
app:tabSelectedTextColor="@android:color/white" />
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
public class MainActivity extends AppCompatActivity {
private List<Fragment> fragmentList = new ArrayList<Fragment>();
private List<String> titleList = new ArrayList<String>();
private TabLayout mTabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initAllView();
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
viewPager.setAdapter(new MyViewPagerAdapter(getSupportFragmentManager()));
// 给 TabLayout 布局加载 viewPager
mTabLayout.setupWithViewPager(viewPager);
}
// 初始化一些 view
private void initAllView(){
fragmentList.add(new MyFragment());
fragmentList.add(new MyFragment());
fragmentList.add(new MyFragment());
fragmentList.add(new MyFragment());
titleList.add("tab1");
titleList.add("tab2");
titleList.add("tab3");
titleList.add("tab4");
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.addTab(mTabLayout.newTab());
}
class MyViewPagerAdapter extends FragmentPagerAdapter{
public MyViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
MyFragment fragment = (MyFragment) fragmentList.get(position);
return fragment;
}
@Override
public int getCount() {
return fragmentList.size();
}
/*
* 注意一定要重写 getPageTitle 方法,以为在这里 TabLayout 是
* 结合 ViewPager 使用,tab 的 text 是取 PageTitle 为准的
*/
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
}
}
效果(菜鸟还不会截动图):
需要记录的属性:
如果我们需要响应 tab 的选择事件,可以为 tabLayout 设置 TabLayout.TabLayoutOnPageChangeListener,方法如下:
/*
* This method was deprecated in API level 24.0.0. Use
* addOnTabSelectedListener(OnTabSelectedListener) and
* removeOnTabSelectedListener(OnTabSelectedListener).
*/
setOnTabSelectedListener(TabLayout.OnTabSelectedListener listener)
7)DrawerLayout 和 NavigationView
DrawerLayout 是一个滑动菜单布局,在布局中可以包含两个子控件,第一个子控件是屏幕主内容区,第二个控件是侧滑的导航菜单,侧滑的导航菜单一般结合 NavigationView 使用,当然也可以不使用 NavigationView。简单用法如下:
<android.support.v4.widget.DrawerLayout
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"
android:id="@+id/drawer_layout">
<RelativeLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="主屏幕区内容"
android:textSize="30sp"/>
</RelativeLayout>
<android.support.percent.PercentFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start">
<android.support.design.widget.NavigationView
app:layout_widthPercent="90%"
app:layout_heightPercent="100%"
android:id="@+id/navigation_view"
app:menu="@menu/navi_menu"
app:headerLayout="@layout/header_layout" />
</android.support.percent.PercentFrameLayout>
</android.support.v4.widget.DrawerLayout>
上面的 xml 片段,DrawerLayout 中包含了一个 RelativeLayout 显示主屏幕内容,一个 PercentFrameLayout 显示侧滑菜单,在 PercentFrameLayout 中包裹了一个 NavigationView ,这里使用百分比布局主要是为了能够控制菜单占据屏幕的百分比。
需要注意的地方: 侧滑菜单一定要设定 android:layout_gravity 属性,表示从左侧还是有侧滑出,一般使用 start 或 end ,分别表示左侧滑出 或右侧滑出,这里的左右是取决于系统设置的语言是从左到右还是从右到左的。
NavigationView 的使用:其中有两个属性 app:menu 和 app:headerLayout 分别指定一个头布局和菜单栏,所以我们要事先准备好一个头布局和一个菜单的 xml 文件,然后通过这两个属性指定即可。
nav_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/message"
android:title="我的消息"
android:icon="@mipmap/message1"/>
<item
android:id="@+id/phone"
android:title="我的电话"
android:icon="@mipmap/phone"/>
<item
android:id="@+id/friends"
android:title="我的朋友"
android:icon="@mipmap/friends"/>
<item
android:id="@+id/sub_item"
android:title="subItem">
<menu>
<item
android:id="@+id/settings"
android:title="设置"
android:icon="@mipmap/settings"/>
<item
android:id="@+id/moon_style"
android:title="夜间模式"
android:icon="@mipmap/night"/>
<item
android:id="@+id/exit"
android:title="退出"
android:icon="@mipmap/turn_off"/>
</menu>
</item>
</group>
</menu>
header_layout.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@drawable/bg">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/circle_image_view"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerInParent="true"
android:src="@drawable/dog"/>
<TextView
android:layout_marginTop="20dp"
android:id="@+id/name_text_view"
android:layout_below="@id/circle_image_view"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小小莫是我"
android:textColor="@android:color/white"
android:textSize="25sp"/>
<TextView
android:layout_toRightOf="@id/name_text_view"
android:layout_alignTop="@id/name_text_view"
android:layout_marginLeft="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="@android:color/white"
android:text="lv.5" android:background="@drawable/bg_rectangle_with_stroke_dash"
/>
</RelativeLayout>
那么如何给菜单项添加事件响应:
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// 通过菜单项 id 识别菜单项
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
当你点击菜单以外的地方,会自动滑动隐藏菜单,我们也可以通过代码来打开和关闭菜单:
// 注意这里穿进去的参数要和 xml 中的 layout_gravity 值一致
drawerLayout.closeDrawer(GravityCompat.START);
drawerLayout.openDrawer(GravityCompat.START);
效果(菜鸟还不会截动图):
8) CoordinatorLayout 、ToolBar 、AppBarLayout
工具栏 ToolBar 是用来代替 ActionBar 的,它具有 ActionBar 功能,此外也有 MaterialDesign 效果,简单用法如下:
<FrameLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:background="#DC143C"
android:layout_height="?attr/actionBarSize"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
上面 xml 片段,在 FrameLayout 中放置一个 Toolbar 和 RecyclerView , 由于是 FrameLayout ,所以 RecyclerView 会覆盖 Toolbar。
为了解决这个 bug ,常规做法是让 RecyclerView 下移一个工具栏的高度,我们也可以对 Toolbar 嵌套一个 AppBarLayout ,如下:
<FrameLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DC143C"
android:paddingTop="25dp">
<android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:background="#DC143C"
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
上面的是 xml 中的定义,在代码区我们也要做相应的工作,在使用工具栏时,我们首先需要隐藏原来的 AcitonBar,可以在 xml 中修改 Style:
// 这里是直接继承 Theme.AppCompat.Light.NoActionBar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
然后在 onCreate 方法中:
// 告知使用 Toolbar 代替 ActionBar
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
// 这里可以设定 toolBar 左侧导航图标按钮,我们在onOptionsItemSelected
// 方法中响应点击左侧导航图标,其按钮 id 为 android.R.id.home
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// 图标默认为左侧箭头,这里可以设定自己的图标
actionBar.setHomeAsUpIndicator(R.mipmap.home);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home :
mDrawerLayout.openDrawer(GravityCompat.START);
break;
}
return true;
}
我们提及到过 CoordinatorLayout ,它是一个加强版的 FrameLayout,可以监听所有子控件的事件,自动帮助我们做出最为合理的响应,既然这样我们看看把 CoordinatorLayout 代换成 FrameLayout 试试看:
<android.support.design.widget.CoordinatorLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:background="#DC143C"
android:paddingTop="25dp"
android:layout_height="wrap_content"
app:layout_scrollFlags="enterAlways|snap|scroll" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
看上面的 xml 片段,在 ToolBar 中添加 app:layout_scrollFlags 属性 ,在 RecyclerView 中添加 app:layout_behavior=”@string/appbar_scrolling_view_behavior。
看效果(截下的是mp4,在线转为gif就这样了,比较模糊,意思意思就好了):
我们可以看到,toolbar 与 RecyclerView 的滚动同步了,当向上滚动时候,toolbar会一同向上滚动,至隐藏,当向下滚动时,toolbar 又显示了。ToolBar 中app:layout_scrollFlags 属性 和 RecyclerView 中app:layout_behavior 属性能够使他们联动。
app:layout_scrollFlags 值 | 说明 |
---|---|
scrool | 向上滚动时一同滚动 |
snap | toolBar 没有完全显示或隐藏时,根据滑动距离做出选择 |
enterAlways | 一发现向下滚动则显示toolBar |
exitUntilCollapsed | 滚动折叠完成后保留显示在界面,在CollapsingToolBarLayout 中即将使用 |
9)CollapsingToolBarLayout
上面我们看到的 toolbar 的 Material 效果就是可以与其他控件联动,那可不可以设计一个更高级的 toolbar , 是可以的。CollapsingToolBarLayout 是一个 FrameLayout , 它可以代表一个高级的标题栏,但是它必须是 AppBarLayout 的直接子布局,而 AppBarLayout 又必须是 CoordinatorLayout 的子布局。一般会用 CollapsingToolBarLayout 来包裹一个 Toolbar ,但不是必须的。看下面的 xml 片段:
<android.support.design.widget.CoordinatorLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapse_tool_bar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="#DC143C"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="小小莫是我">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/bg"
app:layout_collapseMode="parallax"
/>
<android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:paddingTop="25dp"
android:layout_height="85dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:popupTheme="@style/Theme.AppCompat.Light"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
效果:
我们可以看到 CollapsingToolbarLayout 就是我们定制的标题栏,因为标题栏,不再是 ToolBar 了,所以相应的我们要把 app:layout_scrollFlags 属性上移一层至 CollapsingToolbarLayout,使其与 RecyclerView 联动。在 CollapsingToolbarLayout 中,可以看到有一个 imageView 和 toolBar ,其中有一个 app:layout_collapseMode 属性,它的作用是指定当前控件在 CollapsingToolbarLayout 折叠中的折叠模式,parallax 指在折叠中产生错位偏移, pin 指 位置始终保持不变。还有 app:contentScrim 属性,它是指定在完成折叠后标题栏的背景色。注意,CollapsingToolbarLayout 是一个 FrameLayout , 我们可以在其中添加更多的控件,ToolBar 其实也是一个ViewGroup , 我们也可以在其中添加控件。
CollapsingToolbarLayout 中的 title , 我们可以看到布局中的标题可以在折叠过程中移动至 toolBar 的位置(我觉得,在折叠完成后,系统自动会帮我们把 CollapsingToolbarLayout 中的 title 设为 toolBar 的 title , 如果我在设定 toolBar 的高度为 wrap_content 时,无论这样设定 CollapsingToolbarLayout 中的 title,都没有显示,应该是因为 toolBar 高度为 wrap_content,在没有位置显示 title ,所以 CollapsingToolbarLayout 中也不显示 title。这只是主观的猜测,有人知道就说说呗,告诉我这个新手)
我们可以通过多种属性设置 CollapsingToolbarLayout 中的 title 的在不同状态的内容和样式。一般来说,一个 xml 属性有对应的一个设置该属性的方法,我们可以在 xml 中设置属性,也可在代码中调用相应的方法。其实,一般一个类对象其中的字段就是对应的 xml 属性,我们在使用过程中,可以去查找其属性的用法就好了,因为这些属性太多了,实在是无法记忆的。如下:我们可以官网看起相关的类属性和类方法。
小结:系统提供的一些布局和控件用多了,发现不外乎是要掌握其属性的设置,不同的属性有不同的效果与功能,可以通过 xml 设置,也可以通过函数方法设置,在使用一个新布局或新控件时,我们可以通过看其文档介绍来查找一些需要的属性使用方法,同时我们也要脱离现象,想想完成一个动作效果,需要怎样的算法流程,例如在使用 TabLayout 时,我们可以想到这样一个情景,在导航栏切换 tab , 应该做出怎样的响应,在与之关联的布局切换内容区,应该做出怎样的响应,很容易想到的是,需要互相监听,我们想到的做法就是去看看布局对应的类中有没有什么 Listener 中可用等。好啦,我的意思是无论这样,一个动作效果对应的算法流程是基本不变的,无论你用什么编程语言去实现这个效果。