Material Design
Material Design是由Google推出的全新的设计语言,谷歌表示,这种设计语言旨在为手机、平板电脑、台式机和“其他平台”提供更一致、更广泛的“外观和感觉”。
谷歌推出Android 5.0之际,在带来了更加详细的Material Design设计规范的同时也推出了全新的Android
Design Support Library,这个兼容库很容易和之前的 Android Support Library 22.1混淆。它们都是兼容库,二
者的区别是这个库多了一些Material Design设计风格的控件。
SbackBar
SnackBar显示在屏幕的底部,包含 了文字信息与一个可选的操作按钮。它在指定时间结束之后自动消失。
public class MainActivity extends AppCompatActivity {
private RelativeLayout mRootContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRootContainer = findViewById(R.id.rl_root_container);
findViewById(R.id.btn_snack_bar)
.setOnClickListener(v -> {
showSnackBar();
});
}
private void showSnackBar() {
Snackbar.make(mRootContainer, "标题", Snackbar.LENGTH_LONG)
.setAction("点击事件", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Toast", Toast.LENGTH_SHORT).show();
}
}).setDuration(Snackbar.LENGTH_LONG)
.show();
}
}
SnackBar的make方法第一个参数是View类型,传入的是SnackBar的父控件。
TextlnputLayout
TextInputLayout控件是一个容器,它跟ScrollView一样只接受一个子元素,并且这个子元素是 EditText。
简单示例
代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rl_root_container"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="username"
android:maxLength="25"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="password"
android:maxLength="25"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
这是一个登录页面的简单实例。
如果对TextInputLayout输入框以及输入框上方的hint提示颜色不满意,则还可以在style.xml文件中对
colorAccent属性进行修改
错误提示
TextInputLayout还可以通过如下两个api来设置错误信息的友好提示:
TextInputLayout.setErrorEnabled(boolean enabled) // 打开和隐藏错误提示
TextInputLayout.setError("") // 设置错误提示文本
FloatingActionButton
它是一个负责显示界面基本操作的圆形按钮。其使用起来非常便捷,可以把它当作一个Button,代码如
下所示:
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:src="@mipmap/ic_launcher"
android:clickable="true"
android:backgroundTint="#3F51B5"
android:elevation="3dp"
app:pressedTranslationZ="6dp"/>
app:backgroundTint来设定背景填充色。
app:elevation用来设置正常状态的阴影大小,
app:pressedTranslationZ 用来设置点击时阴影的大小。
TabLayout
Tablayout继承自HorizontalScrollView,可以用作顶部标签效果、底部导航栏效果。一般多与ViewPager一起使用。
TabHost效果
- Activity的布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rl_root_container"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorHeight="2dp"
app:tabMode="fixed"
app:tabIndicatorColor="#0a0"
app:tabSelectedTextColor="#0a0"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="none"/>
</LinearLayout>
- Activity的代码如下:
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager viewPager;
private List<PageFragment> mPageFragments;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.tab_layout);
viewPager = findViewById(R.id.view_pager);
mPageFragments = new ArrayList<>();
// Init ViewPager
for (int i = 0; i < 5; i++) {
mPageFragments.add(new PageFragment("标题" + i, "内容" + i));
}
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
tabLayout.setupWithViewPager(viewPager);
}
class ViewPagerAdapter extends FragmentPagerAdapter{
public ViewPagerAdapter(@NonNull FragmentManager fm) {
super(fm);
}
@NonNull
@Override
public Fragment getItem(int position) {
return mPageFragments.get(position);
}
@Override
public int getCount() {
return mPageFragments.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mPageFragments.get(position).getTitle();
}
}
}
- 最后是Fragment的代码:
public class PageFragment extends Fragment {
private TextView tvContent;
private String title, content;
public PageFragment(String title, String content) {
this.title = title;
this.content = content;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_page, container, false);
tvContent = view.findViewById(R.id.tv_content);
tvContent.setText(content);
return view;
}
public String getTitle() {
return title;
}
}
效果如下图所示:
NavigationView
NavigationView 来可以实现抽屉菜单界面。和普通的侧拉菜单实现方式一样,所有的东西还是都放在一个DrawerLayout中,用NavigationView来替代我们此前自定义的控件。
Activity布局文件代码
<?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/rl_root_container"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:fitsSystemWindows="true">
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header_container"
app:menu="@menu/drawer_view">
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
注意:左侧菜单必须要设置android:layout_gravity="start",否则报错。
使用到的navigation_header_container.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:background="#660000ff"
android:gravity="center_horizontal"
android:layout_height="150dp">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="fitXY"
android:layout_gravity="center_vertical"
android:src="@mipmap/ic_launcher_round"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:gravity="center_vertical"
android:layout_marginTop="5dp"
android:layout_gravity="center_vertical"
android:text="legend"
android:textSize="20sp"/>
</LinearLayout>
使用到的菜单文件drawer_view.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_home"
android:icon="@mipmap/ic_launcher"
android:title="首页"/>
<item
android:id="@+id/nav_message"
android:icon="@mipmap/ic_launcher"
android:title="事项"/>
<item
android:id="@+id/nav_music"
android:icon="@mipmap/ic_launcher"
android:title="音乐"/>
<item
android:id="@+id/nav_discussion"
android:icon="@mipmap/ic_launcher"
android:title="消息"/>
</group>
<item android:title="其他">
<menu>
<item
android:icon="@mipmap/ic_launcher_round"
android:title="设置"/>
<item
android:icon="@mipmap/ic_launcher_round"
android:title="关于我们"/>
</menu>
</item>
</menu>
最后是Activity中代码的实现:
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = findViewById(R.id.rl_root_container);
NavigationView navigationView = findViewById(R.id.navigation);
navigationView.setNavigationItemSelectedListener(this);
mDrawerLayout.openDrawer(GravityCompat.START);
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
String title = item.getTitle().toString();
Toast.makeText(this, title, Toast.LENGTH_SHORT).show();
mDrawerLayout.closeDrawers();
return true;
}
}
CoordinatorLayout
CoordinatorLayout是在 Google IO/15 大会发布的,遵循Material 风格,包含在 support Library中,结合AppbarLayout, CollapsingToolbarLayout等 可 产生各种炫酷的效果
AppBarLayout
如果我们想要实现折叠的ActionBar效果,在CoordinatorLayout
中,AppBarLayout
绝对是作为首选的控件。
在正式介绍AppBarLayout
的使用时,我们先来看看几个Flag,这几个Flag在AppBarLayout
里面非常的重要。
名称 | 值 | 作用 |
---|---|---|
SCROLL_FLAG_NO_SCROLL | 0x0 | 将表示该View不能被滑动。也就是说不参与联动。 |
SCROLL_FLAG_SCROLL | 0x01 | 表示该View参与联动。具体效果需要跟其他Flag组合。 |
SCROLL_FLAG_EXIT_UNTIL_COLLAPSED | 0x02 | 表示当View被推出屏幕时,会跟着滑动,直到折叠到View的最小高度;同时只有在其他View(比如说RecyclerView )滑动到顶部才会展开。 |
SCROLL_FLAG_ENTER_ALWAYS | 0x02 | 不管是View是滑出屏幕还是滑进屏幕,该View都能立即响应滑动事件,跟随滑动。比如说,如果该View是折叠的,当RecyclerView 向下滑动时,该View随时都能跟随展开;反之亦然。 |
SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED | 0x04 | 在SCROLL_FLAG_ENTER_ALWAYS 的基础上,该Flag增加了折叠到固定高度的限制。在View下拉过程中,首先会将该View显示minHeight的高度,RecyclerView 在继续下拉(这里以RecyclerView 为例)。注意,该Flag在SCROLL_FLAG_ENTER_ALWAYS 前提下生效。 |
SCROLL_FLAG_SNAP | 0x08 | 该Flag表示View拥有吸附功能。比如说,当前滑动停止,View离底部更近,那么就会折叠;反之则会展开。 |
这几个Flag非常的简单,我们来看看具体的使用,先来看看布局文件:
<?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:id="@+id/rl_root_container"
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">
<View
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#5FF"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed"/>
<View
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#FF00FF"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.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" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
其中Activity的代码如下:
public class MainActivity extends AppCompatActivity{
private RecyclerView mRecyclerView;
private List<String> mStrings = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler_view);
for (int i = 0; i < 30; i++) {
mStrings.add("Item" + i);
}
CustomAdapter customAdapter = new CustomAdapter();
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(customAdapter);
}
class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>{
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_content, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull MainActivity.CustomAdapter.ViewHolder holder, int position) {
holder.tvContent.setText(mStrings.get(position));
}
@Override
public int getItemCount() {
return mStrings.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView tvContent;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvContent = itemView.findViewById(R.id.tv_item_content);
}
}
}
}
效果如下所示:
CollapsingToolbarLayout
CollapsingToolbarLayout
主要是实现折叠布局的,我们来看看是怎么使用的。首先,我们来看看CollapsingToolbarLayout
的几个Flag:
名称 | 值 | 作用 |
---|---|---|
COLLAPSE_MODE_OFF | 0 | 默认值,表示View不会有任何属性 |
COLLAPSE_MODE_PIN | 1 | 当CollapsingToolbarLayout 完全收缩之后,设置该Flag的View会保留在屏幕当中。 |
COLLAPSE_MODE_PARALLAX | 2 | 设置该Flag的View会跟内容滚动,可以通过setParallaxMultiplier 方法来设置视图差比率,其中0表示毫无视图差,完全跟内容滚动同步;1表示View完全不动。默认的视图差为0.5。 |
接下来我们看一个Demo:
<?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:id="@+id/rl_root_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="300dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/ic_launcher"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#5FF"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.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" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
其中Activity的代码同上个示例一样。
使用CollapsingToolbarLayout
时,我们需要注意的是:CollapsingToolbarLayout
需要作为AppBarLayout
子View。然后我们来看看相关的效果: