目录
3.CoordinatorLayout:加强版FrameLayout
一、什么是Material Design
一套全新的界面设计语言
二、Toolbar
修改D:\soft\projects\MaterialTest\app\src\main\res\values\themes.xml
//界面的主体颜色设成深色,陪衬颜色设成淡色
<style name="Theme.MaterialTest" parent="Theme.MaterialComponents.NoActionBar">
//界面的主体颜色设成淡色,陪衬颜色设成深色
<style name="Theme.MaterialTest" parent="Theme.MaterialComponents.Light.NoActionBar">
如何使用Toolbar?
首先修改themes.xml文件:
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MaterialTest" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
其次在activity_main.xml添加:
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/purple_500"
tools:ignore="MissingConstraints" />
最后修改MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
}
效果如下图:
添加android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"让Toolbar单独使用深色主题,这样文字就会变成浅色,如下图
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/purple_500"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
tools:ignore="MissingConstraints" />
在Toolbar中添加一些按钮
<?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/backup"
android:title="Backup"
android:icon="@drawable/ic_backup"
app:showAsAction="always"
/>
<item
android:id="@+id/delete"
android:title="Delete"
android:icon="@drawable/ic_delete"
app:showAsAction="ifRoom"
/>
<item
android:id="@+id/settings"
android:title="Settings"
android:icon="@drawable/ic_settings"
app:showAsAction="never"
/>
</menu>
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.backup:
Toast.makeText(this, "你点击了返回", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "你点击了删除", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "你点击了设置", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
}
如果不指定android:icon="@drawable/ic_backup",会用title作为按钮,如下图:
加了icon属性如下图:
当你点最右边三个点时如下图:
只需要在布局文件中的Toolbar添加如下代码就可以,如下图:
app:popupTheme="@style/Theme.AppCompat.Light"
三、滑动菜单
1.DrawerLayout
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</FrameLayout>
<!--指定start表示会根据系统语言进行判断,系统语言是从左往右的,滑动菜单在左边,系统语言从右往左的,滑动菜单在右边-->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="这是菜单"
android:textSize="30sp"
android:background="#FFF"
/>
</androidx.drawerlayout.widget.DrawerLayout>
Toorbar的最左边加入一个导航按钮
public class MainActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawerLayout = findViewById(R.id.drawer_layout);
ActionBar actionBar = getSupportActionBar();
if(actionBar!=null){
//让导航按钮显示出来
actionBar.setDisplayHomeAsUpEnabled(true);
//设置导航按钮图标
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
//HomeAsUp按钮的id永远都是android.R.id.home
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.backup:
Toast.makeText(this, "你点击了返回", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "你点击了删除", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "你点击了设置", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
}
2.NavigationView
添加依赖:
//开源项目CircleImageView,可以用来轻松实现图片圆形化的功能
implementation 'de.hdodenhof:circleimageview:3.1.0'
NavigationView不用添加依赖,直接
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"
/>
四、悬浮按钮和可交互提示
1.FloatingActionButton:悬浮按钮
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_done"
//指定高度值,高度值越大,投影范围也越大,投影效果越淡;高度值越小,投影范围越小,投影效果越浓
app:elevation="8dp"
/>
2.Snackbar:提示工具
Snackbar允许在提示中加入一个可交互按钮
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//第一个参数需要传入一个View,当前界面布局的任意一个View都可以;第二个参数是内容;第三个参数是显示的时长
Snackbar.make(v,"数据删除",Snackbar.LENGTH_SHORT).setAction("不做", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "数据保存", Toast.LENGTH_SHORT).show();
}
}).show();
}
});
3.CoordinatorLayout:加强版FrameLayout
CoordinatorLayout可以监听其所有子控件的各种事件,然后自动帮助我们做出最为合理的响应。
比如可以实现提示条不会挡住悬浮按钮
<androidx.coordinatorlayout.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=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorOnSecondary"
android:theme="@style/ThemeToolbar"
app:titleTextColor="@color/white"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_done"
app:elevation="8dp"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
五、卡片式布局
1.MaterialCardView
也是一个FrameView,只是额外提供了圆角和阴影等效果
添加Glide库依赖:Glide是一个超级强大的图片加载库
implementation 'com.github.bumptech.glide:glide:4.12.0'
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
app:elevation="5dp">
<TextView
android:id="@+id/infoText"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.card.MaterialCardView>
2.AppBarLayout
实际上是一个垂直方向的LinearLayout,在内部做了很多滚动事件的封装
怎么解决Toolbar被覆盖的问题?
第一步将Toolbar嵌套到AppBarLayout中,第二部给RecycleView指定一个布局行为
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorOnSecondary"
android:theme="@style/ThemeToolbar"
app:titleTextColor="@color/white"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
//指定一个布局行为
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorOnSecondary"
android:theme="@style/ThemeToolbar"
app:titleTextColor="@color/white"
//scroll表示当RecycleView向上滚动时,Toolbar会跟着一起向上滚动并隐藏;enterAlways反之;snap表示当Toolbar还没有完全隐藏或显示的时候,会根据当前的滚动距离,自动选择是隐藏还是显示
app:layout_scrollFlags="scroll|enterAlways|snap"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
六、下拉刷新
SwipeRefreshLayout是用于实现下拉刷新功能的核心类
导入SwipeRefreshLayout依赖:
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
在RecycleView的外面嵌套一层SwipeRefreshLayout,这样RecycleView就自动拥有下拉刷新的功能了:
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
修改MainActivity:
protected void onCreate(Bundle savedInstanceState) {
......
swipeRefreshLayout = findViewById(R.id.swipe_refresh);
// swipeRefreshLayout.setColorSchemeResources(R.color.design_default_color_primary);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshFruits();
}
});
}
private void refreshFruits(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initFruits();
//通知数据发生了变化
adapter.notifyDataSetChanged();
//表示刷新事件结束,并隐藏刷新进度条
swipeRefreshLayout.setRefreshing(false);
}
});
}
}).start();
}
七、可折叠式标题栏
1.CollapsingToorbarLayout
一个作用于Toolbar基础之上的布局,可以让Toolbar的效果变得更加丰富,展示标题栏的同时实现非常华丽的效果。CollapsingToolbarLayout只能作为AppBarLayout的直接子布局来使用,而AppBarLayout又必须是CoordinatorLayout的子布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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=".FruitActivity"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toorbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
//指定CollapsingToolbarLayout趋于折叠状态以及折叠之后的背景色
app:contentScrim="@color/black"
scroll表示CollapsingToolbarLayout会对着水果内容详情的滚动一起滚动,exitUntilCollapsed表示当CollapsingToolbarLayout随着滚动完成折叠之后就保留在界面上,不再移出屏幕
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
>
<ImageView
android:id="@+id/fruit_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
//折叠模式parallax:在折叠过程中产生一定的错位偏移
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true"
/>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
//折叠模式pin:在折叠的过程中位置始终保持不变
app:layout_collapseMode="pin"
/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
//允许使用滚动的方式来查看屏幕以外的数据,并增加了嵌套响应滚动事件的功能 内部只允许存在一个直接子布局,如果想要在里面放入很多东西,通常会先嵌套一个LinearLayout
<androidx.core.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"
>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="15dp"
app:cardCornerRadius="4dp"
>
<TextView
android:id="@+id/fruit_content_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
/>
</androidx.cardview.widget.CardView>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_comment"
//指定了一个锚点,锚点设置为AppBarLayout,这样悬浮按钮就会出现在水果标题栏的区域内
app:layout_anchor="@id/appBar"
//将悬浮按钮定位在标题栏区域的右下角
app:layout_anchorGravity="bottom|end"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
2.充分利用系统状态栏空间
第一步:将ImageView和ImageView布局的所有父布局都设置上下面的属性
android:fitsSystemWindows="true"
第二步:打开res/values/styles.xml文件,对主题的内容进行修改
<resources>
<!-- Base application theme. -->
<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>
<style name="FruitActivityTheme" parent="AppTheme">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
最后,还需要让FruitActivity使用这个主题才可以
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.materialtest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
<activity
android:name=".FruitActivity"
android:theme="@style/FruitActivityTheme">
</activity>
</application>
</manifest>