Material适配1 - 入门篇
随着Material Design的普及,很多开发人员都会面临App的Material适配。如果你的App不只是针对5.0以上设备的话(多数情况也必须做兼容), 那么下面的经验总结将会对你有所帮助。
当然,有些公司的App不会改成Material Design,但如果你以前使用AppCompatV7的话,升级到21后,你必然面临和以前不一样的使用方式,了解新的方式也是必须的。
言归正传,官方给我们的适配方案是AppCompatV7,新发布的22.1.1适配包相对于22又进行了较大的改动,同时对Material适配更加强大,因此本文主要介绍基于22.1.1版本的适配流程。
开始使用
compile 'com.android.support:appcompat-v7:22.1.1'
这里需要说明的是使用19、20及其以下版本仍然是Holo风格,
使用21和22版本都会有Material的效果。
Theme介绍
引用完库之后,首先要面对的是配置主题。否则如果你以前使用AppCompat的话,运行之后会发现App惨不忍睹。
分类
Theme主要有以下几种分类:
- Theme.AppCompat (dark version)
- Theme.AppCompat.Light (light version)
- Theme.AppCompat.Light.DarkActionBar
如果以前使用ActionBar Holo风格时使用的就是AppCompat,那么这些地方是不需要更改的。
注: Material下的ActionBar会比之前更大,这点可在之后的ActionMode讨论中看到。
配置
Theme配置和原先有些不一样,配置示例如下:
<style name="Theme.App" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="colorPrimary">@color/theme_primary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="colorPrimaryDark">@color/theme_primary_dark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="colorAccent">@color/theme_color_accent</item>
</style>
先上官方解释图:
图上的各参数都可以直接配置到主题中生效。其中colorPrimaryDark仅在Lollipop以上机器生效。
colorAccent解析
colorAccent会改变光标颜色、checkbox背景色等。
基本上可以理解为控件的主色调。
以Checkbox为例:
官方默认是绿色的
改变colorAccent为蓝色后
自定义Status Bar (Lollipop以上设备)
Material可以让你轻松订制Staus Bar。
- 可以使Theme中的
android:statusBarColor
属性来改变,默认从android:colorPrimaryDark
中获取。 - 代码设置:
Window.setStatusBarColor()
常见错误
现在AppCompat对窗口主题的flag要求更严格。
主要原因是为了支持Dialog,大量使用了 AppCompat 之前并没有重视的 windowNoTitle 标志。
升级到v22.1.0以后(包括本文讲述的22.1.1),你可能遇到下面的异常:
Caused by: java.lang.IllegalArgumentException: AppCompat does not support the current theme features
at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:360)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:246)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
解决办法有两种:
最简单的是使用 Theme.AppCompat.NoActionBar 作为 parent theme,这样就会一直正常。
如果不能这样做(或许你需要同时支持ActionBar和NoActionBar,其实也可以通过第一种方式来解决,可能colorPrimary之类的需要多配置一遍),
你可以采用:<style name="MyTheme" parent="Theme.AppCompat">
...
</style> <style name="MyTheme.NoActionBar" parent="MyTheme">
<!-- Both of these are needed -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
AppCompatActivity使用
最新的22.1.1版本,ActionBarActivity已经废弃。开始采用AppCompatActivity。
如果你以前使用的是ActionBarActivity,建议替换掉,不需要更改其他代码。
(特别重要的AppCompatDelegate登场,具体代码可以查看AppCompatActivity实现,这里可以简单替换下快速适配,其实一般情况下也不需要自己来写AppCompatDelegate)
OK,到这里,其实你的App差不多就能正常运行了,只是有些细节方面还需要继续完善。
你可能已经注意到你的Dialog还不是Material风格,那么我们继续来看Dialog。
AppCompatDialog
AppCompat之前的21、22版本都没有实现Material Dialog。 在22.1.x发布时,这个问题终于解决了。
AppCompatDialog是AppCompat themed Dialog的 Base class.
目前他的子类只有AlertDialog,但已经足够使用。
使用方式也很简单,直接将AlertDialog改为android.support.v7.app
包下的AlertDialog即可。
其他使用方式一样,不需要做任何改动。
Preference
官方至今没有做到完全的适配。
对比图:
4.x设备上
5.x设备上
可以看到PreferenceCategory
和Preference
在4.x设备上底部都有横线,5.x设备上都没有。
也可以看到CheckBoxPreference是已经适配了的。
为了能让Preference适配的更加彻底,推荐下常用的第三方适配库: Android-MaterialPreference
但是作者并没有去写DialogPreference一类的,比如常见的ListPreference。
其实这里是有解决办法的。上面已经写到了新版的AlertDialog,配合How can I change the appearance of ListPreference Dialog 这篇帖子,就不难实现。
但也可以看到有人讨论了Material规范中提到的实现方式,当然也有人根据Google规范进行了实现,这里可以根据需求来自行选择实现方式。
关于Preference需要说明的是:
- 如果app是针对11以上的,推荐使用AppCompatActivity和PreferenceFragment来实现。
- 如果兼容更早的版本,需要借助AppCompatDelegate来实现,Google的示例代码:AppCompatPreferenceActivity.java
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.supportv7.app;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat.
*
* This technique can be used with an {@link android.app.Activity} class, not just
* {@link android.preference.PreferenceActivity}.
*/
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
Material中还有一个重要的特性是阴影的设置和波纹效果的实现,这里来粗略说明一下:
Elevation - 设置阴影
v21以后在View的xml中使用android:elevation
属性,或者在代码中使用View的setElevation()
方法。
兼容老版的阴影策略
还是需要使用.9图片的阴影来做。
注: ViewCompat.setElevation() sadly doesn't apply shadows in pre-Lollipop.
RippleDrawable - 波纹效果
使用已经提供好的
?android:attr/selectableItemBackground
扩散到View边界?android:attr/selectableItemBackgroundBorderless
设置后,会从孩子往父亲找一个依附的色。如果View往上找的时候,亲生父亲没背景色,会继续向上查找直到最顶端。找到了最顶端的爷爷,这个时候才绘制。
然而,如果父亲的兄弟又绘制了颜色,且盖住了最顶端的绘制,会导致看不到效果。如果有一定的透明度,结果就显而易见了。
特别注意:- 当把硬件加速给关闭时,这个效果是没有的。
- 这是API 21的新属性,老版本无法使用.
改变默认响应色
改变Theme中的android:colorControlHighlight
属性。
自定义
<!-- A green ripple drawn atop a black rectangle. -->
<ripple android:color="#ff00ff00">
<item android:drawable="@android:color/black" />
</ripple>
<!-- A blue ripple drawn atop a drawable resource. -->
<ripple android:color="#ff0000ff">
<item android:drawable="@drawable/my_drawable" />
</ripple>
android:color
中是点击响应色,也是波纹扩散色。
item中是正常状态下的显示。
一般使用时会和原有的selector配合,原有的selector负责5.0以下显示效果,
新的selector内部含有ripple标签放在drawable-v21中,保证点击效果。
写到这里,我觉得对一个中国开发者的Material入门篇来说,还需要说明下魅族适配的问题
关于魅族SmartBar适配问题
和魅族官方技术人员沟通过,不(pu)幸(tian)被(tong)告(qing)知(a):使用AppCompatV7 21以上,暂时无法进行SmartBar适配。
原因大概解释如下:
- v19的时候,ActionBar的处理是:如果系统有,系统处理;系统没有,自己画。
- v21以后都是Compat库自己画了,不会调用系统的,因此魅族无法获取合并到SmartBar中。
so,坐等魅族找到新的适配策略或者放弃SmartBar~~
最后
下一篇Toolbar与ActionMode,继续看请点击Material适配2 - 高级篇
参考资料
- Support Libraries v22.1.0
- AppCompat does not support the current theme features
- Getting Your Apps Ready for Nexus 6 and Nexus 9
Material适配1 - 入门篇的更多相关文章
- Material适配2 - 高级篇
版权声明: 欢迎转载,但请保留文章原始出处 作者:GavinCT 出处:http://www.cnblogs.com/ct2011/p/4493439.html 继续Material系列,先从Tool ...
- weex入门篇
weex入门篇 Weex 致力于使开发者能基于当代先进的 Web 开发技术,使用同一套代码来构建 Android.iOS 和 Web 应用. weex SDK 集成了vueJS,Rax,不需要额外引入 ...
- Java中的集合Set - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的集合Set - 入门篇>,希望对大家有帮助,谢谢 简介 前面介绍了集合List,映射Map,最后再简单介绍下集合Set,相关类如下 ...
- Spring Cloud Alibaba(1)---入门篇
Spring Cloud Alibaba入门篇 有关微服务的一些概念的东西我这里就不再阐述了,因为之前在写Spring Cloud系列的时候都有详细写过. 具体地址: Spring Cloud系列博客 ...
- Membership三步曲之入门篇 - Membership基础示例
Membership 三步曲之入门篇 - Membership基础示例 Membership三步曲之入门篇 - Membership基础示例 Membership三步曲之进阶篇 - 深入剖析Pro ...
- spring boot(一):入门篇
构建微服务:Spring boot 入门篇 什么是spring boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框 ...
- 1. web前端开发分享-css,js入门篇
关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人与人的教育背景与成长环境心理活动都有差别,但就别人的心得再结合自己的特点,然后探索适合自己的学 ...
- 一个App完成入门篇(七)- 完成发现页面
第七章是入门篇的倒数第二篇文章了,明天整个APP将进入收官. 本节教程主要要教会大家使用二维码扫描和用do_WebView组件加在html页面. 导入项目 do_WebView组件 扫描功能 自定义事 ...
- [原创]Linq to xml增删改查Linq 入门篇:分分钟带你遨游Linq to xml的世界
本文原始作者博客 http://www.cnblogs.com/toutou Linq 入门篇(一):分分钟带你遨游linq to xml的世界 本文原创来自博客园 请叫我头头哥的博客, 请尊重版权, ...
随机推荐
- linux 从0开始
网络配置: http://blog.51yip.com/linux/1120.html 网络配置为自动获取 vi命令参考: http://c.biancheng.net/cpp/html/2735.h ...
- jade直接写类似JavaScript语法的东西,不需要写script
我们知道,html做计算都是在JavaScript中完成的,那么不用JavaScript行不行呢,可以直接在jade中一样的编写 如: -var a = 3 -var b = 4 div a+b = ...
- (转)Jupyter notebook入门教程(上,下)
https://blog.csdn.net/red_stone1/article/details/72858962------上 https://blog.csdn.net/red_stone1/ar ...
- Android 开发工具类 11_ToolFor9Ge
1.缩放/ 裁剪图片: 2.判断有无网络链接: 3.从路径获取文件名: 4.通过路径生成 Base64 文件: 5.通过文件路径获取到 bitmap: 6.把 bitmap 转换成 base64: 7 ...
- Xshell用鼠标选中一段文字后自动换行的问题
JavaScript HTML(CSS) ASP 跨浏览器开发 IIS Apache vbScript JavaScript 应用服务器 XML/XSL 其他 CGI Ajax 非技术区 Cold ...
- Java虚拟机(六):JVM调优工具
工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗费性能的分析(dump文件分析)一般也不会在生产直接分析,往往dump下来的文件达1G左右,人工分析效率较低,因此利用工具来分析jvm相关问题 ...
- C++中指针和引用、数组之间的区别
指针指向一块内存,它的内容是所指内存的地址:而引用则是某块内存的别名,引用初始化后不能改变指向.使用时,引用更加安全,指针更加灵活. 初始化.引用必须初始化,且初始化之后不能呢改变:指针可以不必初始化 ...
- 修改MVC默认的pageBaseType以添加功能
试想下在MVC的前端页面JS或者html中需要使用多语言,而后端的多语言是维护在资源文件中的,前端如果使用的话需要使用AJAX频繁的获取,一个页面中可能会存在大量的需要语言转换的地方,频繁使用AJAX ...
- 修改 /etc/pam.d/login, linux 本地账号密码无法登陆,一直返回 登陆的login界面
今天我在我虚拟机测试的时候遇到了一个问题.登陆centos一直是返回login,账号和密码没错,我也换了两个用户. 1.问题描述 我正常的输入用户名和密码 错误提示截图:返回登陆界面,我重新试了另外的 ...
- 基于VUE的SPA单页应用开发-加载性能篇
1.基于异步数据的vue页面刷新 先看看基于异步数据的vue页面刷新后,都发生了啥- 如图所示: 图1 基于异步数据的vue页面刷新 网络请求图 步骤如下: step1:请求页面: step2:请求页 ...