Android L 的 Tint(着色)

Tint 是什么?

Tint 翻译为着色。

着色,着什么色呢,和背景有关?当然是着背景的色。当我们开发 App 的时候,如果使用了 Theme.AppCompat 主题的时候,会发现 ActionBar 或者 Toolbar 及相应的控件的颜色会相应的变成我们在 Theme 中设置的 colorPrimary, colorPrimaryDark, colorAccent 这些颜色,这是为什么呢,这就全是 Tint 的功劳了!

这样做有什么好处呢?好处就是你不必再老老实实的打开 PS 再制作一张新的资源图。而且大家都知道 apk 包最大的就是图片资源了,这样减少不必要资源图,可以极大的减少了我们的 apk 包的大小。

实现的方式就是用一个颜色为我们的背景图片设置 Tint(着色)。


看看即将发布的SegmentFault for Android 2.7中,发布问题功能,这个EditText的颜色和我们的主要颜色相同。它利用了TintManager这个类,为自己的背景进行着色(绿色)。
那么这个原始图是什么样子呢?我们从appcompat-v7包中找到了这个图,是一个.9图,样子如下:


其实它只是一个黑色的条,通过绿色的着色,变成了一个绿色的条。 就是这样的设计方式,使得我们在Material Design中省了多少资源文件呀!


例子:

WhiteBall-2WhiteBall-1

大家可以看上面再张图,这个是做的一个应用“小白球”,如图 1 的小图片本来都是白色的(圆背景的单独设的),但是经过 Tint 着色后就变成了图 2 中的浅蓝色了。

好了,既然理解了tint的含义,我们赶紧看下这一切是如何实现的吧。 
其实底层特别简单,了解过渲染的同学应该知道PorterDuffColorFilter这个东西,我们使用SRC_IN的方式,对这个Drawable进行颜色方面的渲染,就是在这个Drawable中有像素点的地方,再用我们的过滤器着色一次。 
实际上如果要我们自己实现,只用获取View的backgroundDrawable之后,设置下colorFilter即可。

看下最核心的代码就这么几行

if (filter == null) { 
   // Cache miss, so create a color filter and add it to the cache 
   filter = new PorterDuffColorFilter(color, mode); 
}

d.setColorFilter(filter); 
通常情况下,我们的mode一般都是SRC_IN,如果想了解这个属性相关的资料,这里是传送门:http://blog.csdn.net/t12x3456/article/details/10432935 (中文)

由于API Level 21以前不支持background tint在xml中设置,于是提供了ViewCompat.setBackgroundTintList方法和ViewCompat.setBackgroundTintMode用来手动更改需要着色的颜色,但要求相关的View继承TintableBackgroundView接

源码解析

以 EditText 为例,其它的基本一致

public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {super(TintContextWrapper.wrap(context), attrs, defStyleAttr);...ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); //根据背景的resource id获取内置的着色颜色。if (tint != null) {setInternalBackgroundTint(tint); //设置着色}...
}private void setInternalBackgroundTint(ColorStateList tint) {if (tint != null) {if (mInternalBackgroundTint == null) {mInternalBackgroundTint = new TintInfo();}mInternalBackgroundTint.mTintList = tint;mInternalBackgroundTint.mHasTintList = true;} else {mInternalBackgroundTint = null;}//上面的代码是记录tint相关的信息。applySupportBackgroundTint();  //对背景应用tint
}private void applySupportBackgroundTint() {if (getBackground() != null) {if (mBackgroundTint != null) {TintManager.tintViewBackground(this, mBackgroundTint);} else if (mInternalBackgroundTint != null) {TintManager.tintViewBackground(this, mInternalBackgroundTint); //最重要的,对tint进行应用}}
}

然后我们进入tintViewBackground看下TintManager里面的源码

public static void tintViewBackground(View view, TintInfo tint) {final Drawable background = view.getBackground();if (tint.mHasTintList) {//如果设置了tint的话,对背景设置PorterDuffColorFiltersetPorterDuffColorFilter(background,tint.mTintList.getColorForState(view.getDrawableState(),tint.mTintList.getDefaultColor()),tint.mHasTintMode ? tint.mTintMode : null);} else {background.clearColorFilter();}if (Build.VERSION.SDK_INT <= 10) {// On Gingerbread, GradientDrawable does not invalidate itself when it's ColorFilter// has changed, so we need to force an invalidationview.invalidate();}
}private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {if (mode == null) {// If we don't have a blending mode specified, use our defaultmode = DEFAULT_MODE;}// First, lets see if the cache already contains the color filterPorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);if (filter == null) {// Cache miss, so create a color filter and add it to the cachefilter = new PorterDuffColorFilter(color, mode);COLOR_FILTER_CACHE.put(color, mode, filter);}// 最最重要,原来是对background drawable设置了colorFilter 完成了我们要的功能。d.setColorFilter(filter);
}

以上是对API21以下的兼容。
如果我们要实现自己的AppCompat组件实现tint的一些特性的话,我们就可以指定好ColorStateList,利用TintManager对自己的背景进行着色,当然需要对外开放设置的接口的话,我们还要实现TintableBackgroundView接口,然后用ViewCompat.setBackgroundTintList进行设置,这样能完成对v7以上所有版本的兼容。

实例

比如我现在要对一个自定义组件实现对Tint的支持,其实只用继承下,加一些代码就好了,代码如下(几乎通用):

public class AppCompatFlowLayout extends FlowLayout implements TintableBackgroundView {private static final int[] TINT_ATTRS = {android.R.attr.background};private TintInfo mInternalBackgroundTint;private TintInfo mBackgroundTint;private TintManager mTintManager;public AppCompatFlowLayout(Context context) {this(context, null);}public AppCompatFlowLayout(Context context, AttributeSet attributeSet) {this(context, attributeSet, 0);}public AppCompatFlowLayout(Context context, AttributeSet attributeSet, int defStyle) {super(context, attributeSet, defStyle);if (TintManager.SHOULD_BE_USED) {TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attributeSet,TINT_ATTRS, defStyle, 0);if (a.hasValue(0)) {ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));if (tint != null) {setInternalBackgroundTint(tint);}}mTintManager = a.getTintManager();a.recycle();}}private void applySupportBackgroundTint() {if (getBackground() != null) {if (mBackgroundTint != null) {TintManager.tintViewBackground(this, mBackgroundTint);} else if (mInternalBackgroundTint != null) {TintManager.tintViewBackground(this, mInternalBackgroundTint);}}}@Overrideprotected void drawableStateChanged() {super.drawableStateChanged();applySupportBackgroundTint();}private void setInternalBackgroundTint(ColorStateList tint) {if (tint != null) {if (mInternalBackgroundTint == null) {mInternalBackgroundTint = new TintInfo();}mInternalBackgroundTint.mTintList = tint;mInternalBackgroundTint.mHasTintList = true;} else {mInternalBackgroundTint = null;}applySupportBackgroundTint();}@Overridepublic void setSupportBackgroundTintList(ColorStateList tint) {if (mBackgroundTint == null) {mBackgroundTint = new TintInfo();}mBackgroundTint.mTintList = tint;mBackgroundTint.mHasTintList = true;applySupportBackgroundTint();}@Nullable@Overridepublic ColorStateList getSupportBackgroundTintList() {return mBackgroundTint != null ? mBackgroundTint.mTintList : null;}@Overridepublic void setSupportBackgroundTintMode(PorterDuff.Mode tintMode) {if (mBackgroundTint == null) {mBackgroundTint = new TintInfo();}mBackgroundTint.mTintMode = tintMode;mBackgroundTint.mHasTintMode = true;applySupportBackgroundTint();}@Nullable@Overridepublic PorterDuff.Mode getSupportBackgroundTintMode() {return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;}
}

  • Github:https://github.com/iQuick/AndroidTint


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/261814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 调用函数 开销_Python函数调用非常慢

这主要是为了确保我的方法是正确的,但我的基本问题是,如果我需要访问函数,那么检查函数外部是否值得.我知道,我知道,过早优化,但在很多情况下,它在函数调用中放置一个if语句以确定是否需要运行其余代码,或者将它放在函数调用之前.换句话说,它不会以任何方式做到这一点.现在,所有…

机房收费系统讨论

在假期快要结束的时候,我们大家一起讨论了各自的机房收费系统.轮流的看了每个人的作品.我们是分两个组看得. 说说看这次作品的感受吧. 大家作品都做得很认真.由于都是第一次做作品,而且还是第一次自己独立的完成一个较大的作品. 基本功能大家可是说是都实现了.我个人的作品现在…

《从零开始学Swift》学习笔记(Day 66)——Cocoa Touch设计模式及应用之通知机制...

原创文章&#xff0c;欢迎转载。转载请注明&#xff1a;关东升的博客 通知&#xff08;Notification&#xff09;机制是基于观察者&#xff08;Observer&#xff09;模式也叫发布/订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;是 MVC&#xff08;模型-视图-控…

医学计算机应用研究的意义,医学图像感兴趣区域的自动提取-计算机应用研究.PDF...

医学图像感兴趣区域的自动提取-计算机应用研究第 12 期 何 楚等: 医学图像感兴趣区域的自动提取 157 医学图像感兴趣区域的自动提取*何 楚, 彭文敏, 李吉星, 廖孟扬( 武汉大学 电子信息学院, 湖北 武汉 430072)摘 要: 针对医学图像归档与通信系统通过视频采集和胶片扫描产生的海…

JUnit3 一次运行多个测试类和进行多次重复测试:使用测试套件和RepeatedTest

测试套件 如果测试类写到很多&#xff0c;每次要进行测试&#xff0c;难道要重新点击每一个测试类来运行&#xff1f;如果有200个测试类要测试呢&#xff1f; 为了解决这个问题&#xff0c;引入了测试套件&#xff08;TestSuite&#xff09;。 通过将多个测试放入套件中&#x…

DataGridView控件初始化,添加删除行(不绑定数据库)

转载&#xff1a; http://blog.163.com/zjlovety126/blog/static/2241862420106128264300/ 也不知道是否该应用这个控件&#xff0c;不过也想不出该用其他什么控件&#xff0c;关键是俺比较菜没什么经验。 要求是这样的&#xff0c;用户一次添加一个任务&#xff0c;这个任务有…

mysql 不同分区 同时insert_Mysql分区表的原理和优缺点

分区表的原理分区表是由多个相关的底层表实现&#xff0c;这些底层表也是由句柄对象表示&#xff0c;所以我们也可以直接访问各个分区&#xff0c;存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎)&#xff0c;分区表的索引只是在各个底层…

计算机应用 范文,计算机应用基础(范文).doc

第 PAGE \* Arabic 1 页计算机应用基础(范文)PAGE计算机应用基础5一、单选题1、第一台电子计算机是1946年在美国研制成功的&#xff0c;该机的英文缩写名是_ A&#xff1a;ENIAC _____。2、关于计算机的分类方法有多种&#xff0c;下列选项中不属于按计算机处理数据的方式进行分…

架构漫谈(八):从架构的角度看如何写好代码

2016-03-03 王概凯Kevin 聊聊架构架构漫谈是由资深架构师王概凯Kevin执笔的系列专栏&#xff0c;专栏将会以Kevin的架构经验为基础&#xff0c;逐步讨论什么是架构、怎样做好架构、软件架构如何落地、如何写好程序等问题。 本文是漫谈架构专栏的第八篇&#xff0c;作者Kevin举例…

大理三塔,及崇圣寺里的假深沉

大理三塔&#xff0c;及崇圣寺里的假深沉 记得我第一次看见三塔时&#xff0c;是一副破败不堪的景象。而第二次来大理时&#xff0c;因为“崇圣寺”正在修葺&#xff0c;只能远远地眺望一下三塔。那时我对大理失望极了。 现在三塔修缮一新&#xff0c;给人耳目一新的感觉。 三塔…

WCF三种通信模式(转)

一、概述 WCF在通信过程中有三种模式&#xff1a;请求与答复、单向、双工通信。以下我们一一介绍。 二、请求与答复模式 描述&#xff1a; 客户端发送请求&#xff0c;然后一直等待服务端的响应(异步调用除外)&#xff0c;期间处于假死状态&#xff0c;直到服务端有了答复后才能…

python语言打印菱形_Python打印菱形

使用python打印出菱形&#xff1a;*************************思想&#xff1a;平常我写这种代码的时候&#xff0c;总是自然地使用二层循环&#xff0c;今天老师教了一个特别好的方法&#xff0c;化二维为一维。我觉得代码优化是很重要的&#xff0c;所以把它写下来&#xff0c…

计算机软件及应用stata,蒙特卡洛模拟及其Stata应用实现

蒙特卡洛模拟及其Stata应用实现出版时间&#xff1a;2015年版丛编项&#xff1a;海南大学经济管理系列丛书内容简介《蒙特卡洛模拟及其Stata应用实现》的第1章是Stata软件基础&#xff0c;主要介绍了Stata软件的一些基本功能与操作。第2章介绍了Stata软件的语法结构&#xff0c…

第一个程序,Hello World

在eclipse里新建一个project&#xff0c;选Android-Android Project 然后Next,继续 解释一下 Package Name&#xff1a;这个学过编程的人都应该熟悉了&#xff0c;类似于namespace&#xff0c;你定义的所有东西都在一个包里不会和别的包出现重命名的问题等等&#xff0c;不多说…

Hadoop2.6集群动态添加和删除数据节点

2019独角兽企业重金招聘Python工程师标准>>> 开始之前&#xff0c;应该把所有新增数据节点上的Hadoop环境都配置好&#xff08;如果要直接复制已经存在节点的hadoop文件夹&#xff0c;应该删掉里面已经产生的集群数据&#xff0c;比如tmp和data目录&#xff0c;不然…

读操作系统的设计与实现--进程互斥

1.竞争条件 当两个或多个进程读写某些共享数据时&#xff0c;而最后的结果取决于进程的运行顺序时&#xff0c;这就称为竞争条件。包含竞争条件的程序&#xff0c;大多数时候运行结果良好&#xff0c;但是往往会发生一些无法解释的结果。事实上&#xff0c;只要涉及到共享资源的…

拉取ftp服务器上的文件_winscp和云服务器,2步实现winscp将文件上传到腾讯云Linux云服务器...

WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端。同时支持SCP协议&#xff0c;它的主要功能就是在本地与远程计算机间安全的复制文件。与使用FTP上传代码相比&#xff0c;通过WinSCP可以直接使用服务器账户密码访问云服务器&#xff0c;无需在服务器端做任何配置。II…

计算机技术qq交流群,专业计算机群QQ

我想学习计算机的程序没什么基础 应该怎么做学什么 要怎么样才可以学好楼上的说得不对,直接学C就可以了,C不用学得太深,学些基本语法,然后转学C,因为C是面向对象的编程思想,把C的基础编程弄明白以后,可以从Visual C,C#,C。Net中选一项来学,先学些基础的,然后做些小项目,然后可以…

笔记:设计模式(3)-Abstract Factory抽象工厂模式

工厂模式的起源 1.变化点在“对象的创建”&#xff0c;因此就封装“对象创建”&#xff1b; 2.面向接口编程&#xff0c;依赖接口&#xff0c;而非依赖实现。 动机&#xff08;Motivation&#xff09; 在系统中&#xff0c;经常面临着“一系列相互以来的对象”的创建工作&#…

MongoDB操作:insert()

2019独角兽企业重金招聘Python工程师标准>>> Override public boolean inSert(String dbName, String collectionName, String[] keys,Object[] values) { DB db null; DBCollection dbCollection null; WriteResult result null; String resul…