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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值