美文网首页
Android 5.0新特性之Material Design

Android 5.0新特性之Material Design

作者: 付凯强 | 来源:发表于2017-08-18 14:12 被阅读0次

    1. Toolbar

    • Toolbar的强大之处在于:不仅继承了ActionBar的所有功能,而且灵活性很高,可以配合其他控件来完成一些Material Design的效果。
    • 新建一个项目,默认显示ActionBar,是因为项目中指定的主题含有ActionBar。
    android:theme="@style/AppTheme"
    
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    
    • 准备使用Toolbar替代ActionBar,指定一个不带ActionBar的主题,通常以下两种:
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    Light表示淡色主题,主体颜色淡色,陪衬颜色深色。
    <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
    默认是深色主题,主体颜色深色,陪衬颜色淡色。
    
    • 我们需要了解几个名词colorPrimary、colorPrimaryDark、colorAccent、textColorPrimary、windowBackground和navigationBarColor所指定的位置。

    2. 编写一个Toolbar

    • 布局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">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="wrap_content"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    
    </FrameLayout>
    
    说明:
    1.xmlns:android 表示可以使用android:id等。xmlns:app 表示可以使用app:attribute。
    2.整体是淡色主题,Toolbar上的各种要素自动使用深色系,字体颜色是黑色。为了体验更好,借助android:theme单独设置Toolbar的主题是深色主题,这样字体颜色就会是白色。
    3.Toolbar单独设置为深色主题,菜单按钮弹出的菜单项也会变成深色主题,太难看,所以我们使用app:popupTheme设置菜单项为淡色主题。
    
    • 修改MainActivity:
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
        }
    }
    
    说明:外观和功能和ActionBar一致。
    
    • 修改标题栏上显示的文字内容
    android:label="Fruits"
    
    • 添加action按钮
      新建res-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/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="never" />
    </menu>
    
    说明:
    1.showAsAction指定按钮的显示位置。always:永远显示在Toolbar中,如果屏幕空间不够则不显示;ifRoom:屏幕空间足够的情况下显示在Toolbar中,不够的话显示在菜单中;never表示永远显示在菜单当中。
    2.Toolbar中的action按钮只会显示图标,菜单中的action按钮只会显示文字。
    
    • 修改MainActivity:
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.toolbar,menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()){
                case R.id.backup:
                    Toast.makeText(this,"Backup",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.delete:
                    Toast.makeText(this,"Delete",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.settings:
                    Toast.makeText(this,"Settings",Toast.LENGTH_SHORT).show();
                    break;
            }
            return true;
        }
    }
    
    说明:之前章节有讲,这里就不再赘述。
    

    3. 显示DrawerLayout

    • 修改activity_main.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.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">
    
            <android.support.v7.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>
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="#FFF"
            android:text="This is menu"
            android:textColor="#FFF00000"
            android:textSize="30sp" />
    
    </android.support.v4.widget.DrawerLayout>
    
    说明:
    1.最外层是DrawerLayout,包含两个子控件,第一个控件是FrameLayout,第二个控件是TextView,前者显示主屏幕,后者显示滑动菜单内容。
    2.第二个控件借助layout_gravity指定滑动出现的方式,left是左边,right是右边,start根据系统语言进行判断。
    

    4. 主屏幕Toolbar左边添加导航按钮,实现点击显示滑动菜单

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar 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);
            }
        }
        
    说明:
    1. 获取Drawerlayout控件的实例,用于设置滑动菜单的显示方式。
    2. 获取ActionBar的实例,setDisplayHomeAsUpEnabled显示导航按钮,按钮显示出来,利用setHomeAsUpIndicator设置按钮图标。
    
    case android.R.id.home:
        mDrawerlayout.openDrawer(GravityCompat.START);
        break;
        
    说明:设置滑动菜单显示方式。
    

    5. NavigationView

    我们可以任意定制我们的滑动菜单的布局,不过谷歌提供了一个一种更好的方法——使用NavigationView,让滑动菜单页面的实现变得非常简单。

    • 添加依赖:
    compile 'com.android.support:design:25.3.1'
    compile 'de.hdodenhof:circleimageview:2.1.0'
    
    • 创建menu菜单nav_menu:
    <?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_call"
                android:icon="@drawable/nav_call"
                android:title="Call"></item>
            <item
                android:id="@+id/nav_friends"
                android:icon="@drawable/nav_friends"
                android:title="Friends"></item>
            <item
                android:id="@+id/nav_location"
                android:icon="@drawable/nav_location"
                android:title="Location"></item>
            <item
                android:id="@+id/nav_mail"
                android:icon="@drawable/nav_mail"
                android:title="Mail"></item>
            <item
                android:id="@+id/nav_task"
                android:icon="@drawable/nav_task"
                android:title="Tasks"></item>
        </group>
    </menu>
    
    说明:checkableBehavior表示item只可以单选。
    
    • 定制headerLayout,它的布局命名为nav_header:
    <?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/username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="fkq339@gmail.com"
            android:textColor="#FFF"
            android:textSize="14sp" />
    
        <TextView
            android:id="@+id/mail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/username"
            android:text="Tony Green"
            android:textColor="#FFF"
            android:textSize="14sp" />
    </RelativeLayout>
    
    • 修改activity_main:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.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">
    
            <android.support.v7.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>
    
        <android.support.design.widget.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">
        </android.support.design.widget.NavigationView>
    
    </android.support.v4.widget.DrawerLayout>
    
    说明:之前的滑动菜单为TextView,现在用NavigationView代替TextView。利用:app:headerLayout和app:menu设置我们刚才准备好的menu和headerLayout.
    
    • 处理点击事件
    
    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            mDrawerlayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            NavigationView navigationview = (NavigationView) findViewById(R.id.nav_view);
            ActionBar actionBar = getSupportActionBar();
            if (actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(true);
                actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
            }
            navigationview.setCheckedItem(R.id.nav_call);
            navigationview.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                    mDrawerlayout.closeDrawer(Gravity.START);
                    return true;
                }
            });
        }
    
    说明:获取NavigationView的实例,并且设置Call菜单项为默认选中,点击后回调onNavigationItemSelected方法,这个时候我们关闭滑动菜单。
    

    6. FloatingActionButton

    • 布局:
    <android.support.design.widget.FloatingActionButton
        app:elevation="8dp"
        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" />
        
    说明:
    1.elevation指定的是悬浮的高度。
    2.layout_gravity让控件位于底部,end根据系统语言决定左边或者右边。
    3.layout_margin表示控件周围有空隙,更加美观。
    4.src 可以用一张图片展示在悬浮按钮上。
    
    • 点击事件:
    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(this);
    
    说明:并没有特殊之处,它和普通的button一样。
    

    7. Snackbar

    • Snackbar不是Toast的替代品。
    • Toast作用是告诉用户现在发生了什么事情,用户被动接收;而Snackbar则允许在提示的过程中加入一个可交互的按钮,当用户点击按钮的时候可以执行一些额外的逻辑操作。
    • 举例子:点击按钮,执行删除的操作,Snackbar的交互就可以在点击后起到反悔的功能。
        @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();
        }
        
    说明:
    1. Snackbar.make方法接收三个参数:第一个参数接收一个View,只要是当前布局的任意一个View就可以,Snackbar会使用这个View来自动查找最外层的布局,来展示Snackbar;第二个参数是Snackbar显示的内容;第三个参数是显示的时间。
    2. 接着调用setAction来执行反悔的操作。
    

    8. CoordinatorLayout

    • CoordinatorLayout是一个加强版的FrameLayout,可以监听所有子控件的各种事件,然后做出最为合理的响应。
    • Snackbar提示将悬浮按钮遮挡住了,而如果能让CoordinatorLayout监听到Snackbar的弹出事件,那么它自动会将内部的FloatingActionButton向上偏移,从而确保不会被Snackbar遮挡到。
    • 使用非常简单:替换下FrameLayout即可。
    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.v7.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" />
    
        <android.support.design.widget.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" />
    </android.support.design.widget.CoordinatorLayout>
    
    说明:虽然Snackbar不在CoordinatorLayout里面,但是Snackbar的make方法接收的第一个参数View是FloatingActionButton,也就是说Snackbar基于FloatingActionButton触发的。FloatingActionButton是CoordinatorLayout的子控件,自然可以监听到Snackbar。
    

    9. CardView

    CardView也是一个FrameLayout,只是额外提供了圆角和阴影等效果。以下是结合RecyclerView的示例。其中的知识点我们已经在第3章详细讲解,这里不在赘述。

    • 添加依赖:
        compile 'com.android.support:recyclerview-v7:25.3.1'
        compile 'com.android.support:cardview-v7:25.3.1'
        compile 'com.github.bumptech.glide:glide:3.7.0'
    
    • 整体布局:
     <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.v7.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" />
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
    
            <android.support.design.widget.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" />
        </android.support.design.widget.CoordinatorLayout>
    
    • 子项布局:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.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"
        android:orientation="vertical"
        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>
    </android.support.v7.widget.CardView>
    
    说明:
    1.CardView没有好的定位方式,所以里面包裹一个LinearLayout。
    2.app:cardCornerRadius设置的是圆角的大小。
    3.scaleType指的是图片的缩放模式。
    
    • 实体类
    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 void setName(String name) {
            this.name = name;
        }
    
        public int getImageId() {
            return imageId;
        }
    
        public void setImageId(int imageId) {
            this.imageId = imageId;
        }
    }
    
    • FruitAdapter类
    public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
        private Context mContext;
        private List<Fruit> mFruitList;
    
        static class ViewHolder extends RecyclerView.ViewHolder {
    
            CardView cardview;
            ImageView fruitimage;
            TextView fruitName;
    
            public ViewHolder(View view) {
                super(view);
                cardview = (CardView) view;
                fruitimage = (ImageView) view.findViewById(R.id.fruit_image);
                fruitName = (TextView) view.findViewById(R.id.fruit_name);
            }
        }
    
        public FruitAdapter(List<Fruit> mFruitList) {
            this.mFruitList = mFruitList;
        }
    
        @Override
        public FruitAdapter.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(FruitAdapter.ViewHolder holder, int position) {
            Fruit fruit = mFruitList.get(position);
            holder.fruitName.setText(fruit.getName());
            Glide.with(mContext).load(fruit.getImageId()).into(holder.fruitimage);
        }
    
        @Override
        public int getItemCount() {
            return mFruitList.size();
        }
    }
    
    • MainActivity:
    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 List<Fruit> fruitList = new ArrayList<>();
    
    private FruitAdapter adapter;
    
    initFruits();
    RecyclerView recyclerview = (RecyclerView) findViewById(R.id.recycler_view);
    GridLayoutManager layoutmanager = new GridLayoutManager(this, 2);
    recyclerview.setLayoutManager(layoutmanager);
    adapter = new FruitAdapter(fruitList);
    recyclerview.setAdapter(adapter);
    
    private void initFruits() {
        fruitList.clear();
        for (int i = 0; i < 50; i++) {
            Random random = new Random();
            int index = random.nextInt(fruits.length);
            fruitList.add(fruits[index]);
        }
    }
    

    10. AppBarLayout

    • CardView示例中RecyclerView遮挡住了Toolbar,因为它俩都在CoordinatorLayout中,而CoordinatorLayout是一个FrameLayout,所以造成了这个bug.
    • 解决方法:借助AppBarLayout:第一步将Toolbar嵌套到AppBarLayout中,第二步给RecyclerView指定一个布局行为。
    • 修改activity_main:
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <android.support.v7.widget.Toolbar
            app:layout_scrollFlags="scroll|enterAlways|snap"
            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" />
    </android.support.design.widget.AppBarLayout>
    
    <android.support.v7.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">
    </android.support.v7.widget.RecyclerView>
    
    说明:
    1.RecyclerView借助app:layout_behavior属性指定一个布局行为,目的是建立Toolbar和RecyclerView之间的关联。
    2.借助app:layout_behavior,Toolbar在接收到RecyclerView滚动事件的时候,会进行相应的操作。
    3.scroll表示Recy向上滚动的时候,Toolbar会跟着一起向上滚动并实现隐藏;enterAlwys表示Recy向下滚动的时候,Toolbar会跟着一起向下滚动并重新显示。snap表示当Toolbar还没有完全隐藏或显示的时候,会根据当前滚动的距离,自动选择是隐藏还是显示。
    

    11. SwipeRefreshLayout

    • 把想要实现下拉刷新功能的控件放置到SwipeRefreshLayout中,就可以迅速让这个控件支持下拉刷新。app:layout_behavior要放在SwipeRefreshLayout中。
    <android.support.v4.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">
    
                <android.support.v7.widget.RecyclerView
                    android:id="@+id/recycler_view"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
            </android.support.v4.widget.SwipeRefreshLayout>
    
    • 修改MainActiivty,处理刷新逻辑
    swiperefreshlayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
            swiperefreshlayout.setColorSchemeColors(getResources().getColor(R.color.colorPrimary));
            swiperefreshlayout.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();
                            swiperefreshlayout.setRefreshing(false);
                        }
                    });
    
                }
            }).start();
        }
    说明:
    1. setColorSchemeColors 处理下拉刷新的颜色。
    2. onRefresh处理具体的刷新逻辑。
    3. adapter.notifyDataSetChanged()通知页面刷新。
    4. setRefreshing隐藏下拉刷新。
    

    12. CollapsingToolbarLayout

    • 借助CollapsingToolbarLayout可根据自己的喜好随意定制出标题栏的样式,让Toolbar更加丰富,不仅仅是展示一个标题栏,而是能够实现非常华丽的效果。
    • CollapsingToolbarLayout不能独立存在,它在设计的时候就被限定只能作为AppBarLayout的直接子布局来使用。而AppBarLayout又必须是CoordinatorLayout的子布局。
    • activity_fruit.xml 标题栏部分:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.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:orientation="vertical">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appBar"
            android:layout_width="match_parent"
            android:layout_height="250dp">
    
            <android.support.design.widget.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" />
    
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"></android.support.v7.widget.Toolbar>
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>
    </android.support.design.widget.CoordinatorLayout>
    
    说明:
    1. ThemeOverlay.AppCompat.Dark.ActionBar是一个深色的主题,保证字体颜色是浅色系。
    2. contentScrim用于指定趋于折叠状态以及折叠以后的背景色。CollapsingToolbarLayout折叠之后就是一个普通的Toolbar,背景色是colorPrimary.
    3. layout_scrollFlags:scroll表示CollapsingToolbarLayout会随着水果内容详情的滚动一起滚动,exitUntilCollapsed表示当CollapsingToolbarLayout随着滚动完成折叠之后就保留在界面上,不再移出屏幕。
    4. 高级版的标题栏是由普通的标题栏加上图片组合而成的。
    5. layout_collapseMode 用于指定CollapsingToolbarLayout折叠过程中的折叠模式,其中Toolbar指定成pin,表示在折叠的过程中位置始终不变,ImageView指定成parallax,表示在折叠过程中产生一定的错误偏移。
    
    • activity_main 水果内容详情部分:
     <android.support.v4.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">
    
                <android.support.v7.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" />
                </android.support.v7.widget.CardView>
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    
    说明:
    1. NestedScrollView除了具有ScrollView的功能之外,还具有嵌套响应滚动事件的功能,并且指定了布局行为,向CoodinatorLayout传递滚动事件。
    2. NestedScrollView只能有一个子布局,我们添加一个LinearLayout,里面是一个卡片式布局,布局里面是一个TextView,显示水果的内容详情。
    
    • 添加FloatingActionButton:
    <android.support.design.widget.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" />
    说明:
    1. FloatingActionButton和AppBarLayout以及NestedScrollView是平级的。
    2. layout_anchor指定一个锚点,将锚点设置为AppBarLayout,这样悬浮按钮就会出现在水果标题栏的区域内。
    3. layout_anchorGravity将悬浮按钮定位在标题栏区域的右下角。
    
    • FruitActivity:
    public class FruitActivity extends AppCompatActivity {
        private static final String FRUIT_NAME = "fruit_name";
        private static final String FRUIT_IMAGE_ID = "fruit_image_id";
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_fruit);
    
            Intent intent = getIntent();
            String fruitName = intent.getStringExtra(FRUIT_NAME);
            int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
            ImageView fruitImageView = (ImageView) findViewById(R.id.fruit_image_view);
            TextView fruitContentText = (TextView) findViewById(R.id.fruit_content_text);
            setSupportActionBar(toolbar);
            ActionBar actionbar = getSupportActionBar();
            if (actionbar != null) {
                actionbar.setDisplayHomeAsUpEnabled(true);
            }
            
            collapsingToolbar.setTitle(fruitName);
            Glide.with(this).load(fruitImageId).into(fruitImageView);
            String fruitContext = generateFruitContext(fruitName);
        }
    
        private String generateFruitContext(String fruitName) {
            StringBuilder fruitContent = new StringBuilder();
            for (int i = 0; i < 500; i++) {
                fruitContent.append(fruitName);
            }
            return fruitContent.toString();
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case android.R.id.home:
                    finish();
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }
    
    说明:
    1. 通过intent获取传入的水果名称和水果图片的资源id,然后通过fv拿到布局文件中各个控件的实例。显示Toolbar,启用HomeAsUp按钮。
    2. collapsingToolbar的setTilte设置当前页面的标题;使用Glide加载传入的水果图片。 onOptionsItemSelected方法中处理了HOMEASUP按钮的点击事件。
    
    • 修改FruitAdapter,设置点击事件:
    @Override
        public FruitAdapter.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();
                    Log.e("FruitAdapter","position:"+position);
                    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;
        }
        
    说明:通过Intent传递数据启动FruitActivity。
    

    13. 充分利用系统状态栏空间

    • 借助android:fitsSystemWindows="true"这个属性实现背景图和状态栏的有效融合:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.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:fitsSystemWindows="true"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <android.support.design.widget.AppBarLayout
            android:fitsSystemWindows="true"
            android:id="@+id/appBar"
            android:layout_width="match_parent"
            android:layout_height="250dp">
    
            <android.support.design.widget.CollapsingToolbarLayout
                android:fitsSystemWindows="true"
                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:fitsSystemWindows="true"
                    android:id="@+id/fruit_image_view"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax" />
    说明:
    1. ImageView以及父类标签都要指定属性。
    
    • 指定状态栏颜色为透明色并且区分版本:
    1. 设置状态栏颜色为透明色是从Android 5.0系统开始才有的,之前的系统无法指定这个属性,所以需要区别对待。
    2. 创建values-v21目录,新建style.xml的resource file:
    <resources>
        <style name="FruitActivityTheme" parent="AppTheme">
            <item name="android:statusBarColor">@android:color/transparent</item>
        </style>
    </resources>
    
    说明:
    1.values-v21只有5.0才可以读取。
    2.FruitActivityTheme专门给FruitActivity使用,parent主题是AppTheme,也就是说它继承了AppTheme的所有特性。
    3.指定FruitActivityTheme为透明色。
    

    3.values-styles.xml指定FruitActivity的5.0之前的主题设置:

    <style name="FruitActivityTheme" parent="AppTheme"></style>
    
    说明:5.0之前无法指定状态栏的颜色,这里什么都不做即可。
    

    4.配置FruitActivity主题

    <activity android:name=".FruitActivity" android:theme="@style/FruitActivityTheme"></activity>
    

    相关文章

      网友评论

          本文标题:Android 5.0新特性之Material Design

          本文链接:https://www.haomeiwen.com/subject/wokarxtx.html