188博金宝电子体育频道Android改进的本地化与自定义TextView效果

我们已经开始了使我们的应用程序更加国际化友好的过程。这通常需要删除所有硬编码字符串,并用对string.xml在翻译的过程中,这是一个很好的开始。当然,在发布翻译后的应用程序之前,还有许多不同的问题需要解决,如字符串格式、字符串连接、复数、图像文本等。
图片中的文字是我们在OkCupid翻译项目中遇到的一个问题。188bet金宝搏官网在某些情况下,图像中的文本可以被替换为另一种更具表现力且不需要任何文字的图像。但有时我们需要给文本添加一些特殊效果,这样它就能在用户面前突出,也能正确地本地化。这篇文章将展示一个应用于文本的挤压效果的例子,然后集成到应用程序作为图像,以及它是如何被常规替换的TextView这很容易翻译。

这个问题

目标是显示一个具有挤压效果的文本,并且它还应该适用于不同的语言。就像这样。

一种解决方案是使用带有挤压效果的自定义字体,但这不适用于不同语言的字符。自定义字体必须指定字体应用时每个字符的外观。如果字体不能处理字符,那么Android的默认字体将只用于该字符。188博金宝电子体育频道此外,我们应该记住,有些亚洲语言没有传统的字母,将自定义字体应用到这些语言可能很困难。自定义TextView在我们的例子中,在文本后面绘制挤压效果是一个更好、更快、更可扩展的解决方案。我们对自定义也有更多的控制TextView它允许我们调整颜色、挤压方向和挤压深度。

解决方案

让我们创建一个扩展的类AppCompatTextView和覆盖onDraw ()方法

@JvmOverloads构造函数(
背景:背景下,
attrs: AttributeSet ?=零,
defStyleAttr: Int = 0
): AppCompatTextView(context, attrs, defStyleAttr) {
.........
override fun onDraw(canvas: canvas ?) {super.onDraw(canvas)}

这里的想法是多次绘制相同的文本,每次绘制文本时移动x和y位置,以产生挤出效果。首先,我们会得到TextView描绘对象。这是一个定义要绘制的文本样式的对象,它负责更改文本大小、文本颜色、字体等。我们将使用一个油漆对象,改变文本颜色(所有其他文本属性将被保留),并只是绘制文本多次。

@JvmOverloads构造函数(
背景:背景下,
attrs: AttributeSet ?=零,
defStyleAttr: Int = 0
): AppCompatTextView(context, attrs, defStyleAttr) {
.....
val extrudeColor =颜色。黑色的
val extrudeDepth = 10

override fun onDraw(canvas: canvas ?) {
super.onDraw(帆布)

油漆颜色= extrudeColor
帆布? .save ()

dx = 1f
Val dy = -1f

//绘制相同的文本多次移动x和y位置
for (i in 0..extrudeDepth) {
帆布吗?。翻译(dx, dy)
布局却是(帆布)

帆布? .restore ()

dxdy指定我们想要移动的距离,在本例中为1像素。+/-符号表示移动的方向。

Dx = 1f向右移动

Dx = -1f向左移动

Dy = 1f向下移动

Dy = -1f向上移动

canvas.save ()帮助我们在进行任何操作(如翻译)之前保存画布的状态。帆布? .restore ()恢复画布的状态。布局是另一个特性TextView用来显示文本的
现在,当我们完成了拉伸效果的绘制,我们需要用原始颜色绘制文本,然后给文本添加一个笔触。

val strokeWidth = 2f
val strokeColor =颜色。红色的

override fun onDraw(canvas: canvas ?) {
super.onDraw(帆布)

val originalTextColor =油漆颜色
油漆
颜色= extrudeColor
帆布? .save ()

........

//用原始颜色绘制文本
油漆
.setColor (originalTextColor)
布局却是(帆布)

//在文本周围添加描边
油漆
.setColor (strokeColor)
油漆风格= Paint.Style.STROKE
油漆strokeWidth= strokeWidth
布局却是(帆布)

帆布? .restore ()

这一切都很好,但仍然有一个小问题。我们正在绘制从左下到右上的对角线挤压效果。越大extrudeDepth风险越高TextView将被画出边界,在右边和顶部边缘看起来被切断了。为了解决这个问题,我们需要向视图添加一些额外的填充,以确保没有任何东西被截断。

@JvmOverloads构造函数(
背景:背景下,
attrs: AttributeSet ?=零,
defStyleAttr: Int = 0
): AppCompatTextView(context, attrs, defStyleAttr) {

init {
addExtraPadding ()


.....

private fun adddextrapadd () {
setPadding (
paddingStart
paddingTop+ extrudeDepth,
paddingEnd+ extrudeDepth,
paddingBottom


我们还应该考虑到一些语言有从右到左的文本方向,所以我们需要添加更多的逻辑来处理这种情况。首先,让我们确定布局方向。这可以使用下面的代码片段来完成

Val config = context.resources.configuration
val isRtl =配置。layoutDirection= =视图。LAYOUT_DIRECTION_RTL

我们可以使用isRtl标记来确定挤压的方向(在本例中,RTL将从右下角到左上角绘制),以及在哪条边上设置填充。

@JvmOverloads构造函数(
背景:背景下,
attrs: AttributeSet ?=零,
defStyleAttr: Int = 0
): AppCompatTextView(context, attrs, defStyleAttr) {

override fun onDraw(canvas: canvas ?) {
super.onDraw(帆布)
.....
//基于RTL改变挤出方向
val dx = if (isRtl) -1f else 1f
Val dy = -1f

//绘制相同的文本多次移动x和y位置
for (i in 0..extrudeDepth) {
帆布吗?。翻译(dx, dy)
布局却是(帆布)

......



private fun adddextrapadd () {
val配置=上下文资源配置
isRtl =配置。layoutDirection= =视图。LAYOUT_DIRECTION_RTL
如果(isRtl) {
//在右向左开始是在右边
setPadding (
paddingEnd+ extrudeDepth,
paddingTop+ extrudeDepth,
paddingStart
paddingBottom

其他}{
setPadding (
paddingStart
paddingTop+ extrudeDepth,
paddingEnd+ extrudeDepth,
paddingBottom



这里有一些不同语言的例子。

我们还可以用Android伪本地化测试视图(更多信息)188博金宝电子体育频道在这里),这在任何国际化项目中都非常有用。伪本地化将模拟应用程序有翻译的场景。通过添加

188博金宝电子体育频道android {
...
buildTypes {
调试{
pseudoLocalesEnabled真实

将语言改为英语(XA),字符串从string.xml将变成带有奇怪字符的字符串。这些字符看起来像英文字母,但在它们上面也有一些额外的符号。每个字符串的长度将通过连接占位符文本来增加。硬编码的字符串不会改变。伪本地化允许开发人员发现任何与翻译相关的UI问题,并在添加真正的翻译之前发现任何硬编码字符串。

现在我们有一个TextView使用任何语言都可以使用的挤出效果,并且可以很容易地本地化。我们还可以用所有的TextView属性,如textSize, fontFamily,字母间距,行间距,重力等,它不会破坏我们的挤出效果。我们还可以添加一些自定义属性来进行更多的自定义。这里是所有的代码在一起和前后比较

想从事像这样很酷的项目吗?我们正在招聘Android工188博金宝电子体育频道程师!应用在今天https://www.188bet金宝搏官网okcupid.com/careers

左边是ImageView,右边是TextView
@JvmOverloads构造函数(
背景:背景下,
attrs: AttributeSet ?=零,
defStyleAttr: Int = 0
): AppCompatTextView(context, attrs, defStyleAttr) {

var extrudeDepth: Int = 0
集(值){
=值
addExtraPadding ()
refreshLayout ()

var extrudeColor: Int =颜色。黑色的
集(值){
=值
refreshLayout ()


var strokeWidth:浮动= 0f
集(值){
=值
refreshLayout ()

var strokeColor: Int =颜色。白色
集(值){
=值
refreshLayout ()

private var isRtl: Boolean = false

init {
addExtraPadding ()

context.theme.obtainStyledAttributes (
attrs,
R.styleable.ExtrudeEffect,
0,0
)苹果

尝试{
extrudeDepth = getInt (R.styleable。ExtrudeEffect_extrudeDepth, 0)
(R.styleable extrudeColor =色鬼。ExtrudeEffect_extrudeColor Color.BLACK)
strokeWidth = getFloat (R.styleable。ExtrudeEffect_textStrokeWidth 0 f)
(R.styleable strokeColor =色鬼。ExtrudeEffect_textStrokeColor Color.WHITE)
最后}{
回收()




override fun onDraw(canvas: canvas ?) {
super.onDraw(帆布)

//保存原始文本颜色,因为TextPaint将更改为绘制阴影和描边
val originalTextColor = paint.color
油漆。颜色= extrudeColor

帆布? .save ()

//考虑视图上的填充设置
val translateX = if (isRtl
帆布? .translate (translateX.toFloat (), paddingTop.toFloat ())

//基于RTL改变挤出方向
val dx = if (isRtl) -1f else 1f
Val dy = -1f

//绘制相同的文本多次移动x和y位置
for (i in 0..extrudeDepth) {
帆布吗?。翻译(dx, dy)
layout.draw(帆布)


//用原始颜色绘制文本
paint.setColor (originalTextColor)
layout.draw(帆布)

//在文本周围添加描边
paint.setColor (strokeColor)
油漆。风格= Paint.Style.STROKE
油漆。strokeWidth = strokeWidth
layout.draw(帆布)

//恢复原始状态
油漆。颜色= originalTextColor
油漆。风格= Paint.Style.FILL
帆布? .restore ()


private fun adddextrapadd () {
Val config = context.resources.configuration
isRtl =配置。布局Direction == View.LAYOUT_DIRECTION_RTL
如果(isRtl) {
//在右向左开始是在右边
setPadding (
paddingEnd + extrudeDepth,
paddingTop + extrudeDepth,
paddingStart,
paddingBottom

其他}{
setPadding (
paddingStart,
paddingTop + extrudeDepth,
paddingEnd + extrudeDepth,
paddingBottom




private fun refreshLayout() {
无效()
requestLayout ()


/ / src / main / res / / attrs.xml值
< declare-styleable name = " ExtrudeEffect " >
= < attr name = " extrudeDepth "格式"整" / >
= < attr name = " extrudeColor "格式"参考|色" / >
= < attr name = " textStrokeWidth "格式"浮" / >
= < attr name = " textStrokeColor "格式"参考|色" / >
< / declare-styleable >

/ /布局
< com.example.shadoweffect.ExtrudeEffectText
188博金宝电子体育频道android: layout_width = " wrap_content "
188博金宝电子体育频道android: layout_height = " wrap_content "
188博金宝电子体育频道android: textSize = " 20 sp”
188博金宝电子体育频道android:输入textColor = " # 000 "
188博金宝电子体育频道android:文本=“Hello world !”
应用:extrudeDepth =“7”
应用:extrudeColor = " @color / colorAccent”
应用:textStrokeWidth =“2”
应用:textStrokeColor = " @color /黄”
188博金宝电子体育频道android: fontFamily = " @font / gt_america_black " / >

最初发表在118bet金博宝 2020年8月28日。

188bet金宝搏官网OkCupid科技博客

阅读来自OkCupid工程团队的故事,每天连188bet金宝搏官网接着数百万人

安东Begeima

写的

188博金宝电子体育频道Android开发者@OkCupid188bet金宝搏官网

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid的工程团队负责每天为数百万人配对。在OkCupid科技博客上阅读他们的故事188bet金宝搏官网

安东Begeima

写的

188博金宝电子体育频道Android开发者@OkCupid188bet金宝搏官网

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid的工程团队负责每天为数百万人配对。在OkCupid科技博客上阅读他们的故事188bet金宝搏官网