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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

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

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

WCF三种通信模式(转)

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

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

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

笔记:设计模式(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…

最近处理的几个小问题_20160311

最近处理的小问题很多&#xff0c;我就拿出来几个&#xff0c;简单和大家说一说。我就分为三个方面&#xff0c;硬件问题&#xff0c;Oracle表空间迁移&#xff0c;MySQL断电恢复首先是硬件问题。如果看到下面的系统日志&#xff0c;就会发现早在2014年就出现了一些警告和问题&…

3. 什么是icmp?icmp与ip的关系_你知道如何跟女生,确定恋人关系吗?

哈喽&#xff01;同学你好&#xff01;我是子伯&#xff0c;是一名情感咨询。今天我想给你分享&#xff0c;和女生再暧昧期&#xff0c;如何去确定关系&#xff0c;因为......在我做咨询当中&#xff0c;有很多男生跟女生&#xff0c;不管是在聊天上&#xff0c;还是在线下的交…

量子计算机完整的图片,记者带你走近世界首台超越早期经典计算机的光量子计算机(组图)...

在光学体系方面&#xff0c;研究团队在去年首次实现十光子纠缠操纵的基础上&#xff0c;利用高品质量子点单光子源构建了世界首台超越早期经典计算机的单光子量子计算机。图为基于单光子的量子计算原型机结构。潘建伟教授供图据了解&#xff0c;多粒子纠缠的操纵作为量子计算的…

漂浮的表单

代码<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns"http://www.w3.org/1999/xhtml"><head><meta http-equiv"Content-Typ…

计算机word文档无法工作,电脑docx打不开怎么办(word文档无法打开的解决方法)...

我们在日常工作的时候&#xff0c;经常都会遇到这样子的一个问题&#xff0c;那也就是Word文件无法的现象。当我们的工作时间又非常的紧迫&#xff0c;那么个时候该怎么办呢&#xff1f;稳住&#xff0c;别慌&#xff0c;今天小编就来和大家一起探讨一下Word无法打开的解决方法…

LinkedList剖析

第1部分 LinkedList介绍 LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations, and per…

powerdesigner怎么导出pdf_各种科研绘图软件中的矢量图导出技巧

引言科技论文常含有插图&#xff0c;借助插图来形象直观、简明扼要地表达所要表述的内容(梁福军. 科技论文规范写作与编辑[M]. 清华大学出版社, 2014.)。科研绘图软件有很多种&#xff0c;而软件导出的图片可以分为矢量图&#xff08;vector&#xff09;和位图&#xff08;bitm…

Typesafe公司正式更名为Lightbend公司

Scala编程语言的发明者&#xff1a;Typesafe公司&#xff0c;已经完成他们的更名计划&#xff0c;改名后成为Lightbend公司。Typesafe公司在去年五月就宣布了他们的更名计划&#xff0c;从那时起&#xff0c;他们希望可以在两个月内完成改名相关事宜。Typesafe公司邀请了社区的…

理解Javascript_12_执行模型浅析

大家有没有想过&#xff0c;一段javascript脚本从载入浏览器到显示执行都经过了哪些流程&#xff0c;其执行次序又是如何。本篇博文将引出javascript执行模型的概念&#xff0c;并带领大家理解javascript在执行时的处理机制。 简单的开始 简单的代码&#xff1a; <script ty…

怎么制作铁闸门_“短笛”拿铁,最近的心头好!

其实花式咖啡除了市面上一些常见的款式外&#xff0c;还有一些是不常见又好喝的&#xff01;今天来给大家推荐一款“短笛”拿铁&#xff0c;最近的最爱&#xff01;什么是短笛拿铁&#xff1f;piccolo latte&#xff0c;在意大利文中“piccolo”是小的意思&#xff0c;而latte则…