38、Android--Material Design

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的父控件。

38、Android--Material Design

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>

这是一个登录页面的简单实例。

38、Android--Material Design

如果对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效果

  1. 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>
  1. 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();
        }
    }
}
  1. 最后是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;
    }
}

效果如下图所示:

38、Android--Material Design

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);
            }
        }
    }
}

效果如下所示:

38、Android--Material Design

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。然后我们来看看相关的效果:
38、Android--Material Design

38、Android--Material Design

上一篇:WPF 判断是否为设计(Design)状态


下一篇:在GitHub中向开源框架提交PR的过程