zoukankan      html  css  js  c++  java
  • Material Design & Android 5

    最近研究了一下Material Design和Android 5的新特性,这里做下总结归纳。

    Material Design在我认为就是类似于卡片一样的设计,当然并不只是卡片,material design可以把一个布局或者控件当做实际生活中得一个卡片来对待。

    那么具有以下几个方面的属性(具体参照 http://www.google.com/design/spec/material-design/introduction.html 上面某些效果看起来还是挺炫的):

    1. 物理属性——卡片是三维的,在z坐标上只有1dp厚;具有投影,不同高度的投影效果不一样;任何颜色、形状和内容都可以在material上显示且不增加厚度;卡片之间不能相互重叠,相互穿过,阻塞点击触摸事件。
    2. 变换属性——可以改变形状、合并、拆分然后合并,但不可以弯曲和折叠。
    3. 运动属性——可以自然的被创建或者销毁,可以任意移动,用户与material的交互一般通过z轴变化和波纹动画展示

    同时material design定义了许多了规范,是经过google产品设计工程师用心总结起来,总体看起来体验蛮炫。具体效果可以参照chrome的新书签,感觉比以前高大上许多。在手机设备上也定义了一些规范,这里只总结个人较为关注和在手机上比较好实现的一些规范。

      布局:layout一般内容距离边界边距为16dp

      可触摸控件:大小一般为48*48dp,实际内容为40*40或者24*24dp

       imageView可以通过设置padding来实现或者让设计截图留好padding

      类似按钮这样的可触摸控件一般可触摸高度为48dp,实际高度为36dp

      那么在安卓内该如何实现这样的按钮?

      It's big problem,这里想到了两种方式,但没有完全实现:

    1. 通过自定义背景来设置,
    2. 调用父类View中得setTouchDelegate方法来扩大button的可触摸范围,但一个父类只能设置一个TouchDelegate,当有多个button要实现这样的可触摸范围时,可以考虑继承默认的TouchDelegate类,内部自己定义多个可点击范围来实现对多个button的委托访问。
    3. 听之任之……

    material design定义了button控件有三种模式,如下图:

    分别为:

    1. Floating action button——官方无实现,我在目前开发设计业没有用到过如果需要使用可以参照github:https://github.com/futuresimple/android-floating-action-button
    2. Raised button——普通的button,5以上通过使用material相关主题实现波纹和阴影效果;5以下不推荐实现波纹效果,Chris Banes回复说“Ripples are highly dependent on Lollipop's new RenderThread for performance. As devices before that do not have RT, the performance will be bad.”5以下建议使用Appcompat theme,需要阴影需要自己设置阴影或者使用对应的效果图。
    3. Flat button——1、设置stateListAnimator,elevation,translationZ为0;2、api在11以上设置background为?android:attr/selectableItemBackground(按钮默认颜色为透明);

    这三种按钮建议使用频率是 flat button>raised button>floating action button,主要是为了避免过多的层叠

    后面还列出一些其他material design列出的规范:

    Dividers——1dp thick,opacity 12% black or 12% white

    Snackbars & toasts 

    Single-line snackbar height: 48dp

    Multi-line snackbar height: 80dp

    Text: Roboto Regular 14sp

    Action button: Roboto Medium 14sp, all-caps text

    Default background fill: #323232 100%

     

    Android 5关于material design实现

    以上内容是关于对于material design的一个简单介绍和个人归纳,很多具体规范可以参照官方material design手册,设计应该比码农要关注更多吧,读完可是要费蛮多功夫的。后面的内容是个人使用Android对material design的实现,其中有一部分摘自于网络内容,尤其是图片,算我盗版呗。

    首先,Android 5提供了material theme实现了大多数的控件的样式,但是个人推荐使用Appcompat包得Theme.AppCompat,其实际上就是继承了material theme,并实现了对5下部分控件的兼容,material design有以下主题可以选择:

    Theme.Material (dark version)

    Theme.Material.Light (light version)

    Theme.Material.Light.DarkActionBar

    Theme.AppCompat

    Theme.AppCompat.Light

    Theme.AppCompat.Light.NoActionBar

    Theme.AppCompat.NoActionBar

    其次,要配置调色板,一般可以配置的颜色如图所示:

    其代码大概可以是

    <resources>
      <style name="AppTheme" parent="android:Theme.Material">
        <item name="android:colorPrimary">@color/primary</item>
        <item name="android:colorPrimaryDark">@color/primary_dark</item>
        <item name="android:colorAccent">@color/accent</item>
      </style>
    </resources>

    这部分具体在我的demo中如下:

    <style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- 主要文字颜色 -->
            <item name="android:textColorPrimary">#ffaa66cc</item>
    
            <!-- 窗口的背景颜色 -->
            <!--<item name="android:windowBackground">@android:color/white</item>-->
    
            <!-- 默认switch颜色 -->
            <item name="colorSwitchThumbNormal">#ffcc0000</item>
            <item name="colorControlActivated">#ff669900</item>
            <item name="toolbarStyle">@style/MyToolBar</item>
            <item name="switchStyle">@style/MySwitch</item>
            <item name="searchViewStyle">@style/MySearchViewStyle</item>
        </style>
    
        <style name="AppTheme" parent="@style/AppBaseTheme"/>
    MyAppTheme
     <application
            android:name=".common.MyApplication"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
            ...    
    AndroidManifest.xml--begin

    其中涉及到material design提到的三种组件:

    System bar(Status bar) ——即android手机显示电量,时间等状态的系统转太烂;height:24p ,color:一般暗色,也可以设计为应用的一种元素色或者半透明

    Android navigation bar —— android的导航栏,这里指左右导航栏,其实安卓手机底部的有返回键、home键的这一栏也称为navigation bar,在屏幕上的时虚拟导航栏,是在手机硬件上得称为硬件导航栏;height:48p,color:同status bar侧边导航;推荐:左导航右是当前页的二级内容 width=Screen width - 56dp;最大width:左320dp,右:全屏

    Tools bar -> App bar (Action bar),即系统状态栏下应用的标题栏,过去是action bar,现在一般用toolbar;横屏48dp 竖屏最小56dp,菜单栏一般是一个薄纸片,而不是bar的一个扩展

     这里关于系统的状态栏和底部导航栏有些配置,介绍如下:

    隐藏StatusBar——1、style定义android:windowFullScreen为true;2、getWindow().addFlags(WindowManager.LayoutParams.FLAY_FULLSCREEN);3、View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREENSYSTEM_UI_FLAG)

    隐藏NavigationBar(API 14)——view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

    设置颜色(API 21)——getWindow().setStatusBarColor(…);getWindow().setNavigationBarColor();

    设置透明(API 14)

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)

    可以通过View的一些常量来改变屏幕的一些特性(View.setSystemUiVisibility(UiOptions)(API 11)),具体如下(隐藏系统栏和低能模式会在有app bar时失效):

    SYSTEM_UI_FLAG_FULLSCREEN   全屏隐藏系统状态栏 (lean back)模式

    SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN   全屏但是不隐藏系统状态栏

    SYSTEM_UI_FLAG_HIDE_NAVIGATION 全屏并隐藏导航栏

    SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 全屏不隐藏导航栏

    SYSTEM_UI_FLAG_LOW_PROFILE 低能状态

    SYSTEM_UI_FLAG_LAYOUT_STABLE 保持状态栏和导航栏布局稳定,类似于invisible

    SYSTEM_UI_FLAG_IMMERSIVE immersive 模式

    SYSTEM_UI_FLAG_IMMERSIVE_STICKY  不清除flag的immersive模式,过一段时间隐藏的系统栏和导航栏会再次自动隐藏

     具体效果参照demo的StatusBarActivity。

    Ripple效果(波纹效果)

    1. 其他控件可以设置背景为?android:attr/selectableItemBackground(API 11)或者?android:attr/selectableItemBackgroundBorderless(API 21),点击触摸颜色可以通过android:colorControlHighlight(API 21)来设置
    2. 使用ViewAnimationUtils.createCircularReveal来实现
    3. 新建一个RippleDrawable资源,赋值给backgroud。
    <ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@android:color/holo_red_dark"><item
        android:drawable="@android:color/holo_green_dark"/></ripple>`
    ripple drawable

    兼容的使用Android 5.0新特性

    • 使用AppCompat-v7包和Theme.Appcompat主题,提供了以下控件的兼容性,(极力推荐,对于不满意的地方只要去修改style就好了):

    Everything provided by AppCompat’s toolbar (action modes, etc)

    EditText

    Spinner

    CheckBox

    RadioButton

    SwitchCompat

    CheckedTextView

    • 定义不同的styles,这种方式还好,可以同时继承一个低版本的父类style,然后不同机型实现不同效果

         res/values/styles.xml.

      

    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
            <item name="windowActionBar">false</item>
            <item name="windowNoTitle">true</item>
            <!-- 主要文字颜色 -->
            <item name="android:textColorPrimary">#ffaa66cc</item>
            <item name="android:textColorHighlight">@color/abc_primary_text_material_dark</item>
    
            <item name="colorPrimaryDark">#ffaa66cc</item>
            <item name="colorPrimary">#ffaa66cc</item>
            <item name="colorAccent">?attr/colorAccent</item>
            <!-- 窗口的背景颜色 -->
            <!--<item name="android:windowBackground">@android:color/white</item>-->
    
            <!-- 默认switch颜色 -->
            <item name="colorSwitchThumbNormal">#ffcc0000</item>
            <item name="colorControlActivated">#ff669900</item>
            <item name="toolbarStyle">@style/MyToolBar</item>
            <item name="switchStyle">@style/MySwitch</item>
            <item name="searchViewStyle">@style/MySearchViewStyle</item>
            <item name="editTextStyle">@style/Widget.AppCompat.EditText</item>
            <item name="buttonStyle">@style/MyButton</item>
            <item name="dialogTheme">@style/Theme.AppCompat.Light.Dialog</item>
        </style>
    style

         res/values-v21/styles.xml.

    <resources xmlns:android="http://schemas.android.com/apk/res/android">
    
        <style name="AppTheme" parent="@style/AppBaseTheme">
            <!-- 系统状态栏 颜色-->
            <item name="android:colorPrimaryDark">@android:color/holo_green_dark</item>
            <!-- 底部导航栏颜色 -->
            <item name="android:navigationBarColor">@android:color/holo_purple</item>
    
            <item name="android:colorAccent">?attr/colorAccent</item>
            <!-- 触摸颜色,包括button ripple 背景-->
            <item name="android:colorControlHighlight">@android:color/holo_red_dark</item>
        </style>
    
    
    </resources>
    style-v21
    • 定义不同的布局,如果真的是布局会有不同,感觉大事不妙,在现在的技术基础上,只要是两份相同的布局文件便会遇到维护性难的问题,所以最好还是保持一致性,如果某些新特性需要修改的话还是建议使用代码来实现,可以采取工厂模式实现不同版本特性的抽离:

         res/layout/my_activity.xml 

         res/layout-v21/my_activity.xml

      

    Android 5新控件

    RecyclerView

    RecyclerView是官方首先推出来的一个大控件,官方希望关于展示集合类型的数据均用Recyclerview来实现,可以用来替代listview和gridview;他对比listview和gridview有以下特点

    • 抽象出了viewholder来缓存view,recyclerview直接管理的时viewholder,不再是view
    • 对比listview,gridview,它更高效,拥有更大的灵活性,方便的使用不同类型的数据,提供辅助类配置动画
    • 但是需要写更多的代码,没有默认的adapter提供,除了scroll监听不提供其他监听
    • 通过Adapter的细粒度的封装使得效率提高,譬如增、删、改某个元素或者某个范围的元素通过调用notifyItemChanged(int position)、notifyItemInserted(int position)、notifyItemMoved(int fromPosition, int toPosition)、notifyItemRangeChanged(int positionStart, int itemCount)等方法实现,不再像listview必须一次性通知更改全部集合元素。

     简单使用:

    StaggeredGridLayoutManager指布局按照瀑布流模式来排列布局
     1 private void initRecycler() {
     2         // use this setting to improve performance if you know that changes
     3 
     4         RecyclerView.LayoutManager layoutManager = new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL);
     5         RecyclerView.LayoutManager layoutManager1 = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
     6         RecyclerView.LayoutManager layoutManager2 = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
     7         RecyclerView.LayoutManager layoutManager3 = new GridLayoutManager(this, 3);
     8         mRecyclerView.setLayoutManager(layoutManager);
     9         mRecyclerView.setAdapter(new Adapter(Arrays.asList("button & background", "status bar & nav bar",
    10                 "cardView & ripple", "toolbar", "switchCompat", "exit", "add1", "add2")));
    11         // in content do not change the layout size of the RecyclerView
    12         mRecyclerView.setHasFixedSize(false);
    13     }
    recyclerView init
      1 private class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {
      2         private List<String> list;
      3         private OnItemClickListener listener;
      4 
      5         public Adapter(List<String> list) {
      6             super();
      7             this.list = new ArrayList<>(list);
      8             listener = new OnItemClickListener() {
      9                 @Override
     10                 public void onItemClick(View v, int layoutPosition) {
     11                     onClick(v);
     12                 }
     13             };
     14         }
     15 
     16         @Override
     17         public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     18             Context context = parent.getContext();
     19             if (viewType == 1) {
     20                 ImageView imageView = new ImageView(context);
     21                 imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 150));
     22                 return new MyViewHolder(new ImageView(context));
     23             }
     24             Button btn = new Button(context);
     25             btn.setMinHeight((int) (context.getResources().getDisplayMetrics().density * (36 + random.nextInt(36) + 0.5f)));
     26             return new MyViewHolder(btn);
     27         }
     28 
     29         @Override
     30         public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
     31             if (position != getItemCount() - 1) {
     32                 ((Button) holder.itemView).setText(list.get(position));
     33             } else {
     34                 ((ImageView) holder.itemView).setImageResource(R.mipmap.ic_launcher);
     35             }
     36         }
     37 
     38         @Override
     39         public int getItemViewType(int position) {
     40             if (position == getItemCount() - 1) {
     41                 return 1;
     42             }
     43             return super.getItemViewType(position);
     44         }
     45 
     46         @Override
     47         public int getItemCount() {
     48             return list == null ? 0 : list.size() + 1;
     49         }
     50 
     51         public void add(int position, String str) {
     52             list.add(position, str);
     53             notifyItemInserted(position);
     54         }
     55 
     56         public void delete(int position) {
     57             list.remove(position);
     58             notifyItemRemoved(position);
     59         }
     60 
     61         @Override
     62         public void onClick(View v) {
     63             int index;
     64             switch ((String) v.getTag()) {
     65             case "button & background":
     66                 if (Utils.hasLollipop()) {
     67                     getWindow().setExitTransition(new Fade());
     68                 }
     69 
     70                 startActivity(
     71                         new Intent(HomeActivity.this, ButtonActivity.class),
     72                         ActivityOptions.makeCustomAnimation(HomeActivity.this, android.R.anim.fade_in,
     73                                 android.R.anim.slide_out_right).toBundle());
     74                 break;
     75             case "status bar & nav bar":
     76                 startActivity(new Intent(HomeActivity.this, StatusBarActivity.class));
     77                 break;
     78             case "cardView & ripple":
     79                 startActivity(new Intent(HomeActivity.this, CardViewActivity.class));
     80                 break;
     81             case "toolbar":
     82                 startActivity(new Intent(HomeActivity.this, ToolBarActivity.class));
     83                 break;
     84             case "switchCompat":
     85                 startActivity(new Intent(HomeActivity.this, SwitchActivity.class));
     86                 break;
     87             case "exit":
     88                 exit();
     89                 break;
     90             case "delete 1":
     91                 delete(list.indexOf("delete 1"));
     92                 break;
     93             case "delete 2":
     94                 delete(list.indexOf("delete 2"));
     95                 break;
     96             case "add1":
     97                 index = list.indexOf("delete 1");
     98                 if (index < 0) {
     99                     add(list.indexOf("add1"), "delete 1");
    100                 }
    101                 break;
    102             case "add2":
    103                 index = list.indexOf("delete 2");
    104                 if (index < 0) {
    105                     add(list.indexOf("add1"), "delete 2");
    106                 }
    107                 break;
    108             }
    109         }
    110 
    111         private class MyViewHolder extends RecyclerView.ViewHolder {
    112             public MyViewHolder(View itemView) {
    113                 super(itemView);
    114 
    115                 if (listener != null) {
    116                     itemView.setOnClickListener(new View.OnClickListener() {
    117                         @Override
    118                         public void onClick(View v) {
    119                             if (v.getTag() == null) {
    120                                 v.setTag(list.get(getLayoutPosition()));
    121                             }
    122                             listener.onItemClick(v, getLayoutPosition());
    123                         }
    124                     });
    125                 }
    126             }
    127 
    128             @Override
    129             public String toString() {
    130                 return super.toString();
    131             }
    132         }
    133     }
    定义Adapter

    其中,onCreateViewHolder方法用来创建对应的Viewholder,onBindViewHolder用来指定当viewholder被绑定时该做什么操作,getItemViewType方法指定数据类型,好生成不同类型的View。

    PS:

    Recyclerview内部定义的position有两种position,他们在大多时候相同,仅在某些情况下不一致,如下:

    • layout position: 指的是你所能看到的item的position.
    • adapter position: item在adapter的position,只在调用adapter.notify*时会不同(两者大概差16ms),获取该position的方法可能会返回NO_POSITION或者null.

    CardView

    官方上说list大多数情况是瓷砖,四角方方正正,但cardview是真的卡片。那么CardView在android的实现其实可以设置圆角自带阴影的FrameLayout,适用情况:文字内容在三行以上,一个布局有两个以上的动作事件;其他情况请酌情考虑使用list,不要滥用。以下是几个要点:

    • cardView在5以下使用了padding来绘制阴影,所以cardview的padding在5以下无效,建议使用setContentPadding(int, int, int, int) 来设置内容和边界的padding
    • 如果给cardview指定了准确的大小,那么cardview在5以前和5以后的版本会有一些差别,可以通过兼容的resource来解决该差异,也可以通过setUseCompatPadding(true)来设置5以后的cardview也使用内部padding来解决该差异
    • 通过设置 setCardElevation(float)来改变海拔高度,同时改变阴影大小;只改变阴影大小,不改变z坐标使用 setMaxCardElevation(float)

    Palette

    palette是官方给的一个新API,可以从一个图片抽取6种不同元素的颜色,这个API使得android的界面可以显得更加富有变化和活泼,比如在一个listview中,抽取每个item的图片来作为这个item的标题栏,来区分这个item和其他item的颜色分类;或者抽从app的一个主要图片抽取颜色赋予到status bar等等。

    官方的这个类只提供了6种颜色,其实也是提取某些范围的颜色值,提取出来的颜色是完全不透明的。具体用法如下:

     1 build = Palette.from(((BitmapDrawable) getResources().getDrawable(R.mipmap.ic_launcher)).getBitmap())
     2                 .maximumColorCount(16).resizeBitmapSize(192);
     3 build.generate(new Palette.PaletteAsyncListener() {
     4                 @Override
     5                 public void onGenerated(Palette palette) {
     6                     Palette.Swatch swatch = palette.getVibrantSwatch();
     7                     int tc = swatch.getTitleTextColor(), bc = swatch.getBodyTextColor();
     8                     if (Utils.hasLollipop()) {
     9                         getWindow().setStatusBarColor(swatch.getRgb());
    10                     }
    11                 }
    12             });

    PS:建议使用22.1以上的support包,效率会提升5倍以上

    AppCompatActivity & Toolbar

    AppCompatActivity用来代替ActionBarActivity,提供在安卓所有版本一致性的App bar,即Toolbar。AppCompatActivity要求使用Theme.AppCompact主题或者该主题的子类。以后建议使用AppCompatActivity来当做所有activity的父类。

    那么现在有个问题,我们为什么要使用toolbar,我个人总结了以下三点原因:

    1. google推material design,toolbar作为一个重点来推,他们认为这样的设计是一个好的设计
    2. toolbar提供了之前actionbar几乎所有的功能(有些被废弃但依然很强大),有利于保持设计的一致性,并且保持了灵活性和扩展性
    3. toolbar是个类似于RelativeLayout的viewgroup,子view支持layout_gravity属性,可以自由扩展;以前需要费劲的扩展actionbar的瓶颈已经不复存在,你想怎么扩展就怎么扩展!

    那么ToolBar默认提供了哪些强大的功能:

    1. 和DrawerLayout良好配合实现“抽屉”导航栏
    2. 提供可折叠的视图(CollapsibleActionView),官方已提供searchview的实现。
    3. 提供了action provider,可以展示一个子菜单,官方提供了ShareActionProvider,MediaRouteActionProvider

    以下三张图分别展示了这三个功能,具体示例和实现可以参照demo

     

     

    toolbar默认元素图如下:

    如果希望toolbar充当如图系统中的app bar,那么需要在OnCreate中调用setSupportActionBar(toolbar),这时toolbar即成为系统的app bar,拥有action bar绝大多数功能。

    设置NavigationIcon,需在setSupportActionBar后调用toolbar.setNavigationIcon;

    设置Logo,主标题和副标题调用setLogo、setTitle、setSubTitle即可。如果不希望显示toolbar自带的标题,那么可以设置标题为"",注意为null无效;或者设置getSupportActionBar().setDisplayShowTitleEnabled(false);

    设置toolbar的NavigationIcon随着drawerlayout的抽屉变化而改变图标,设置getSupportActionBar().setDisplayHomeAsUpEnabled(true)和getSupportActionBar().setHomeButtonEnabled(true);

    设置右侧菜单,需在activity的onCreateOptionsMenu方法中设置自己的菜单,然后可以在onOptionsItemSelected方法中捕获到每个菜单被选择到得到的事件,也可以toolbar自己设置监听;

     

    额外的一些分享

    退出系统

    在android 5要退出应用一般启动app的一个singleTop的activity,然后再finish这个activity。在android 5以上不推荐由我们来退出程序,应该交给系统来完成这样的工作,如果在android 5还是需要这样的功能,可以通过下面简单的代码实现:

    1 List<ActivityManager.AppTask> list = activityManager.getAppTasks();
    2for (ActivityManager.AppTask appTask : list) {
    appTask.finishAndRemoveTask();

    3 }
    exit

    判断当前activity是否正在运行

    在android 5以前都是通过拿getRuningTask来获取相关信息,但是现在android 5认为这个方法会泄露隐私,因此废弃了getRuningTask等方法,因此在android 5以上需要通过runningAppProcessInfo来获取相关信息,具体代码如下:

    1 boolean isOnForeGround = false;
List<ActivityManager.RunningAppProcessInfo> pList =activityManager.getRunningAppProcesses();
for(ActivityManager.RunningAppProcessInfo processInfo : pList){
    if(processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
        
    2 for(String activityPack : processInfo.pkgList){
            if(activityPack.equals(context.getPackageName())){
                isOnForeGround = true;
                
    3 return;
            
    4 }

    5         }
    6 
    }
}
    activity is foreground ?

    更改背景的透明度和灰度(API 1)

    即更改如弹出dialog默认的背景,可以由下面代码来做

    1 WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();

    2 lp.alpha = 0.5f;
    3 lp.dimAmount = 0.6f;

    4 dialog.getWindow().setAttributes(lp);
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    dim background

    大概总结这么多,demo下载地址

    https://github.com/jonyChina162/LollipopTest

    里面还有我自己做的一个ppt

  • 相关阅读:
    【CSS】330- 手把手教你玩转 CSS3 3D 技术
    【每周小回顾】4- 一起回顾上周精彩内容
    【CSS】329- 非常强!3行核心css代码的rate评分组件
    Android 高仿微信头像截取 打造不一样的自定义控件
    十三.200多万元得到的创业教训--用户体验就是人性
    十一. 没有这4项素质,别想在创业公司
    十二.200多万元得到的创业教训--app名字是关键
    十. 加班等于团队建设?
    Android 实现形态各异的双向侧滑菜单 自定义控件来袭
    九. 200多万元得到的创业教训--“雕爷”是忽悠吗?
  • 原文地址:https://www.cnblogs.com/lake19901126/p/4529667.html
Copyright © 2011-2022 走看看