Android :安卓第一行代码学习笔记之 material design简单理解和使用

material design简单理解和使用

Material Design 是谷歌的一套全新的界面设计语言,包含了视觉,运动,互动效果等特性。
Design Support库,将Material Design中最具代表性的一些控件和效果进行了封装。

1、 Toolbar

ToolBar是我们接触的第一个 Material Design 控件,对于它的另一个相关控件ActionBar。

ActionBar的设计被限定只能位于活动的顶部,从而不能实现 Material Design 的效果。因此官方更加推荐使用ToolBar。

创建的基本步骤:

  • step1.更改程序的ActionBar主题

  • step2.在布局中添加Toolbar控件

  • 3.活动中设置支持动作栏

1、把之前默认的深色主题改为不带ActionBar的主题

任何一个新建项目,默认都会显示ActionBar。它是根据项目中指定的主题来显示的,打开AndroidManifest.xml文件,如下:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
    </application>

使用android:theme属性指定了一个AppTheme的主题。打开res/values/styles.xml文件,如下:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

这里定义了一个叫AppTheme的主题,然后指定了它的parent主题是Theme.AppCompat.Light.DarkActionBar。这个DarkActionBar是一个深色的主题,项目中自带的ActionBar就是因为指定了这个主题才出现的。

接下来我们使用ToolBar来代替ActionBar,通常Theme.AppCompat.NoActionBar(表示深色主题,将界面的主题颜色设成深色,陪衬颜色设成淡色)和Theme.AppCompat.Light.NoActionBar(表示淡色主题,将界面的主题颜色设成淡色,陪衬颜色设成深色)两种主题可选。那我们就选用淡色主题,如下所示:

<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>

</resources>

在这里插入图片描述
step2.在布局中添加Toolbar控件

现在我们已经将ActionBar隐藏起来了,使用ToolBar来代替ActionBar。修改activity_main.xml中的代码如下:

<androidx.appcompat.widget.Toolbar
	  android:layout_width="match_parent"
	  android:layout_height="?attr/actionBarSize"
	  android:id="@+id/toolbar"
	  android:background="?attr/colorPrimary"
	  android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
	  app:popupTheme="@style/ThemeOverlay.AppCompat.Light"   />
     <!-- android:theme 设置Toolbar的主题风格-->
     <!-- app:popupTheme 单独指定弹出的菜单项的主题-->           

使用了 xmlns:app 指定了一个新的命名空间。是由于 Material Design 是在 Android5.0 系统中才出现的,为了兼容之前老的系统,我们就必须使用app:attribute

定义了一个Toolbar控件。为了让ToolBar单独使用深色主题,这里我们使用 android:theme 属性,将Toolbar的主题指定成了ThemeOverlay.AppCompat.Dark.ActionBar。为了使Toolbar中的菜单按钮弹出的菜单项也变成淡色的主题,这里使用了 app:popupTheme ,是因为popupTheme这个属性是 Android5.0 新增的,这样我们就可以兼容 Android5.0 以下的系统了。

3.活动中设置支持动作栏

接下来我们修改MainActivity中的代码如下:

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar); //将Toolbar的实例传入
    }
}

这样我们就让它的外观和功能都和ActionBar一致了。运行程序如下:
在这里插入图片描述

1.1、修改标题栏上显示的文字内容

Toolbar常用的一些功能,比如修改标题栏上显示的文字内容。在AndroidManifest.xml中指定,如下:

// 在activity标签中修改,如果没有指定,默认用application中指定的label内容。
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="Fruits">
            ...
        </activity>
    </application>

这里在activity新增了一个label属性,用于指定Toolbar显示的文字内容,如果没有指定就会默认使用application中指定的label内容,也就是我们的应用的名称。

1.2、添加action按钮

和添加普通菜单流程基本一样。

step1.创建菜单项的xml文件

为了丰富我们Toolbar,可以再添加 action 按钮。准备一些图片来作为按钮的图标。将它们放在 drawable-xxhdpi 目录下。创建一个 menu文件夹。再创建一个toolbar.xml 文件,并编写代码如下:

 <?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/item1"
        android:title="Backup"
        android:icon="@mipmap/ic_launcher"
        app:showAsAction="always"/>
    <item
        android:id="@+id/item2"
        android:title="Delete"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/item3"
        android:title="Setting"
        app:showAsAction="never"/>

</menu>

通过< item>标签定义 action 按钮,android:id 用于指定按钮的 id,android:icon 用于指定按钮的图标,android:title 指定按钮的文字。app:showAsAction 指定按钮显示的位置,使用app命名空间,为了能够兼容更低的系统。可选值:always(永远显示在Toolbar中,屏幕空间不足则不显示),ifRoom(屏幕空间足够的情况下显示在Toolbar中,不够则显示在菜单当中),never(永远显示在菜单中)。注意:Toolbar中的action按钮只会显示图标,菜单中的 action 只会显示文字。

step2.加载菜单文件、设置点击事件

修改MainActivity中的代码如下:

public class MainActivity extends AppCompatActivity {
     ...

    /**
     * 加载toolbar.xml文件
     *
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.toolbar, menu);
        return true;
    }

    /**
     * 处理各个按钮的点击事件
     *
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.backup:
                Toast.makeText(this, "You clicked Backup", Toast.LENGTH_SHORT).show();
                break;
            case R.id.delete:
                Toast.makeText(this, "You clicked Delete", Toast.LENGTH_SHORT).show();
                break;
            case R.id.settings:
                Toast.makeText(this, "You clicked Settings", Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
        return true;
    }
}

在这里插入图片描述

2、 滑动菜单

在这里插入图片描述

2.1、DrawerLayout

DrawerLayout控件可用来实现滑动菜单的效果。首先它是一个布局,在布局中允许放入两个直接子控件:

  • 第一个子控件用于显示主屏幕中的内容
  • 第二个子控件用于显示滑动菜单中的内容

示例:

修改activity_main.xml中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        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="@color/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />


    </FrameLayout>

    <TextView
        android:id="@+id/text_view"
        android:text="This is menu"
        android:background="#fff"
        android:textSize="30sp"
        android:layout_gravity="start"//侧拉栏的布局必须声明这一属性,left表示侧拉栏在左,right表示侧拉栏在右,start则会根据系统语言来自动选择
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.drawerlayout.widget.DrawerLayout>

我们可以看到第一个子控件FrameLayout(用于作为主屏幕显示的内容);第二个子控件TextView(作为滑动菜单中显示的内容),这个子控件中 android:layout_gravity 这个属性必须指定(滑动菜单是在屏幕的左边还是右边,left,right,这里我指定了start,根据系统语言进行判断,比如英语,汉语,滑动就在左边,阿拉伯语滑动就在右边)。

运行程序,左侧向右侧滑动,如图:
在这里插入图片描述
向左滑动,或者点击菜单以外的区域,都可以将滑动菜单关闭。

为了解决用户不知道这个功能,Material Design建议我们在Toolbar 的最左边接入了一个导航按钮,点击也会将滑动菜单展示出来。(这样就相当于给用户提供了良两种打开滑动菜单的方式)。

将准备好的c_menu.png放在drawable-xxhdpi目录下,修改MainActivity中的代码如下:

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    private DrawerLayout mDrawerLayout;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mDrawerLayout= (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true); //显示导航按钮
            actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);//设置导航按钮图标(默认返回箭头,含义返回上一个活动)
        }
    }
    ...
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                mDrawerLayout.openDrawer(GravityCompat.START);//对HomeAsUp按钮(id永远是 android.R.id.home),显示滑动菜单,传入GravityCompat.START
                break;
                ...
        }
        return true;
    }
}

运行程序,如下:
在这里插入图片描述
在Toolbar 最左边就会出现导航按钮,点击按钮,滑动菜单就会显示。

2.2、NavigationView

NavigationView是Design Support库中的一个控件,借助它,可让滑动菜单页面的实现变得简单。

step1、添加依赖

 implementation 'com.google.android.material:material:1.0.0'
implementation 'de.hdodenhof:circleimageview:3.1.0'

第二个是开源项目CircleimageView的依赖,GitHub地址,借助它可轻松实现图片圆形化的功能。

step2、准备menu

我们首先要准备:menu(在NavigationView中显示的菜单项) 和 headerLayout(在NavigationView中显示头部布局的)。

准备几张图片放在了drawable-xxhdpi目录下。右击menu,创建一个nav_menu.xml文件,编写代码如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group
        android:checkableBehavior="single">
        <!-- group表示一个组,android:checkableBehavior="single"表示组中的所有菜单项只能单选 -->
        <item
            android:id="@+id/item_cgl1"
            android:title="grape"
            android:icon="@drawable/grape"/>
        <item
            android:id="@+id/item_cgl2"
            android:title="orange"
            android:icon="@drawable/orange"/>
        <item
            android:id="@+id/item_cgl3"
            android:title="pear"
            android:icon="@drawable/pear"/>
        <item
            android:id="@+id/item_cgl4"
            android:title="watemelon"
            android:icon="@drawable/watemelon"/>
    </group>


</menu>

< menu>嵌套了< group>(一组),将group的checkableBehavior属性设为single(所有菜单项只能单选)。接下来定义了5个菜单项。这样准备好了menu。

step3、写headLayout

headerLayout, 这是一个随意定制的布局,那我们就在里面放置头像,用户名,邮箱吧。

准备一张图片放在drawable-xxhdpi目录下。最好是一张正方形,因为一会将它圆形化。右击layout,创建一个nav_header.xml文件。修改代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="180dp"
    android:background="?attr/colorPrimary"
    android:padding="10dp">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/icon_image"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_centerInParent="true"
        android:src="@drawable/nav_icon" />

    <TextView
        android:id="@+id/tv_mail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Jack@mail.com"
        android:textColor="#FFF"
        android:textSize="14sp" />

    <TextView
        android:id="@+id/tv_username"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/tv_mail"
        android:text="Jack"
        android:textColor="#FFF"
        android:textSize="14sp" />
</RelativeLayout>

step4、使用NavigationView

接下来我们使用 NavigationView 了,修改activity_main中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="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="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    </FrameLayout>

    <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:headerLayout="@layout/nav_header"
        app:menu="@menu/nav_menu" />

</androidx.drawerlayout.widget.DrawerLayout>

这样NavigationView定义好了。

step5、处理菜单项的点击事件

接下来处理菜单的点击事件,修改MainActivity中的代码如下:

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    private DrawerLayout mDrawerLayout;
    private NavigationView navView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        navView= (NavigationView) findViewById(R.id.nav_view);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
        }
        navView.setCheckedItem(R.id.nav_call); //设置默认选中
        navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { //菜单选项监听事件
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                //处理逻辑
                mDrawerLayout.closeDrawers();
                return true;
            }
        });
    }
    ...
 }

运行程序,点击Toolbar左侧导航按钮,如下:
在这里插入图片描述

3、 悬浮按钮和可交互提示

立体效果的代表性的设计:悬浮按钮。

一种可交互式提示工具(可对用户做出响应)。

3.1、悬浮按钮(FloatingActionButton)

FloatingActionButton是实现悬浮按钮的效果。还可以给这个按钮指定图标,表示来做什么。

1、在布局中添加

我们准备好一个ic_done.png,修改activity_main.xml中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="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="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        <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" />
    </FrameLayout>
    ...
</androidx.drawerlayout.widget.DrawerLayout >

end和之前的start原理是一样的。app:elevation属性给FloatingActionButton按钮设置阴影(指定高度值)。其实默认的FloatingActionButton效果足够了。

2、处理FloatingActionButton点击事件

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    private DrawerLayout mDrawerLayout;
    private NavigationView navView;
    private FloatingActionButton fab;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "FAB clicked", Toast.LENGTH_SHORT).show();
            }
        });
    }
   ...
 }

运行程序,点击FloatingActionButton按钮,如下:
在这里插入图片描述

3.2、Snackbar

Toast作用是告诉用户发生了什么事情,但同时用户只能被动接收这个事情,没有办法让用户原则。
Snackbar提示加入一个可交互按钮,当用户点击可以执行一些额外的操作。

Snackbar的用法:可以增加额外的点击事件。修改MainActivity中的代码如下:


public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    private DrawerLayout mDrawerLayout;
    private NavigationView navView;
    private FloatingActionButton fab;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(v,"Data deleted",Snackbar.LENGTH_SHORT).setAction("Undo", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(MainActivity.this, "Data restored", Toast.LENGTH_SHORT).show();
                    }
                }).show();
            }
        });
    }
  ...  
  }

调用Snakebarmake()来创建一个Snakebar对象:

  • 第一个参数传入view(当前布局的任意一个View,自动查找最外层布局),用户展示Snakebar。

  • 第二个参数Snakebar显示的内容,第三个参数用于显示的时长。

紧接着调用setAction()设置执行一个动作。从而可以和用户进行交互。最后调用show()显示。

重新运行程序,点击悬浮按钮,如下:
在这里插入图片描述
Snakebar上面有我们提示的文字,UNDO按钮可以点击。过一段时间Snakebar从底部消失(自带动画,用户提体比较好)。

这个Snakebar将我们的悬浮按钮遮挡了。这是一个bug,影响用户体验。解决办法借助CoordinatorLaoyout轻松解决。

3.3、CoordinatorLayout

CoordinatorLaoyout是一个加强版的FrameLayout。它可以监听所有子控件的各种事情,自动帮助我们做出合理的响应。

在刚才的Snackbar弹出后会遮挡FloatingActionButton,如果我们使用CoordinatorLayout布局,他可以监听到Snackbar的弹出事件,它会自动将内部的FloatingActionButton向上偏移。

只需要CoordinatorLaoyout来替换我们的FrameLayout,修改main_activity.xml中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="match_parent">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        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="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        <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>
    ...
</androidx.drawerlayout.widget.DrawerLayout >

在这里插入图片描述
消失的时候,悬浮按钮会回到原来的位置,悬浮按钮的上下偏移也伴随着动画的效果,且与Snakebar完全同步,整体效果赏心悦目。

Snakebar传入的View是当前的FloatingActionButton,所以就能通过CoordinatorLayout监听到了。

4、 卡片式布局

4.1、CardView

CardView是实现卡片式布局的重要控件,它也是一个FrameLayout,只是额外增加了圆角和投影的效果,立体感。

注:Glide库,GitHub地址,是一个超级强大的图片加载库,不仅可以用来加载本地图片,还可以加载网络图片,GIF图片,甚至是本地视频.

CardView 的基本用法,代码如下:

1、修改MainActivity中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="match_parent">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        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="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <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>
    ...
</androidx.drawerlayout.widget.DrawerLayout >

2、接下来定义RecycleView的子项布局fruit_item.xml文件

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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="wrap_content"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/fruit_image"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:scaleType="centerCrop" />

        <TextView
            android:id="@+id/fruit_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:textSize="16sp" />
    </LinearLayout>

</androidx.cardview.widget.CardView>

Image中使用了scaleType属性,指定图片的缩放式。centerCrop(原有图片充满ImageView)。

3、定义Fruit实体类:

public class Fruit {

    private String name;
    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }


    public int getImageId() {
        return imageId;
    }

}

4、FruitAdapter适配器

接下来为RecycleView准备FruitAdapter适配器,继承自RecycleView.Adapter,并将泛型指定为FruitAdapter.ViewHolder,代码如下:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private Context mContext;
    private List<Fruit> mFruitList;

    public FruitAdapter(Context mContext, List<Fruit> mFruitList) {
        this.mContext = mContext;
        this.mFruitList = mFruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mContext == null) {
            mContext = parent.getContext();
        }
        View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruit_name.setText(fruit.getName());
        Glide.with(mContext).load(fruit.getImageId()).into(holder.fruit_image);
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        CardView cardView;
        ImageView fruit_image;
        TextView fruit_name;

        public ViewHolder(View itemView) {
            super(itemView);
            cardView = (CardView) itemView;
            fruit_image = (ImageView) itemView.findViewById(R.id.fruit_image);
            fruit_name = (TextView) itemView.findViewById(R.id.fruit_name);
        }
    }
}

Glide的用法:

首先调用Glide的with()方法并传入一个Context,Activity或Fragment参数,然后调用load()方法,传入图片的URL地址,也可以是本地路径,或者是id,接着调用info()方法设置到具体的哪个ImageView。

5、修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {

    private List<Fruit> mData = new ArrayList<>();
    private Fruit[] fruits = {new Fruit("Apple", R.drawable.apple), new Fruit("Banana", R.drawable.banana),
            new Fruit("Orange", R.drawable.orange), new Fruit("Watermelon", R.drawable.watermelon),
            new Fruit("Pear", R.drawable.pear), new Fruit("Grape", R.drawable.grape),
            new Fruit("Pineapple", R.drawable.pineapple), new Fruit("Strawberry", R.drawable.strawberry),
            new Fruit("Cherry", R.drawable.cherry), new Fruit("Mango", R.drawable.mango)};

    private Toolbar toolbar;
    private DrawerLayout mDrawerLayout;
    private NavigationView navView;
    private FloatingActionButton fab;
    private RecyclerView mRecyclerView;

    private FruitAdapter adapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        initFruits();
        mRecyclerView = (RecyclerView) findViewById(R.id.recycle_view);
        GridLayoutManager manager = new GridLayoutManager(this, 2);
        mRecyclerView.setLayoutManager(manager);
        adapter = new FruitAdapter(this, mData);
        mRecyclerView.setAdapter(adapter);

    }

    private void initFruits() {
        mData.clear();
        for (int i = 0; i < 50; i++) {
            Random random = new Random();
            int index = random.nextInt(fruits.length);
            mData.add(fruits[index]);
        }
    }
    ...
   }

运行程序如下:
在这里插入图片描述
我们把精美的图片展示在单独的卡片当中,并且还有圆角和阴影(美观)。

我么发现了一个bug,Toolbar被RecycleView遮住了。为了解决这个问题,借助工具——AppBarLayout。

4.2、AppBarLayout

既然我们使用的是CoordinatorLayout(原理),自然会有更加巧妙的办法解决。

Design Support中的AppBarLayout。实际是一个垂直方向的LinerLayout,它在内部做了很多滚动封装,使用Material Design设计理念。

只需两步解决Toolbar覆盖问题:

  • 第一步,将Toolbar嵌套到AppBarLayout中
  • 第二步,给RecycleView指定一个布局(app:layout_behavior)。修改activity_main.xml中的代码如下
<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="match_parent">


    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <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/colorPrimary"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </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" />
 ...
</androidx.drawerlayout.widget.DrawerLayout>

appbar_scrolling_view_behavior是Design Support提供的。

运行程序如下,你会发现一切正常:
在这里插入图片描述
进一步优化,AppBarLayout实现 Material Design 效果,当AppBarLayout接收到滚动事件,通过 app:layout_scrollFlags 属性实现内部子控件的事件。修改activity_main中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="match_parent">


    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <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/colorPrimary"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:layout_scrollFlags="scroll|enterAlways|snap"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </com.google.android.material.appbar.AppBarLayout>
        ...
</androidx.drawerlayout.widget.DrawerLayout >

指定app:layout_scrollFlags属性scroll|enterAlways|snap

  • scroll表示当RecycleView向上滚动的时候,Toolbar会跟着向上滑动并实现隐藏;
  • enterAlways表示当RecycleView向下滑动并重新显示。
  • snap表示Toolbar还没有完全隐藏或显示的时候,根据当前滚动的距离自动选择显示还是隐藏。

运行程序,向上滑动,如图:
在这里插入图片描述

5、 下拉刷新(SwipeRefreshLayout)

Material Design 中制定了Android的统一的下拉刷新的风格。

SwipeRefreshLayout是用于实现下拉刷新的核心类。

在RecycleView外层嵌套SwipeRefreshLayout,修改activity_main.xml中的代码,如下:

<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
    android:layout_height="match_parent">


    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        ...
        <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" />

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
     ...

</androidx.drawerlayout.widget.DrawerLayout >

修改MainActivity中的代码如下:

public class MainActivity extends AppCompatActivity {

    ...
    private SwipeRefreshLayout swipeRefresh;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
        swipeRefresh.setColorSchemeResources(R.color.colorPrimary); //设置颜色
        swipeRefresh.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();//通知数据发生变化
                        swipeRefresh.setRefreshing(false);//刷新结束事件,并隐藏进度条
                    }
                });
            }
        }).start();
     }
     ...
  }

重新运行程序,在屏幕往下托,就会出现下拉刷新的进度条,松手就会自动刷新,如图:
在这里插入图片描述

6、 可折叠式标题栏

6.1、CollapsingToolbarLayout

CollapsingToolbarLayout(Design Support)它是一个作用于Toolbar基础之上的布局。它可以让Toolbar的效果变得更加丰富,实现非常华丽的效果。

CollapsingToolbarLayout是不能独立存在的,它只限制在作为AppBarLayout子布局来使用。而AppBarLayout又必须作为CoordinatorLayout的子布局。

创建水果的详情展示界面,创建FruitActivity,并指定布局成为activity_fruit.xml,主要分为两部分:

  • 一个是水果标题栏
  • 一个是水果内容详情。

1、首先实现标题栏部分

这里使用CoordinatorLayout来作为最外层布局,里面嵌套AppBarLayout,在AppBarLayout里面嵌套CollapsingToolbarLayout布局,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout  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">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="250dp">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/fruit_image_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin" />
        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

</androidx.drawerlayout.widget.DrawerLayout  >

实现更加高级的Toolbar效果,我们把android:theme主题指定在上一层。app:contentScrim属性用于指定折叠状态以及折叠后的背景色。(折叠后就是一个普通的Toolbar)。 app:layout_scrollFlags属性中的sroll(CollapsingToolbarLayout会随着内容详情页一起滚动),exitUntilCollapsed(CollapsingToolbarLayout滚动完折叠之后就保留在界面上,不会移除屏幕)。

里面我们定义了一个ImaggView和Toolbar的高级标题(普通标题栏加上图片合成)。app:layout_collapseMode属性(用于当前控件在CollapsingToolbarLayout折叠过程中的折叠模式,pin表示在折叠过程中位置保持始终不变,parallax表示折叠过程中产生一定的错位偏移,视觉效果非常棒)。

2、接下来编写水果内容详情部分

继续修改activity_fruit.xml中的代码:

<?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">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="250dp">
        ...
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginTop="35dp"
                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"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|end" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

NestedScrollView布局和AppBarLayout是同级,与SrollView用法一样,增加了嵌套响应滚蛋事件的功能。只允许存放在一个直接子布局。app:layout_behavior属性指定行为布局,与之前的RecycleView用法一样。

之后我们加入悬浮按钮了,获得额外的动画效果。FloatingActionButton中的app:layout_anchor(指定瞄点,设置为AppBarLayout,悬浮按钮出现在水果标题局域栏内),接着使用app:layout_anchorGravity指定它的显示位置。

3、编辑完成界面之后,我们修改FruitActivity中的代码

public class FruitActivity extends AppCompatActivity {

    public static final String FRUIT_NAME = "fruit_name";
    public static final String FRUIT_IMAGE_ID = "fruit_image_id";

    private Toolbar toolbar;
    private ImageView fruitImageView;
    private TextView fruitContentText;
    private CollapsingToolbarLayout collapsingToolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fruit);

        Intent intent = getIntent();
        String fruitName = intent.getStringExtra(FRUIT_NAME);
        String fruitNameId = intent.getStringExtra(FRUIT_IMAGE_ID);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        fruitImageView = (ImageView) findViewById(R.id.fruit_image_view);
        fruitContentText = (TextView) findViewById(R.id.fruit_content_text);
        collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);

        setSupportActionBar(toolbar);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true); //默认按钮箭头
        }

        collapsingToolbar.setTitle(fruitName);  //设置当前标题
        Glide.with(this).load(fruitNameId).into(fruitImageView);
        String fruitContent = generateFruitContent(fruitName);
        fruitContentText.setText(fruitContent);
    }

    /**
     * 水果名循环拼接500次
     *
     * @param fruitName
     * @return
     */
    private String generateFruitContent(String fruitName) {
        StringBuilder fruitContent = new StringBuilder();
        for (int i = 0; i < 500; i++) {
            fruitContent.append(fruitName);
        }

        return fruitContent.toString();
    }

    /**
     * 处理HomeAsUp按钮的点击事件
     *
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish(); //返回上一个Activity
                break;
        }
        return super.onOptionsItemSelected(item);
    }
}


4、修改FruitAdapter来处理RecycleView的点击事件

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    ...
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mContext == null) {
            mContext = parent.getContext();
        }
        View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Intent intent = new Intent(mContext, FruitActivity.class);
                intent.putExtra(FruitActivity.FRUIT_NAME, fruit.getName());
                intent.putExtra(FruitActivity.FRUIT_IMAGE_ID, fruit.getImageId());
                mContext.startActivity(intent);
            }
        });
        return holder;
    }
...
}

我们给CardView注册了一个点击事件监听器。来启动FruitActivity。

重新运行程序,并点击任意水果,效果如下:
在这里插入图片描述
当我们向上滑动的时候,水果的背景图片的标题会慢慢的缩小,产生一些偏移的效果,如下:

在这里插入图片描述
继续向上拖动,直到标题栏完全处于折叠状态,如下:

在这里插入图片描述
这个时候我们向下拖动,就会执行一个相反的过程。

6.2 充分利用系统状态栏空间

Android5.0系统之后支持对状态栏和背景进行操作(使背景图和状态栏融合)。

我们需要借助android:fitsSystemWindows这个属性来完成。在CoordinatorLayout,AppBarLayout,CollapingToobarLayout这种嵌套结构的布局中还,将这个属性设置为true(表示该控件会出现在系统状态栏里)。

修改activiy_frui.xml中的代码如下:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    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_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/fruit_image_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />
             ...
        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>
  ...
</androidx.coordinatorlayout.widget.CoordinatorLayout>

设置完之后,我们还必须将程序中的状态栏指定为透明色。由于android:statusBarColor(@android:color/transparent)属性是Android5.0系统开始有的,系统差异的实现:

右击res—>New—>Directory,创建一个 values-21目录,在里面新建styles.xml文件进行编写:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="FruitActivityTheme" parent="AppTheme">
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

这里定义了一个FruitActivityTheme主题,它的父主题是AppTheme(继承了AppTheme所有的特性)。然后我们在这个主题里将状态栏指定为透明色。(Android5.0以上系统)。

为了能够让Android5.0系统识别定义FruitActivityTheme主题,我们修改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"></style>
</resources>

定义FruitActivityTheme主题,由于Android5.0之前无法指定颜色,所以里面不进行操作。

最后我们需要让FruitActivity使用这个主题,修改AndroidManifest.xml中的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hjw.materialtest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
        <activity
            android:name=".FruitActivity"
            android:theme="@style/FruitActivityTheme"></activity>
    </application>

</manifest>

运行在Android5.0以及以上的系统,水果详情页界面的效果如下:
在这里插入图片描述

参考

1、Android Material Design:常用控件学习笔记
2、Android第一行代码——第13章Material Design实战
3、Android第一行代码——第十二章MaterialDesign实战
4、第二行代码学习笔记——第十二章:最佳的 UI 体验——Material Design 实战

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值