Toolbar
首先把ActionBar的主题改成Theme.AppCompat.Light.NoActionBar或者Theme.AppCompat.NoActionBar,这样就隐藏了ActionBar。
然后修改activity_main.xml的代码
<?xml version="1.0" encoding="utf-8"?><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">
<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/Theme.AppCompat.Light"
/>
</FrameLayout>
activity
public class MainActivity extends AppCompatActivity{
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar=findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
}
添加标题的话新建一个menu.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:icon="@drawable/ic_settings"
android:title="你好"
app:showAsAction="ifRoom"/>
</menu>
加载menu中的菜单
@Override
public boolean onCreateOptionsMenu(Menu menu) {//加载menu中的菜单
getMenuInflater().inflate(R.menu.mneu,menu);
return true;
}
实现监听
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {//监听
switch (item.getItemId()){
case R.id.item1:
Toast.makeText(this, "你好", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}
滑动菜单
DrawerLayout
直接在布局文件添加DrawerLayout
<?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"
tools:context=".MainActivity">
<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/colorAccent"/>
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World!"
android:layout_gravity="start"//一定要添加这个 要告诉DrawerLayout滑动屏幕的菜单时左边还是右边
android:textSize="30sp"
/>
</androidx.drawerlayout.widget.DrawerLayout>
添加导航按钮 让用户知道可以滑动菜单
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.drawerlayout);
ActionBar actionBar=getSupportActionBar();//调用getSupportActionBar()得到ActionBar的实例
if (actionBar!=null){//如果不为空
actionBar.setDisplayHomeAsUpEnabled(true);//调用setDisplayHomeAsUpEnabled 把导航按钮显示出来
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);//设置导航按钮图标
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
break;
default:
}
return true;
}
}
NavigationView
- 添加依赖
implementation 'com.google.android.material:material:1.1.0-alpha09' //这个是design库
implementation 'de.hdodenhof:circleimageview:2.1.0'//这个是实现图片圆形化的库
- 在使用NavigationView时,需要提前准备好两个东西,menu和headerLayout。menu是用来在NavigationView中显示菜单项的,headerLayout则是在NavigationView中显示头部布局的
先来看menu
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- checkableBehavior指定为single表示组中的所有菜单项只能单选 groun表示一个组-->
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_call"
android:icon="@drawable/nav_call"
android:title="打电话"/>
<item
android:id="@+id/nav_mail"
android:icon="@drawable/nav_mail"
android:title="发邮箱"/>
<item
android:id="@+id/nav_friends"
android:icon="@drawable/nav_friends"
android:title="发邮箱"/>
<item
android:id="@+id/nav_task"
android:icon="@drawable/nav_task"
android:title="tasks"/>
</group>
</menu>
再来看headerLayout,去新建一个布局文件 ,这个可以随意定制布局,我们为了简单起见,只设置头像和邮箱地址
<?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:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/icon_image"
android:src="@drawable/nav_icon"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="你好世界"
android:textColor="#fff"
android:textSize="14sp"/>
</RelativeLayout>
设置好menu和headerlayout之后,就可以使用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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<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/colorAccent"/>
</FrameLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/headerlayout"/>
</androidx.drawerlayout.widget.DrawerLayout>
NavigationView的定义完成了,但是还差菜单项的单击事件,修改MainActivity中的代码
@Override
protected void onCreate(Bundle savedInstanceState) {
......
NavigationView navigationView=findViewById(R.id.nav_layout);//获取NavigationView实例
......
navigationView.setCheckedItem(R.id.nav_call);//将call菜单项设置为默认选中
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.nav_call:
Toast.makeText(MainActivity.this, "打电话", Toast.LENGTH_SHORT).show();
}
return true;
}
});
}
悬浮按钮和可交互提示
FloatingActionButton
FloatingActionButton是Design库中的一个控件,它可以帮助我们实现悬浮按钮的效果。
下面开始具体操作
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
.......
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
......../>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"//指定把控件放置在右下角
android:layout_margin="16sp"
android:src="@drawable/ic_done"/>
</FrameLayout>
......
</androidx.drawerlayout.widget.DrawerLayout>
效果
实现监听器,和button一样
FloatingActionButton fb=findViewById(R.id.floatbutton);
fb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "我是弹窗", Toast.LENGTH_SHORT).show();
}
});
Snackbar
也是Design库中的 ,有着更为先进的提示工具
它允许在提示中加入一个可交互按钮,当用户点击按钮的时候执行一些额外的逻辑操作。
用法
FloatingActionButton fb=findViewById(R.id.floatbutton);
fb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* make()方法的第一个参数是view,只要是当前界面布局的任意一个View都可以,
* Snackbar会使用这个view来自动查找最外层的布局,用于展示Snackbar
* 第二个参数是显示内容,第三个参数是显示的时长
* 然后调用setAction()方法来设置一个动作。从而可以和用户进行交互
*/
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();
}
});
但是有一个bug,这个Snackbar居然把我们的悬浮按钮遮挡了,这个我们可以用CoordinatorLayout来解决
CoordinatorLayout
CoordinatorLayout是一个加强版的FrameLayout,也是Design库提供的。
CoordinatorLayout可以监听其所有的子控件的各种事件,然后自动帮助我们做出最为合理的响应,比如刚才弹出的提示把悬浮按钮遮挡了,但是如果我们能让CoordinatorLayout监听到Snackbar的弹出事件,那么他会自动将悬浮按钮向上偏移,从而不会被遮挡。
试试把。
- 修改布局文件,把FrameLaout替换成CoordinatorLayout。
<?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:id="@+id/drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<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="@color/colorAccent"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/floatbutton"
android:layout_gravity="bottom|end"
android:layout_margin="16sp"
android:src="@drawable/ic_done"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/headerlayout"/>
</androidx.drawerlayout.widget.DrawerLayout>
运行
卡片式布局
CardView
CardView是用于实现卡片式布局效果的重要控件,实际上,CardView也是一个FrameLayout,只是额外提供了圆角和阴影等效果,看上去会有立体的效果。
用法
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
<!-- 卡片圆角弧度-->
app:cardCornerRadius="4dp"
<!-- 卡片的高度,高度值越大,投影范围就越大-->
android:elevation="5dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.cardview.widget.CardView>
实战
<?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:id="@+id/drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<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="@color/colorAccent"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycle_view"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/floatbutton"
android:layout_gravity="bottom|end"
android:layout_margin="16sp"
android:src="@drawable/ic_done"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/headerlayout"/>
</androidx.drawerlayout.widget.DrawerLayout>
新建Friut类
package com.dos.material;
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;
}
}
创建适配器
package com.dos.material;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private Context context;
private List<Fruit> fruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
CardView cardView;
ImageView fruitImage;
TextView textView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
fruitImage=itemView.findViewById(R.id.fruit_image);
textView=itemView.findViewById(R.id.fruit_name);
cardView= (CardView) itemView;
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (context==null){
context=parent.getContext();
}
View view= LayoutInflater.from(context).inflate(R.layout.fruit_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit=fruitList.get(position);
holder.textView.setText(fruit.getName());
//with()方法是传入一个context,然后调用load()加载图片,然后用into()方法将图片设置到具体某一个imageview就可以了
Glide.with(context).load(fruit.getImageId()).into(holder.fruitImage);
}
@Override
public int getItemCount() {
return fruitList.size();
}
public FruitAdapter(List<Fruit> fruitList) {
this.fruitList = fruitList;
}
}
Mainactivity
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList=new ArrayList<>();
private FruitAdapter adapter;
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)};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initfruit();
RecyclerView recyclerView=findViewById(R.id.recycle_view);
GridLayoutManager gridLayoutManager=new GridLayoutManager(this,2);
recyclerView.setLayoutManager(gridLayoutManager);
adapter=new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initfruit() {
fruitList.clear();
for (int i=0;i<50;i++){
Random random=new Random();
int index=random.nextInt(fruits.length);
fruitList.add(fruits[index]);
}
}
我们发现我们的Toolbar被遮挡了。
AppBarLayout
那么怎么解决前面的遮挡问题呢?
只需要两步
第一把Toolbar嵌套在Appbarlayout中,第二部给RecyclerView指定一个布局行为。
<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="@color/colorAccent"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recycle_view"
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="@color/colorAccent"
app:layout_scrollFlags="scroll|enterAlways|snap"/>
</com.google.android.material.appbar.AppBarLayout>
这里添加了一个app:layout_scrollFlags属性
srcoll表示当RecyclerView向上滚动的时候,Toolbar会跟着一起向上滚动并实现隐藏,
enterAlways表示当RecyclerView向下滚动的时候,Toolbar会跟着一起向下滚动并重新显示,
snap表示当Toolbar还没有完全隐藏或显示的时候,会根据当前滚动的距离,自动选择隐藏还是显示。