(收集转载总结)MD设计常用代码/尺寸/颜色/控件个人收集总结--控件部分

前言

作为Android 开发者,不仅要学习功能的实现,还需要定制用户的界面。如何制作一款符合大家审美的app是个根令人头疼的问题。
不过好在google在15发布了MD设计规范,帮助程序员设计更好的app。

MD概述

说明:本文参考资料极客学院 Material Design 中文版
翻译不是很可靠,也不及时。最好还是去谷歌查看原文。

我们挑战自我,为用户创造了崭新的视觉设计语言。与此同时,新的设计语言除了遵循经典设计定则,还汲取了最新的科技,秉承了创新的设计理念。这就是原质化设计(Material Design)
。这份文档是动态更新的,将会随着我们对 Material Design 的探索而不断迭代、升级。

目标

我们希冀创造一种新的视觉设计语言,能够遵循优秀设计的经典定则,同时还伴有创新理念和新的科技。
我们希望创造一种独一无二的底层系统,在这个系统的基础之上,构建跨平台和超越设备尺寸的统一体验。遵循基本的移动设计定则,同时支持触摸、语音、鼠标、键盘等输入方式。

设计原则

实体感就是(通过设计方式来表达)隐喻
通过构建系统化的动效和空间合理化利用,并将两个理念合二为一,构成了实体隐喻。与众不同的触感是实体的基础,这一灵感来自我们对纸墨的研究,但是我们相信,随着科技的进步,应用前景将不可估量。
实体的表面和边缘提供基于真实效果的视觉体验,熟悉的触感让用户可以快速地理解和认知。实体的多样性可以让我们呈现出更多反映真实世界的设计效果,但同时又绝不会脱离客观的物理规律。
光效、表面质感、运动感这三点是解释物体运动规律、交互方式、空间关系的关键。真实的光效可以解释物体之间的交合关系、空间关系,以及单个物体的运动。

鲜明、形象、深思熟虑

新的视觉语言,在基本元素的处理上,借鉴了传统的印刷设计——排版、网格、空间、比例、配色、图像使用——这些基础的平面设计规范。在这些设计基础上下功夫,不但可以愉悦用户,而且能够构建出视觉层级、视觉意义以及视觉聚焦。精心选择色彩、图像、选择合乎比例的字体、留白,力求构建出鲜明、形象的用户界面,让用户沉浸其中。
Material Design 设计语言强调根据用户行为凸显核心功能,进而为用户提供操作指引。

有意义的动画效果

动画效果(简称动效)可以有效地暗示、指引用户。动效的设计要根据用户行为而定,能够改变整体设计的触感。
动效应当在独立的场景呈现。通过动效,让物体的变化以更连续、更平滑的方式呈现给用户,让用户能够充分知晓所发生的变化。
动效应该是有意义的、合理的,动效的目的是为了吸引用户的注意力,以及维持整个系统的连续性体验。动效反馈需细腻、清爽。转场动效需高效、明晰。

所有的关于MD设计的有关规范都能在该文档里找到,下面我们跟随文档,看下一些符合MD设计的应用是如何做到简约大方的。

热门开源MD风格设计App

  1. 简影讯,简约精彩影讯。仓库地址
    (收集转载总结)MD设计常用代码/尺寸/颜色/控件个人收集总结--控件部分_第1张图片
  2. 就看天气——是一款遵循Material Design风格的只看天气的APP。仓库地址
    (收集转载总结)MD设计常用代码/尺寸/颜色/控件个人收集总结--控件部分_第2张图片

MD相关控件

参考文章:Android MD风格相关控件小结

CoordinatorLayout

CoordinatorLayout作为顶层布局,可以响应子布局的动作,调度协调子布局,形成优雅的动画效果。作为搭配主要有以下几种

CoordinatorLayout+AppBarLayout

CoordinatorLayout配合AppBarLayout 可以形成优雅的顶部导航条。配合ToolBar以及能让响应滑动事件的控件,可以形成根据滑动变化的顶部导航条。
能响应的滑动事件控件有:

  1. RecyclerView 控件
  2. NestedScrollView 里面的子控件

实例:一个常用的布局方式
CoordinatorLayout+AppBarLayout+ToolBar+TabLayout+ViewPager+RecyclerView

  1. CoordinatorLayout+AppBarLayout+ToolBar 制作响应的顶部导航
  2. TabLayout+ViewPager+RecyclerView 形成带Tab的ViewPager

布局文件:

主布局:



    

        
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:title="MdView" />

        

    

    
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    


fragment布局



    


配合CoordinatorLayout、AppBarLayout,我们实现了这样的效果,向上滚动列表时,Toolbar隐藏,TabLayout置顶,再向下滚动Toolbar则显示。
Toolbar之所以可以滚动隐藏\显示,是通过如下属性实现的:
app:layout_scrollFlags="scroll|enterAlways"

相关属性值解释如下

scroll:需要滚动出屏幕的view需要设置该flag, 没有设置则view将被固定在屏幕顶部。
enterAlways: 使用该flag,则向下的滚动会使view变为可见状态。

更多详情可参考文章玩转AppBarLayout,更酷炫的顶部栏

为Toolbar设置layout_scrollFlags属相只是第一步,还需要在CoordinatorLayout 中提供一个可滚动的View,我们使用ViewPager,并在里边嵌套RecyclerView。同时需要为ViewPager设置如下属性:app:layout_behavior="@string/appbar_scrolling_view_behavior"

其他有关代码:

 private void initContent() {
        mFragments = new ArrayList<>();
        mFragments.add(TypeFragment.newInstance("热点"));
        mFragments.add(TypeFragment.newInstance("军事"));
        mFragments.add(TypeFragment.newInstance("科技"));
        mFragments.add(TypeFragment.newInstance("娱乐"));

        mTitles = new ArrayList<>();
        mTitles.add("热点");
        mTitles.add("军事");
        mTitles.add("科技");
        mTitles.add("娱乐");

        TabPagerAdapter adapter = new TabPagerAdapter(getSupportFragmentManager());
        adapter.setArguments(mFragments, mTitles);
        mViewPager.setAdapter(adapter);

        //设置TabLayout可滚动,保证Tab数量过多时也可正常显示
        mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
        //两个参数分别对应Tab未选中的文字颜色和选中的文字颜色
        mTabLayout.setTabTextColors(Color.WHITE, Color.RED);
        //绑定ViewPager
        mTabLayout.setupWithViewPager(mViewPager);
        //设置TabLayout的布局方式(GRAVITY_FILL、GRAVITY_CENTER)
        mTabLayout.setTabMode(TabLayout.MODE_FIXED);
        mTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        //设置TabLayout的选择监听
        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                mViewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            //重复点击时回调
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                scrollToTop(mFragments.get(tab.getPosition()).getTypeList());
            }
        });
    }

    /**
     * 滚动到列表顶部
     *
     * @param recyclerView
     */
    private void scrollToTop(RecyclerView recyclerView) {
        StaggeredGridLayoutManager manager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
        int[] lastPositions = manager.findLastVisibleItemPositions(null);
        if (lastPositions[0] < 15) {
            recyclerView.smoothScrollToPosition(0);
        } else {
            recyclerView.scrollToPosition(0);
        }
    }

 public class TabPagerAdapter extends FragmentPagerAdapter {
        private List fragments;
        private List titles;

        public TabPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        public void setArguments(List fragments, List titles) {
            this.fragments = fragments;
            this.titles = titles;
        }

        @Override
        public Fragment getItem(int position) {
            return fragments.get(position);
        }

        @Override
        public int getCount() {
            return fragments.size();
        }

        //返回TabLayout对应Tab的标题
        @Override
        public CharSequence getPageTitle(int position) {
            return titles.get(position);
        }
    }

RecyclerView的Adapter

public class TypeListAdapter extends RecyclerView.Adapter {

    private ArrayList mDatas;
    private List mHeights;
    private OnItemClickListener mListner;

    public TypeListAdapter(ArrayList datas) {
        if (datas != null) {
            mDatas = datas;
        } else {
            mDatas = new ArrayList<>();
        }
        mHeights = new ArrayList<>();
        for (int i = 0; i < mDatas.size(); i++) {
            mHeights.add((int) (260 + Math.random() * 100));
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        ViewGroup.LayoutParams params = holder.itemTv.getLayoutParams();
        params.height = mHeights.get(position);
        holder.itemTv.setLayoutParams(params);
        holder.itemTv.setText(mDatas.get(position));
        if (mListner != null) {
            holder.itemLayout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mListner.onItemClick(mDatas.get(position), position);
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return mDatas.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.item_tv)
        TextView itemTv;
        @BindView(R.id.item_layout)
        View itemLayout;

        public ViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        mListner = listener;
    }

    public interface OnItemClickListener {
        void onItemClick(String data, int position);
    }
}

效果:

CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout

关于CollapsingToolbarLayout的说明

CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout_scrollFlags,它可以控制包含在CollapsingToolbarLayout中的控件(如:ImageView、Toolbar)在响应layout_behavior事件时作出相应的scrollFlags滚动事件(移除屏幕或固定在屏幕顶端)。

所以我们尝试加一个ImageView在里面试试,同时添加
app:layout_scrollFlags="scroll|exitUntilCollapsed"

再加一个响应滑动的控件,除了RecyclerView还有一个NestedScrollView控件同理加上app:layout_behavior="@string/appbar_scrolling_view_behavior"

布局文件:




    

        
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7" />

            
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        
    

    

        

    

    



可以看到:
CollapsingToolbarLayout添加了两个子控件,由于CollapsingToolbarLayout本质是一个Fragmentlayout,所以层叠显示。同时设置ToolBar背景透明。

关于返回箭头:

//使mToolbar取代原来的ActionBar
        setSupportActionBar(mToolbar);
        //设置mToolbar左上角显示返回图标
        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
        //设置返回图标的点击事件
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

其他代码

 //设置还没收缩时状态下字体颜色
        mToolbarLayout.setExpandedTitleColor(Color.RED);
        //设置收缩后Toolbar上字体的颜色
        mToolbarLayout.setCollapsedTitleTextColor(Color.WHITE);
        //设置image背景
        mDetailImg.setBackgroundResource(R.mipmap.bg);

        mWebView.loadUrl("http://www.jianshu.com/");
        mWebView.setWebChromeClient(new WebChromeClient() {

            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);
                //必须把title设置到CollapsingToolbarLayout上,设置到Toolbar上则不会显示
                mToolbarLayout.setTitle(title);
            }
        });

结合CollapsingToolbarLayout,我们向上滑动时ImageView隐藏、Toolbar显示,向下滑动则反之,类似折叠展开的效果。

在CollapsingToolbarLayout中通过app:contentScrim="?attr/colorPrimary"属相设置Toolbar折叠到顶部的背景,同时设置了app:layout_scrollFlags="scroll|exitUntilCollapsed"属相,其中scroll的=含义已经解释过了,exitUntilCollapsed的含义如下:

exitUntilCollapsed: 滚动退出屏幕,最后折叠在顶端

同时AppBarLayout的高度需要时第一个固定值,这样CollapsingToolbarLayout就有了折叠的效果。

折叠后Toolbar可以固定在顶部是因为使用了app:layout_collapseMode="pin"属性,属性值除了pin还有一个parallax:

pin:固定模式,在折叠的时候最后固定在顶端
parallax:视差模式,在折叠时会有个视差折叠的效果

同时在ImageView中使用了app:layout_collapseMode="parallax"属性,来产生视差渐变的效果,使用app:layout_collapseParallaxMultiplier="0.7"可以控制视差的变化,属性值的范围是[0.0, 1.0],值越大视察越大。

最后还需要在NestedScrollView中设置app:layout_behavior="@string/appbar_scrolling_view_behavior属性。

CoordinatorLayout+FloatingActionButton

这个很简单,只要加入了FloatingActionButton即可响应



    

        ........................................
    


代码

mFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(mCoordinatorLayout, "点我分享哦!", Snackbar.LENGTH_SHORT).show();
            }
        });

在Snackbar展示的时候FloatingActionButton上移,隐藏时下移。如果FloatingActionButton的父View是RelativeLayout或其它Container则FloatingActionButton不会上移而导致被Snackbar覆盖。

要做到我们上滑时FloatingActionButton会折叠消失,其实只需要如下两个属性就可以

app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|end"

第一个属性使FloatingActionButton显示在AppBarLayout的区域,
第二个属性确定显示的具体位置。




    

      .............................
    

    .........................
    
        app:layout_anchor="@id/app_bar"
        app:layout_anchorGravity="bottom|end" />



用来替换yuanlaide

Toolbar

ToolBar的出现是为了替换之前的ActionBar的各种不灵活使用方式,相反,ToolBar的使用变得非常灵活,因为它可以让我们自由往里面添加子控件。我们可以单独的使用也可以代替原来的ActionBar。

替换ActionBar

  1. 使用Toolbar首先要隐藏原有的ActionBar,我们可以增加一个主题

也可以扩展原有的主题,


colorPrimary:对应ActionBar的颜色。
colorPrimaryDark:对应状态栏的颜色
colorAccent:对应EditText编辑时、FloatingActionButton背景等颜色。

配置文件修改:Android:theme=”@style/AppTheme”

  1. 在布局文件中的用法可以参考上边的代码,之后在java代码中得到Toolbar,通过setSupportActionBar(mToolbar);使Toolbar取代原本的ActionBar。

相关属性


        
        

?attr/actionBarSize:表示根据屏幕的分辨率采用系统默认的高度

关于图标以及其他设置:参考图片对应方法


(收集转载总结)MD设计常用代码/尺寸/颜色/控件个人收集总结--控件部分_第3张图片
 mToolbar = (Toolbar) findViewById(R.id.toolbar);
        // App Logo
//        mToolbar.setLogo(R.drawable.app_icon);
        // 主标题,默认为app_label的名字
        mToolbar.setTitle("Title");
        mToolbar.setTitleTextColor(Color.YELLOW);
        // 副标题
        mToolbar.setSubtitle("Sub title");
        mToolbar.setSubtitleTextColor(Color.parseColor("#80ff0000"));
        //侧边栏的按钮
        mToolbar.setNavigationIcon(R.drawable.back);
        //取代原本的actionbar
        setSupportActionBar(mToolbar);
        //设置NavigationIcon的点击事件,需要放在setSupportActionBar之后设置才会生效,
        //因为setSupportActionBar里面也会setNavigationOnClickListener
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mToast.setText("click NavigationIcon");
                mToast.show();
            }
        });
        //设置toolBar上的MenuItem点击事件
        mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_edit:
                        mToast.setText("click edit");
                        break;
                    case R.id.action_share:
                        mToast.setText("click share");
                        break;
                    case R.id.action_overflow:
                        //弹出自定义overflow
                        popUpMyOverflow();
                        return true;
                }
                mToast.show();
                return true;
            }
        });
        //ToolBar里面还可以包含子控件
        mToolbar.findViewById(R.id.btn_diy).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mToast.setText("点击自定义按钮");
                mToast.show();
            }
        });
        mToolbar.findViewById(R.id.tv_title).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mToast.setText("点击自定义标题");
                mToast.show();
            }
        });

设置menu,以及item点击事件

//如果有Menu,创建完后,系统会自动添加到ToolBar上
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

 @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case R.id.menu_share:
                break;
            case R.id.menu_search:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

NavigationView

NavigationView的就是抽屉,是隐藏在界面外的一个布局。
在MD设计规范里,主要的东西应该是显眼的,用户直达的。所以NavigationView只能放一些次要的东西。比如说明、设置等等

布局文件

其实NavigationView就是用来实现我们常见的侧滑菜单的效果的。
在布局文件中的代码:




    

    


以DrawerLayout作为根布局,content_main作为主界面布局,最后是NavigationView,
通过android:layout_gravity="start"设置为左侧滑菜单,
同理android:layout_gravity="end"代表右侧滑菜单。
其中

app:menu="@menu/menu_drawer"
app:headerLayout="@layout/nav_head_main"

两个属性分别代表NavigationView的顶部header布局以及下边的menu item布局,具体可以参考源代码。
nav_head_main.xml




    

    


menu_drawer.xml




    
        
        
    

    
        
            
            
            
        
    

代码

准备好了布局文件,接下来就是初始化工作:

private void initNavigationView() {
        //初始化NavigationView顶部head的icon和name
        ImageView icon = (ImageView) mNavView.getHeaderView(0).findViewById(R.id.nav_head_icon);
        icon.setImageResource(R.mipmap.ic_launcher);
        TextView name = (TextView) mNavView.getHeaderView(0).findViewById(R.id.nav_head_name);
        name.setText("VipOthershe");
        //设置NavigationView对应menu item的点击事情
        mNavView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.nav_item1:
                        break;
                    case R.id.nav_item2:
                        break;
                    case R.id.nav_set:
                        break;
                    case R.id.menu_share:
                        break;
                    case R.id.nav_about:
                        break;
                }
                //隐藏NavigationView
                mDrawerLayout.closeDrawer(GravityCompat.START);
                return true;
            }
        });
    }

很简单,就是初始化NavigationView的顶部header和Menu Item。

接下来看一下如何将右滑菜单和Toolbar结合使用:

ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, mDrawerLayout, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        mDrawerLayout.addDrawerListener(toggle);
        //设置左上角显示三道横线
        toggle.syncState();

通过设置将两者绑定在一起,同时Toolbar左上角显示三道横线,左上角可打开左滑菜单。

还可以采用另外一种方式:

 //设置Toolbar左上角图标
        mToolbar.setNavigationIcon(R.mipmap.ic_launcher);
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mDrawerLayout.openDrawer(GravityCompat.START);
            }
        });

先设置Toolbar左上角图标,并绑定事件,通过mDrawerLayout.openDrawer(GravityCompat.START);打开左滑菜单。

以上两个方法,分别对应打开和关闭左滑菜单:

mDrawerLayout.openDrawer(GravityCompat.START);
mDrawerLayout.closeDrawer(GravityCompat.START);

如果使用右滑菜单则将GravityCompat.START改成GravityCompat.END,即可实现右滑菜单的开关。

效果图

侧滑菜单

你可能感兴趣的:((收集转载总结)MD设计常用代码/尺寸/颜色/控件个人收集总结--控件部分)