今天我们来介绍一种用TextView代替并显示图片,以达到App优化及图标自适应的效果。当然,我们先来看一下效果:
如果你看到上面这张图片,第一反映你可能认为都是用ImageView去显示的,那你就错了,这些全都是用TextView实现的(当然更不可能是给 TextView 设置了背景图)。
平时我们在开发中,图片可谓是处处可见且必不可少的一部分,为了想尽办法让图片达到适配的效果我们可能需要:
根据不同分辨率来提供多套图,暂且不说这种方式是否麻烦,正常情况下我们切的三套或更多套图有时候总在有些机型上的效果不尽人意。
可能这时候你想到了用 .9图片
,这时候且不说你们家 UI 妹子会不会单独的为我们 Android 端提供 .9图片
(姑且相信你们家UI会制作 .9
),但是 .9图片
是有一定的局限性的,它只能是图片部分区域拉伸。
这篇文章也并不是去介绍如何去做图片的适配,而是介绍一种利用字体库的方式,我们用 TextView 的形式去显示图片,而且我们还可以正常的使用 android:textSize
属性来随意设置图片的大小!
其实这里通过 TextView 来显示图片的方式,我更愿意更准确的说成是通过 TextView 来显示图标 ,因为这里的图片不是真正意义上的大图而是相当于可以随意拉伸的矢量图。当然,如果你愿意你也可以用这种方式来显示图片。
啰嗦这么多,你的大刀是不是早就饥渴难耐了?其实这种方式很容易就能实现,只是通过给 TextView 设置一种字体,不要着急,马上开始。
大家都知道,在 android 中,我们如果要更换字体,除了要引入我们需要的字体库外,还需要给我们的 TextView 去手动设置使用的字体,如何去设置呢?其实很简单。
textView.setTypeface(Typeface tf);
尽管就这么一行代码,但是,在我们项目中肯定会存在大量的TextView,难道我们要一个个的去动手设置吗?想想这也是一件很头疼的事,下面就介绍一种方便的方法,一行代码解决字体设置的问题。
在看代码之前,先来看看思路,其实思路很简单,我们提供一个根布局,写一个方法去递归遍历整个根布局,如果发现是textView,则设置字体。思路很简单,相信代码也很简单,就是一个递归方法。
public class FontHelper { public static final String DEF_FONT = "fonts/ocnyangfont.ttf"; public static final void injectFont(View rootView) { injectFont(rootView, Typeface.createFromAsset(rootView.getContext().getAssets(), DEF_FONT)); } private static void injectFont(View rootView, Typeface typeface) { if (rootView instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) rootView; int childViewCount = viewGroup.getChildCount(); for (int i = 0; i < childViewCount; i++) { injectFont(viewGroup.getChildAt(i), typeface); } } else if (rootView instanceof TextView) { ((TextView) rootView).setTypeface(typeface); } } }
定义了一个工具类,这个类提供两个静态方法,但是核心都是
public static final void injectFont(View rootView, Typeface tf)
这个方法中,首先我们去判断我们给的rootView是不是ViewGroup,如果是ViewGroup,则遍历他的所有子view,然后递归去调用这个方法,直到全部完成,如果发现某个view是TextView,则我们调用setTypeface方法来设置字体。
ok,从这个工具类中我们还可以看到,我们的字体是放在assets/fonts目录下的。
最后是在activity中使用字体库,正式利用了上面的工具类,所以我们的代码将会很简单。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FontHelper.injectFont(findViewById(android.R.id.content)); }
仅仅一行代码, FontHelper.injectFont(findViewById(android.R.id.content));
我们就完成了给所有TextView设置字体的工作。
现在对 LayoutInflateFactory 的用法还不太熟悉的,可以先去看一下鸿洋的这篇博文: 探究 LayoutInflate setFactory 。
我们编写一个自定义的LayoutInflaterFactory:
public class IconFontLayoutFactory implements LayoutInflaterFactory { private static Typeface sTypeface; private AppCompatDelegate mAppCompatDelegate; public IconFontLayoutFactory(Context context, AppCompatDelegate appCompatDelegate) { if (sTypeface == null) { sTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/ocnyangfont.ttf"); } mAppCompatDelegate = appCompatDelegate; } @Override public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { View view = mAppCompatDelegate.createView(parent, name, context, attrs); if (view instanceof TextView) { ((TextView) view).setTypeface(sTypeface); } return view; } }
字体文件我们还是放在 assets/fonts
目录下。
然后你可以在你的BaseActivity的onCreate中,调用如下代码:
@Override protected void onCreate(Bundle savedInstanceState) { LayoutInflaterCompat.setFactory(getLayoutInflater(), new IconFontLayoutFactory(this,getDelegate())); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }
注意一定要在super.onCreate前调用即可。
该方式可以在TextView及其子类对象创建完成时,就可以为其调用setTypeFace,非常的高效。
而对于字体库的加载,如果有需要,你甚至可以采用懒加载的方式,在SplashActivity中对其初始化。
这里提供是两种全局设置的方式。
有时候我们只是需要给部分 TextView 设置,这时候大家可以选择手动单独给特定的 TextView 设置,也可以通过自定义 View 的方案来实现( 在构造方法中去设置 TypeFace ,我个人也比较提倡这种方式,使用上相对灵活,也很简单这里就啰嗦了,详细代码可以到这里下载 本文源码 内查看)。
那上面这些只是如何设置字体的方法,可能你也早就知道了,字体是字体,也不是图片呀,大兄弟莫慌,下面就给你如何介绍一种酷炫的字体库和制作自己独特的图片字体库的方法。
在开始使用之前,我们我们需要到
https://github.com/FortAwesome/Font-Awesome/
下载这个字体库(不想麻烦,本文 源代码 也包含有)。下载下来以后,你会看到有很多目录和文件,没关系,我们只需要一个文件-fontawesome-webfont.ttf,这个文件位于/fonts/目录下。将这个ttf文件copy到你项目的assets目录下,按照惯例或者说是共识,我们可能是将它放到assets/fonts这个目录下(注意,没有这个目录的话,创建它!)。
ok, 准备工作都做好了,那我们就开始使用它吧,看我的xml布局文件:
<LinearLayout //... > <TextView android:id="@+id/text1" android:layout_width="match_parent" android:layout_margin="10dp" android:textSize="58sp" android:textColor="#ff995533" android:layout_height="wrap_content" android:text=""/> <TextView android:id="@+id/text2" android:layout_width="match_parent" android:layout_margin="10dp" android:textSize="118sp" android:textColor="#ff9ff533" android:layout_height="wrap_content" android:text=""/> //... </LinearLayout>
看到这个布局文件,我们看到和平时没什么区别,给出了textSize或者textColor属性,不用想这些肯定去控制了我们需要显示的图片的大小和颜色!
细心的你会发现这些 TextView 文本好奇怪。其实这些文本对应的就是相对于的图片。可是,现在我们又遇到了一个问题,我们怎么知道哪写文本代表了什么图片呢?下面给出一个网址,通过这个网址,大家可以看到实体文本和他对应的图片的一个对照表。
http://fortawesome.github.io/Font-Awesome/cheatsheet/
本文 源码 内我们提供了一个 string.xml
文件的图片字符对照表,可以直接在项目中使用。
你也可以在根据自己的需要在上面 string.xml
文件里 Ctrl + F
检索出对应的编码放到自己的字符串文件里或直接使用。
哦,对了,不知道大家有没有发现,这里我们无意中解决了一个图片大小的问题,因为我们可以任意改变一个文本的大小,所以,就不需要提供多套图去适配不同的屏幕了。
这是你可能还是有疑问, Font-Awesome 库
内提供的图标虽然很全很美观,但是不一定能满足我们所有的需要啊!那现在就教大家如何制作属于自己的字体库。
在自己动手制作图片字体库之前,当然要先查找一些自己喜欢的漂亮的图标了,下面开启干货福利模式。
对于使用,最主要就是找到一些靠谱的素材站点了
http://www.iconfont.cn/
https://icomoon.io/app/#/select
https://github.com/mikepenz/Android-Iconics第一个站点是阿里提供的图标库,基本上可以搜索到需要的任何图标,非常方便,也支持颜色和大小的设置,足够满足我们的需求:
无论上面这些网站提供的图标是多么的全,可能都无法满足贪心的你或者你们家追求完美(矫情)到极致的UI,那么如果App内的图标部分是自己制作的,再混杂着网络上已有的图标能打包到一个字体库么?
答案当然是肯定的,我们本来就是要制作属于自己的字体库嘛!比如你就可以依赖 iconfont.com
这个网站,自行上传svg图标,然后就可以自由选择了。
关于 iconfont 网站的用法可以参考官方手册(也可以跳过,直接跟着我学习怎么生成自己的字体库):
http://www.iconfont.cn/help/platform.html我们以 iconfont 库为例,教大家 生成自己图片字体库的整个流程 (下面所有步骤,大家都无需注册账号,就可以直接使用)。
首先在 iconfont 网站上选择自己要生成到字体库的图标,可以选择网站字体库中选择,也可以在我的图标库中选择自己上传的图标。把这些图标添加到库(即添加到购物车):
当你想要生成的字体库的图标选择完成后,在网站右上角点击打开库(购物车),在库里可以看到自己选择的所有图标,确定后点击下载代码:
在解压后的文件夹中,我们看到许多文件。其中以 .ttf
结尾的文件就是我们生成的自己的字体库,而 3 个 .html
文件对应的是不同平台使用时对应的编码。而我们在 Android 开发中要使用的编码是 demo_unicode.html
文件里对应的 &#xxxxx;
形式的编码。
细心的你一定会发现,生成的字体库里虽然包含了很多图标,却只有小小的几 KB 的大小,更难能可贵的是无论设置多大的尺寸它依旧能够保存一样的清晰度,当然,你也可以把该方案看成apk瘦身的可选手段之一。
本文Demo源代码下载地址: https://github.com/OCNYang/FontTest
参考:
亓斌 - FontAwesome-用TextView显示图片
鸿洋 - Android IconFont全攻略
How to Use FontAwesome in an Android App