《第12章 最佳的UI体验——Material Design》

为了解决Android平台的界面风格长期难以统一的问题,Google I/O大会推出了一套全新的界面设计语言——Material Design,并且提供了一个Design Support

  1. ToolBar
    我们之前写的每一个项目都是默认带有ActionBar的,在权限清单中,指定了:
    <application
    	android:theme="@style/AppTheme">
    	
    </application>
    
    位于res/values/styles.xml文件中:
    <resources>
    	<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    		<item name="colorPrimary">@color/colorPrimary</item>
    		<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    		<item name="colorAccent">@color/colorAccent</item>
    	</style>
    </resource>
    
    指定了父主题,并且重写了三个颜色
    我们需要将原来的主题屏蔽掉,将styles.xml文件中的parent改为Theme.AppCompat.Light.NoActionBar(浅色主题)或者Theme.AppCompat.NoActionBar(深色主题)
    然后就可以使用ToolBar代替ActionBar
    直接在布局文件中使用Toolbar就可以
    <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"
               >
    
    然后在活动中使用这个Toolbar:
    Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    
    如果要修改Toolbar的显示内容,在权限清单中指定android:label属性即可:
    <activity android:label="Fruits">
    </activity>
    
  2. 结合menu使用
    首先在res目录下新建一个menu目录,然后在menu目录下新建一个Menu resource file名为: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/backup"
            android:icon="@drawable/ic_backup"
            android:title="Backup"
            app:showAsAction="always"/>
        <item
            android:id="@+id/delete"
            android:icon="@drawable/ic_delete"
            android:title="Delete"
            app:showAsAction="ifRoom"/>
        <item
            android:id="@+id/settings"
            android:icon="@drawable/ic_settings"
            android:title="Settings"
            app:showAsAction="ifRoom"/>
    </menu>
    
    showAsAction属性用来指定是否显示图标:always,ifRoon,never
    要想使用该menu,要在活动中重写boolean onCreateOptionsMenu(Menu menu)和void onOptionsItemSelected(MenuItem item):
    public boolean onCreateOptionsMenu(Menu menu){
    	getMenuInflater().inflate(R.menu.toolbar,menu );	
    	return true;
    }
    
    public boolean onOptionsItemSelected(MenuItem item){
    	switch(item.getItemId()){
    		case R.id.backup:
    	}
    	return true;
    }
    

总结:

  1. 在普通的ActionBar中,使用menu的话,menu的具体的几个选项不会分开显示;而在Toolbar中,menu的具体选项会分开显示;
  2. 除此之外使用方法是一样的,都要在主函数中重写两个方法;
  3. 在Toolbar中的item多了一个app:showAsAction方法,用来设置每个选项的显示方式。

  1. 滑动菜单DrawerLayout
    DrawerLayout是一个布局,它允许加入两个直接子控件,第一个子控件是主屏幕中显示的内容,第二个子控件是滑动菜单中显示的内容.
    第2个控件中必须要指定android:layout_gravity=“start”,end,left,fight

  2. 目前滑动菜单必须要用户手动滑动才可以,但是有的用户可能并不知道可以滑动,所以我们可以用一个导航按钮来提示用户,当点击了该按钮后,滑动菜单的内容也可以显示出来
    只需要在活动的初始化方法中加入如下代码即可:

    private DrawerLayout mDrawerLayout;
    
    public void onCreate(){
    	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);
    			break;
    	}
    }
    

    此处,导航按钮的id始终是android.R.id.home
    调用DrawerLayout对象的openDrawer()可以让滑动菜单显示出来,方法要求传入一个Gravity参数,我们直接传入Gravity.START,让它的行为与XML文件中定义的行为一致

  3. 定制滑动菜单(使用NavigationView
    NavigationViewDesign support库提供的,所以先在build.gradle里面添加依赖:

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

    第一个是Design Support库,第二个是一个实现图片圆形化的开源项目CircleImageView,项目地址是:https://github.com/hdodenhof/CircleImageView

    在开始使用导航界面以前,我们还需要准备好两个东西:menuheaderLayout
    在menu文件夹下新建一个menu文件,名为:nav_menu,编写如下代码:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
    <!--表示一个组,single,all,none-->
        <item
            android:id="@+id/nav_call"
            android:icon="@drawable/nav_call"
            android:title="Call"/>
    
        <item
            android:id="@+id/nav_friends"
            android:icon="@drawable/nav_friends"
            android:title="Friends"/>
        <item
            android:id="@+id/nav_location"
            android:icon="@drawable/nav_location"
            android:title="Location"/>
        <item
            android:id="@+id/nav_mail"
            android:icon="@drawable/nav_mail"
            android:title="Mail"/>
        <item
            android:id="@+id/nav_task"
            android:icon="@drawable/nav_task"
            android:title="Tasks"/>
    </group>
    </menu>
    

```
接下来在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:padding="10dp"
android:background="?attr/colorPrimary">
<de.hdodenhof.circleimageview.CircleImageView
    android:id="@+id/icon_image"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:src="@drawable/nav_icon"
    android:layout_centerInParent="true"/>
<TextView
    android:id="@+id/mail"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:text="yzc35326@gmail.com"
    android:textColor="#fff"
    android:textSize="14sp"/>
<TextView
    android:id="@+id/username"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/mail"
    android:text="Zy"
    android:textAllCaps="false"
    android:textColor="#fff"
    android:textSize="14sp"/>


</RelativeLayout>
```

```
menu和headerLayout都准备好了,接下来就可以使用NavigationView了
修改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/drawaer_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:menu="@menu/nav_menu"指定menu
        app:headerLayout="@layout/nav_header"/>指定headerLayout


</androidx.drawerlayout.widget.DrawerLayout>
```

```
处理菜单项中的点击事件
NavigationView navView = (NavigationView)findViewById(R.id.nav_view);
navView.setCheckedItem(R.id.nav_call);//将Call菜单项设为选中
navView.setNavigationItemSelectedListener(new NavigationView.onNavigationItemSelectedListener(){
	@Override
	public boolean onNavigationItemSelected(MenuItem item){
		mDrawerLayout.closeDrawers();
		return true;
});
```

悬浮按钮和可交互提示

悬浮按钮:FloatingActionButton

在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/drawaer_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>
	    <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"指定menu
	        app:headerLayout="@layout/nav_header"/>指定headerLayout


	</androidx.drawerlayout.widget.DrawerLayout>

然而FloatingActionButton注册点击的方法和普通的按钮一样……

FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
           	 Toast.makeText(MainActivity.this, "Data restored", Toast.LENGTH_SHORT).show();          
            }
        });

一个类似于Toast的工具:Snackbar

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.makeToast(MainActivity.this,"Data restored",Toast.LENGTH.SHORT).show();
					}
				}).show();
	}
}
);

但是当前这种方式,显示Snackbar会将悬浮按钮给遮挡住,这需要借助CoordinatorLayout解决

直接用CoordinatorLayout替换掉原来的activity_layout.xml文件中的帧布局即可,因为CoordinatorLayout就是一个加强版的帧布局。
可以自动监听到该布局中的任何事件,然后做出合理的响应。

AppBarLayout:将Toolbar放进AppBarLayout中 可以防止被遮挡。它实际上是一个竖直方向的LinearLayout。
然后给RecyclerView一个布局行为:app:layout_behavior="@string/appbar_scrolling_view_behavior"
然后给AppBarLayout的子控件Toolbar一个属性,指定它如何去影响AppBarLayout:app:layout_scrollFlags=“scroll|enterAlways|snap”
其中:scroll表示,当RecyclerView向上滚动的时候,Toolbar会跟着一起向上滚动并实现隐藏
enterAlways:表示当RecyclerView向下滚动的时候,Toolbar会跟着一起向下滚动并重新显示
snap:表示当Toolbar还没完全显示或隐藏的时候,根据当前滚动的距离,自动选择是隐藏还是显示


下拉刷新:SwipeRefreshLayout

SwiperRefreshLayout swipeRefresh = (SwipeRefreshLayout)findViewById(R.id.swipe_refresh);
swiperRefresh.setColorSchemeResources(R.color.colorPrimary);//设置下拉刷新进度条的颜色
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener(){
	@Override
	public void onRefresh(){
		refreshFruits();
	}
});//设置下拉刷新的监听器

总结:
使用滑动菜单(DrawerLayout)的话,可以向里面放两个直接子控件,第一个子控件是主界面,第二个子界面是滑动菜单,要设置layout_gravity方式。
主界面:首先可以使用Toolbar代替原来的标题栏。并加入悬浮按钮(FloatingActionButton),设置响应事件,用SnackBar代替弹出的Toast,但是弹出的时候会遮住FloatingActionBar,所以考虑将主界面放进一个CoordinatorLayout中,这是一个加强版的FrameLayout,然后就会解决遮挡的情况。主界面可以放入滚动布局RecyclerView,并且用网格式布局来实现,滚动布局用卡片布局(也是加强版的FrameLayout)来实现,卡片布局里面套一个LinearLayout方便定位,并且顶部的Toolbar可以用AppBarLayout来代替,实现动态的隐藏和显示的功能
下拉刷新用SwiperRefreshLayout实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值