我们已经开始使我们的应用程序更加国际化友好的过程。这通常需要全部拆除硬编码字符串,并与参考替换它们string.xml。只是这样做,仅仅将在翻译项目的良好起点。当然有不同的问题,需要一个翻译应用之前必须解决的一堆得以释放,像字符串格式化,字符串连接,复数,图片中的文字等。
图片中的文字是我们我们的翻译项目中,这里面临的OkCupid的一个问题。188bet金宝搏官网在某些情况下,图片中的文字可以只用一个不同的形象,是更具有表现力,并且不需要在任何字来代替。但有时我们需要一些特殊的效果添加到文本,以便它代表了用户,也可以适当地本地化。这篇文章中将会显示应用到文本,然后集成到应用程序作为图像的拉伸效果的例子,它是如何与常规更换的TextView可以很容易地转换。

问题

我们的目标是显示将有挤出效应的文本,它也应该有不同的语言。一些看起来是这样的。

一个解决方案是使用自定义字体具有挤出效应,但是这并不能很好地在不同的语言文字工作。自定义字体,必须指定每个字符的外观在应用字体等。如果字体不处理的字符,然后Android的默认字体将只在该字符使用。188博金宝电子体育频道此外,我们应该记住,一些亚洲语言没有传统的字母,并在这些语言应用自定义字体可以difficult.Custom的TextView这将绘制文本后面的挤压效果更好,更快,更具扩展性在我们的案例的解决方案。我们也有定制更多的控制权的TextView这使我们能够调整色调,拉伸方向,拉伸和深度。

解决方案

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

类ExtrudeEffectText @JvmOverloads构造(背景:语境,ATTRS:?的AttributeSet = NULL,defStyleAttr:INT = 0):AppCompatTextView(上下文,ATTRS,defStyleAttr){.........倍率乐趣的onDraw(帆布:帆布?){super.onDraw(画布)}}

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

类ExtrudeEffectText @JvmOverloads的构造函数(上下文:语境,ATTRS:?的AttributeSet = NULL,defStyleAttr:INT = 0):AppCompatTextView(上下文,ATTRS,defStyleAttr){......... VAL extrudeColor = Color.BLACK VAL extrudeDepth= 10覆盖乐趣的onDraw(帆布:帆布){super.onDraw(画布)paint.color = extrudeColor画布.save()VAL DX = 1F VAL DY = -1f //绘制与移位x和y相同的文字多次?对位置(i中0..extrudeDepth){画布?.translate(DX,DY)layout.draw(画布)}画布?.restore()}}

DXDY指定我们希望在这种情况下,移动的距离为1个像素。+/-迹象表明移动的方向。

DX = 1F向右移动

DX = -1f移动到左侧

DY = 1F向下移动

DY = -1f向上移动

`canvas.save()`可以帮助我们节省画布的状态,我们不喜欢把任何操作之前。帆布?.restore()恢复画布的状态。布局是他人财产的TextView该用于显示文本
现在,当我们正在绘制挤出效应做了,我们需要把我们的文本与原始的颜色,然后中风添加到文本。

VAL strokeWidth = 2F VAL则strokeColor = Color.RED倍率乐趣的onDraw(帆布:帆布){super.onDraw(画布)VAL originalTextColor = paint.color paint.color = extrudeColor画布.save().......//绘制的原始彩色paint.setColor文本(originalTextColor)layout.draw(画布)//加载文本周围paint.setColor(则strokeColor)行程paint.style = Paint.Style.STROKE paint.strokeWidth = strokeWidth layout.draw(帆布)帆布?.restore()}

这一切工作不错,但是还是有点问题。我们正在绘制对角线从左下角到右上角的挤出效应。该说`TextView`将绘制边界和外观切出关右侧和顶部边缘的`extrudeDepth`越高,风险越大。为了解决这个问题,我们需要一些额外的填充添加到视图,以确保没有切断。

类ExtrudeEffectText @JvmOverloads构造(背景:背景下,ATTRS:AttributeSet中的= NULL,defStyleAttr:= 0):AppCompatTextView(背景下,ATTRS,defStyleAttr){{初始化addExtraPadding()} .....私人乐趣addExtraPadding(){setPadding(paddingStart,paddingTop + extrudeDepth,paddingEnd + extrudeDepth,paddingBottom来)}}

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

VAL配置= context.resources.configuration VAL isRtl = config.layoutDirection == View.LAYOUT_DIRECTION_RTL

我们可以使用isRtl标志来确定挤压的方向(在我们的情况下,我们将汲取到顶部右下角放置RTL)和在其上边缘到集填充。

类ExtrudeEffectText @JvmOverloads构造(背景:语境,ATTRS:?的AttributeSet = NULL,defStyleAttr:INT = 0):AppCompatTextView(上下文,ATTRS,defStyleAttr){倍率乐趣的onDraw(帆布:帆布){super.onDraw(画布)。.... //基于RTL VAL DX =如果改变拉伸方向(isRtl)-1f别的1F VAL DY = -1f //使用(在0..extrudeDepthⅰ)移位x和y位置来画出相同的文字多次{帆布?.translate(DX,DY)layout.draw(画布)} ......}私人乐趣addExtraPadding(){VAL配置= context.resources.configuration isRtl = config.layoutDirection == View.LAYOUT_DIRECTION_RTL如果(isRtl) { // in Right to left the start is on the right setPadding( paddingEnd + extrudeDepth, paddingTop + extrudeDepth, paddingStart, paddingBottom ) } else { setPadding( paddingStart, paddingTop + extrudeDepth, paddingEnd + extrudeDepth, paddingBottom ) } } }

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

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

188博金宝电子体育频道安卓{... buildTypes {{调试真正pseudoLocalesEnabled}}

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

现在我们有一个的TextView与挤压与任何语言的作品,可以轻松地本地化效果。我们仍然可以使用所有的的TextView属性,如TEXTSIZE,fontFamily中,letterSpacing一个,lineSpacing,重力等,它不会破坏我们的挤出效应。我们还可以添加一些自定义属性为更多的定制。这里是所有的代码一起,前后对比

想在清凉的项目,如这项工作?我们正在招聘Android的188博金宝电子体育频道工程师!今天在申请https://www.188bet金宝搏官网okcupid.com/careers

类ExtrudeEffectText @JvmOverloads构造(背景:语境,ATTRS:?的AttributeSet = NULL,defStyleAttr:INT = 0):AppCompatTextView(上下文,ATTRS,defStyleAttr){风险extrudeDepth:INT = 0设定(值){字段=值addExtraPadding()refreshLayout()} VAR extrudeColor:INT = Color.BLACK集(值){字段=值refreshLayout()} VAR strokeWidth:浮点= 0F集(值){字段=值refreshLayout()} VAR则strokeColor:INT = Color.WHITE集(值){字段=值refreshLayout()}私人VAR isRtl:布尔= FALSE的init {addExtraPadding()context.theme.obtainStyledAttributes(ATTRS,R.styleable.ExtrudeEffect,0,0)。适用{尝试{extrudeDepth = getInt(R.styleable.ExtrudeEffect_extrudeDepth,0)= extrudeColor的getColor(R.styleable.ExtrudeEffect_extrudeColor,Color.BLACK)strokeWidth = getFloat(R.styleable.ExtrudeEffect_textStrokeWidth,0F)则strokeColor =的getColor(R.styleable.ExtrudeEffect_textStrokeColor,Color.WHITE)}最后{再循环()}}}覆盖有趣的onDraw(帆布:CAN输精管?){super.onDraw(画布)//节省自TextPaint原始文本颜色将改变为绘制阴影和中风VAL originalTextColor = paint.color paint.color = extrudeColor画布?.save()//考虑到填充组在视图VAL平移X =如果(isRtl)paddingEnd别的paddingStart画布?.translate(translateX.toFloat(),paddingTop.toFloat())//基于RTL改变拉伸方向VAL DX =如果(isRtl)-1f别的1F VALDY = -1f //绘制(在0..extrudeDepthⅰ)移位x和y位置为相同的文字多次{画布?.translate(DX,DY)layout.draw(画布)}的原始彩色//绘制文本paint.setColor(originalTextColor)layout.draw(画布)//周围添加文本paint.setColor(则strokeColor)行程paint.style = Paint.Style.STROKE paint.strokeWidth = strokeWidth layout.draw(画布)//复归油漆原始状态paint.color = originalTextColor paint.style = Paint.Style.FILL印刷品吗?.restore()}私人乐趣addExtraPadding(){VAL配置= context.resources.configuration isRtl = config.layoutDirection == View.LAYOUT_DIRECTION_RTL if (isRtl) { // in Right to left the start is on the right setPadding( paddingEnd + extrudeDepth, paddingTop + extrudeDepth, paddingStart, paddingBottom ) } else { setPadding( paddingStart, paddingTop + extrudeDepth, paddingEnd + extrudeDepth, paddingBottom ) } } private fun refreshLayout() { invalidate() requestLayout() } } // src/main/res/values/attrs.xml       // in layout