php动态字体,APP动态切换字体的实现

news/2024/10/18 9:22:54/

APP动态切换字体的实现

qq2519157 • 2019 年 01 月 10 日

需求

最近做完了新功能,突发奇想,想着如何处理app的动态切换字体

方案

方案1:通过反射机制,修改Typeface类的字体库引用

object FontUtils {

fun setDefaultFont(context: Context,staticTypefaceFieldName:String,fontAssetName:String){

val font = Typeface.createFromAsset(context.assets, fontAssetName)

replaceFont(staticTypefaceFieldName,font)

}

fun replaceFont(staticTypefaceFieldName: String, newTypeface: Typeface) {

try {

val staticField = Typeface::class.java.getDeclaredField(staticTypefaceFieldName)

staticField.isAccessible = true

staticField.set(null, newTypeface)

} catch (e: NoSuchFieldException) {

e.printStackTrace();

} catch (e: IllegalAccessException) {

e.printStackTrace();

}

}

}

不过现有项目都是kotlin写的,不太想用反射

方案2:通过修改特定的View或者自定义TextView

工作量太大,而且效果不好.

方案3:通过第三方库

实现

接入

2.0版本

api 'uk.co.chrisjenx:calligraphy:2.3.0'

3.0版本

api 'io.github.inflationx:calligraphy3:3.0.0'

api 'io.github.inflationx:viewpump:1.0.0'

因为我是在library模块引入的,所以使用的api方式

>初始化

我们可以选择在自定义的Application中初始化,也可以在LauncherActivity中,看个人喜好.

2.0版本

private fun initTypeFace() {

val path = PreferenceUtil.getPreference("fonts")!!.getString("fontPath", "fonts/FounderBlack.ttf")

CalligraphyConfig.initDefault(CalligraphyConfig.Builder()

.setDefaultFontPath(path)

.setFontAttrId(R.attr.fontPath)

.build()

)

}

3.0版本

ViewPump.init(ViewPump.builder()

.addInterceptor(CalligraphyInterceptor(

CalligraphyConfig.Builder()

.setDefaultFontPath(path)

.setFontAttrId(R.attr.fontPath)

.build()))

.build())

在onCreate()方法中调用initTypeFace()即可

这段代码是初始化我们的字体,其实在这里我们就可以选择自己喜欢的字体了,不过选完以后字体就固定了,这与我们的需求不符.

9150e4e5ly1flngo641c3j208c08c75t.jpg

我们先去自己的BaseActivity中处理一下

2.0版本

override fun attachBaseContext(newBase: Context?) {

super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase))

}

3.0版本

override fun attachBaseContext(newBase: Context?) {

super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase?:return))

}

因为要让字体全局生效,必然要在每个Activity的attachBaseContext()方法中绑定我们的框架,所以BaseActivity是最好的选择了.

其实到这里,我们的三方字体就能正常显示了,当然,如果你想针对单个控件设置特别的字体,你可以这样做

android:id="@+id/semibold"

android:text="Bold"

fontPath="fonts/mySemibold.ttf"

android:padding="10dp"

android:gravity="center"

android:onClick="@{onclick}"

android:textSize="14sp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

/>

只需要给文本控件设置fontPath就好了

高级操作

起初,我们的字体是这样的

af797075938971827421d88535cefd95.png

我们的目的是要让用户自己选择显示什么样的字体,比如这样:

599990e6d3036b0bf458e8166468dcc8.png

因此我们还需要其他操作,新建一个FontActivity,在其伴生类中初始化所有字体

companion object {

private val fonts = arrayListOf(

FontStyle("杨任东竹石粗体", "YRDBold", "fonts/YRDBold.ttf"),

FontStyle("杨任东竹石细体", "TRDExtralight", "fonts/YRDExtralight.ttf"),

FontStyle("站酷快乐体2016", "ZhankuHappy2016", "fonts/zhankuHappy2016.ttf"),

FontStyle("站酷高端黑", "ZhankKuAdvancedBlack", "fonts/zhankuAdvancedBlack.ttf"),

FontStyle("王汉宗魏碑体", "WHZ_WB", "fonts/WHZ_WB.ttf"),

FontStyle("Oradano-Mincho名朝", "OradanoMincho", "fonts/Oradano-Mincho.ttf"),

FontStyle("阿里汉仪智能黑体", "AliSmartBlack", "fonts/AliSmartBlack.ttf"),

FontStyle("庞门正道标题体2.0增强版", "PMZD_Title", "fonts/PMZD-Title.ttf"),

FontStyle("思源柔黑体", "GenJyuuGothic", "fonts/GenJyuuGothic-Medium.ttf"),

FontStyle("方正黑体", "FounderBlack", "fonts/FounderBlack.ttf"),

FontStyle("TanukiMagic麦克笔手绘", "TanukiMagic", "fonts/TanukiMagic.ttf")

)

}

FontStyle是一个data class

data class FontStyle(val name:String,val tag :String,val path:String,var inUse:Boolean =false)

用于记录字体信息,包括字体名称,tag标记,以及字体路径,字体的选取与否保存在SharedPreference当中

val string = PreferenceUtil.readString("fonts", "fontPath", "fonts/FounderBlack.ttf")

for (font in fonts) {

val radioButton = RadioButton(this@FontsActivity)

val layoutParams = LinearLayout.LayoutParams(

LinearLayout.LayoutParams.MATCH_PARENT,

LinearLayout.LayoutParams.WRAP_CONTENT)

layoutParams.gravity = Gravity.CENTER

layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT

layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT

layoutParams.bottomMargin = 30

radioButton.setPadding(10, 10, 10, 10)

radioButton.layoutParams = layoutParams

radioButton.tag = font.tag

if (font.path == string) {

font.inUse = true

radioButton.isChecked = true

mCheckRadioButton=radioButton

}

radioButton.text = font.name

radioButton.maxLines = 1

radioButton.ellipsize = TextUtils.TruncateAt.END

radioButton.textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12f, resources.displayMetrics)

CalligraphyUtils.applyFontToTextView(radioButton, Typeface.createFromAsset(assets, font.path))

binding.rg.addView(radioButton)

radioButton.setOnClickListener {

if (radioButton==mCheckRadioButton) {

return@setOnClickListener

}else{

mCheckRadioButton?.isChecked=false

radioButton.isChecked=true

mCheckRadioButton=radioButton

}

}

}

遍历字体集合动态生成RadioButton,加字体tag设置给radioButton,并将已选中的字体选中

通过

CalligraphyUtils.applyFontToTextView(radioButton, Typeface.createFromAsset(assets, font.path))

方法动态设置字体,然后我们就得到了上面的显示效果了

选中后点击确定

val tag = findViewById<RadioButton>(binding.rg.checkedRadioButtonId)?.tag

for (font in fonts) {

if (font.tag == tag) {

if (font.inUse) {

toastShort("字体正在使用当中...")

} else {

PreferenceUtil.writeString("fonts", "fontPath", font.path)

PreferenceUtil.writeString("fonts", "fontName", font.name)

PreferenceUtil.writeString("fonts", "fontTag", font.tag)

BaseApplication.finishAll()

startActivity(Intent(this@FontsActivity, LaunchActivity::class.java))

this@FontsActivity.overridePendingTransition(0, 0)

}

break

}

}

通过选中的radiobutton的tag来判断我们想要换的是什么字体,将它的路径,name tag都保存起来,然后调用application的finishAll()方法关闭所有的Activity,最后再次启动我们的LauncherActivity,我们的APP就重新启动并加载了新的字体了

效果对比

切换前

9df6ab4f6cf63c43bd5c0269091d5a9b.png

切换后

7e21a16d334e68ec8cebac4f93ac3bc0.png

080d2333be10c7bd042e1012870c01fe.png


http://www.ppmy.cn/news/589262.html

相关文章

Pelcod与VISCA常用控制协议整理

PELCO-D控制协议&#xff08;部分&#xff09; 字节 1 字节 2 字节 3 字节 4 字节 5 字节 6 字节 7 同步字节 地址码 指令码 1 指令码 2 数据码 1 数据码 2 校验码 该协议中所有数值都为十六进制数同步字节始终为 FFH地址码为摄像机的逻辑地址号&#xff0c;地址…

leetcode:191. 位1的个数

难度&#xff1a;简单 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 1 的个数&#xff08;也被称为汉明重量&#xff09;。 提示&#xff1a; 请注意&#xff0c;在某些语言&#xff08;…

共享打印机无法连接的解决办法

共享打印机无法连接的解决办法 win10能找到共享打印机但无法连接&#xff0c;双击就报错&#xff0c;添加网络打印机也报错&#xff0c;也修改了共享主机的secpol.msc允许了guest账号&#xff0c;允许了guest通过网络访问&#xff0c;手工添加网络打印机也报错失败。 通过百度…

Armbian-安装cpus

第一步,前往HP官网下载linux驱动,HP Developers Portal | Version: 3.22.6 然后上传到linux端,并赋予可运行权限 安装驱动 第二步,安装cups apt install cups 第三步,安装完成后,修改cpusd.conf文件,红色部分为修改后. # Only listen for connections from the local mac…

【C++】hash:unordered_map和unordered_set的底层结构

hash 哈希概念哈希冲突哈希函数哈希冲突的两种解决方法之闭散列哈希冲突的两种解决方法之开散列开散列和闭散列的比较 哈希概念 在c98中还并没有提出哈希这样的结构&#xff0c;只有以红黑树为底层结构的map&#xff0c;set系列&#xff0c;这样使得查询时的效率 l o g 2 N lo…

高速电路设计系列分享-基本概念

目录 概要 整体架构流程 技术名词解释 1.带宽的理解 2.了解转换器的精度 技术细节 小结 概要 提示&#xff1a;这里可以添加技术概要 本文主要熟悉一些基本概念。随笔&#xff0c;加一些网上用语&#xff0c;只做学习之用&#xff0c;不用深入分析。 整体架构流程 提…

早年黑网吧特供游戏《血战上海滩》如何在Win10运行?

昨天发了一个读者讨论 image 有读者留言&#xff0c;国产游戏《血战上海滩》也是很好玩的射击游戏作品&#xff1b; image-20201017211847416 《血战上海滩》运行在Win10的教程 由于《血战上海滩》年代久远&#xff0c;即使能找到安装包&#xff0c;也很难在Win10 运行了&#…

用VS开发一款“飞机大战“单机游戏<C++>

显示界面如上图所示 自己找的背景和飞机素材,先将素材奉上. 接下来我先简单分析一下这个单机游戏的运行逻辑: 就像显示界面所显示的那样,我们想要实现的是自己的飞机在发射子弹(子弹在上图没显示),然后当子弹射到敌方飞机,这里设置了两种类型的飞机,如果读者想定义更多类型的…