[实战笔记]Android文本编辑的一些实用技巧

有一段时间忙碌了,今天就好好总结记录一下这阵子学到的一些小技巧好了。这一篇先记录一下关于文本编辑的小事儿,Here we go!

************************************************

一、插入符号

现在做的项目由于是多语言的,加上刚好遇到需要安卓和ios统一字段的噩梦,因此会特别注意到符号的使用。刚开始在跟做项目的时候,我的工作就是把大佬们之前赶项目进度时直接使用到的文本放进string里进行引用。也许是为了字段内容和IOS的同步,被特意嘱咐了一些符号要单独在代码之中插入字符,而不是在string中带入字符。

1.符号在尾部

如要引用的文本内容为:

当前状态:

那么对应的string中就应该写成:

<string name="current_status">当前状态</string>

然后在代码的文本引用中手动加入冒号:

TextView mStatusTv = (TextView)findViewById(R.id.xxxxxx);
(或者注解写法@BindView(R.id.xxxxxx) TextView mStatusTv;)
mStatusTv.setText(getResource().getString(R.string.current_status) + ":");

2.符号在中间

当我们遇到的文本内容是这样的时候:(为了方便我下面都直接用文字而非引用了,但是一定要注意实际开发的时候要用引用的方式去写)

联系我们:xxxxxxxx

像这种内容不变,直接写死的文本,中间有符号的时候,如无意外我们当然可以直接使用一个字段存起来。但如果要求符号要被提出来的话,下面就是几个不同的方法了。

可以采取两段式引用的方法:

<string name="contact_us">联系我们</string>
<string name="tel">xxxxxxxx</string>

代码中:

mTxet.setText("联系我们"+":"+"xxxxxx");

或者直接写在一个字段之中,使用字符串截取进行符号插入:

<string name="contact_us">联系我们\\xxxxxx</string><!-- 使用了\作为位置占位符,而为了显示出\这个符号,必须使用多一个\进行标识,"等符号同理 -->

代码中:

String str = getResource().getString(R.string.contact_us);
int index = str.indexOf("\\");//得到占位符/所在的位置
str = str.substring(0, index)+":"+str.substring(index+1);
mText.setText(str);

3.配对符号

同理,遇到配对符号也是一样的写法:

生活就像海洋(偷偷插入一下括号),只有意志坚强的人才能到达彼岸。

这种完整的文本我还是比较喜欢写在一个字段中,使用字符串去截取,毕竟后期如果整理string也比较方便嘛。

<string name="dictum">生活就像海洋\\偷偷插入一下括号\\,只有意志坚强的人才能到达彼岸。</string>

代码中:

String str = getResource().getString(R.string.dictum);
int firstIndex = str.indexOf("\\");
int lastIndex = str.lastIndexOf("\\");
str = str.substring(0, firstIndex) + "(" + str.substring(firstIndex+1, lastIndex) + ")" + str.substring(lastIndex+1);
mText.setText(str);

4.转义字符

在string文件中,比较常用到一些用于控制格式或者是无法直接表示出来的符号,我们就会用转义字符去表示。例如英文符的""、\等。这些符号在string资源文件中进行引用的时候是没有办法直接显示出来的,因此在这些字符前使用反斜杠\进行转义后,才能正确的显示出来。

string中:

墙上挂着\"注意安全\"的标志

使用过程中有任何的建议\\或意见

代码中引用string资源后显示:

墙上挂着"注意安全"的标志

使用过程中有任何的建议\或意见


 

另外,想要控制格式,插入空格键、换行、制表符等,也可以使用转义字符达到效果。参考c中常使用的一些转义符:

空格:&#160;

换行:\n

制表符:\t

二、可动态改变固定位置的文本——格式化字符串

有时候我们会遇到这样的问题:设计稿需要我们将数据插入到一段格式固定的文本之中,例如

欢迎您,xxx老师

对于这种文本处理,最初级的做法就是分成两段式写法,也就是:

<string name="welcome">欢迎您,</string>
<string name="teacher">老师</string>

代码中:

mText.setText(getResource().getString(R.string.welcome) + mTeacherName + getResource().getString(R.string.teacher));

这种写法当然也能实现这个效果,但是在有庞大的这种类型文本处理上,多次拼接就比较容易出错。特别是一个文本中有多个动态变量的情况之下,出错率非常高。为了应对这种情况,可以使用格式化string进行动态插入数据。

1.单个动态文本替换格式

假设在一段文本之中,只拥有一个动态变量,则我们可以使用以下写法实现动态插入变量。

<string name="welcome">欢迎您,%s老师</string>

代码中:

mText.setText(getResource().getString(R.string.welcom, mTeacherName));//mTeacherName是String类型的变量。

我们在字段之中插入的%s是一个占位符,简单来说就是一个先在资源中占着地方,然后允许在引用字段资源的时候再放东西进去替换的好东西。%表示类型,%s也就是string类型。此外,还有%d表示整型,%f表示浮点型。

2.多个动态文本替换格式

假设要实现以下文本,按照上一部分的思路,会怎样呢?

欢迎您,a老师。您目前积分是b,等级为c

a、b、c表示三个动态文本,其中ac为string类型,b为int类型。

按照单个文本替换的思路,对应的string字段应该是:

<string name = "welcome">欢迎您,%s老师。您目前积分是%d,等级为%s</string>

而在代码中引用的时候,按照顺序放入对应格式的变量后,编译时AndroidStudio就会报错:


Error:(445) Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?大意就是在非位置格式加入了多个替换,可以理解AndroidStudio并没有按照我们所排好的变量逐一放进对应占位符中。为了实现按照位置将文本替换进对应的占位符中,在多个文本替换的情况之下我们需要使用以下的方式:

<string name = "welcom">欢迎您,%1$s老师。您目前积分是%2$d,等级为%3$s</string>

在%n$s的格式化string中,%s依旧表示字符串类型,而n则表示这个字段将被传入的第几个文本参数所替换。在引用这个字段的时候,规定了传入的第一个参数类型是string,将被替换到%1$s的位置上;传入的第二个参数类型为int,将被替换到%2$d的位置上;传入的第三个参数的类型为string,将被替换到%3$s的位置上。根据这个规则,我们进行试验一下:

<string name = "welcome_1">欢迎您,%1$s老师。您的积分是%2$d,目前等级为%3$s</string>
<string name = "welcome_2">欢迎您,%3$s老师。您的积分是%2$d,目前等级为%1$s</string>

代码中进行引用:

TextView mText1 = (TextView) findViewById(R.id.test1);
TextView mText2 = (TextView) findViewById(R.id.test2);
mText1.setText(getResource().getString(R.string.welcome_1, "111", 222, "333"));
mText2.setText(getResource().getString(R.string.welcome_2, "111", 222, "333"));


这里我们传入一样的数据,运行之后看看效果:


 

这种方式同样适用于单个动态文本替换,因此建议只有一个替换文本的时候也使用这种方式,毕竟统一又好记嘛~

3.空格、留位等更多替换格式

上一部分已经解决了大部分的使用情况了。这里假设我们需要完成以下文本的话,该怎么办呢?

需要支付  236.50  元 (数字与前后文本各间隔2空格距离)

可能想到的字段应该是:

<string name="pay">需要支付  %1$f  元</string><!--手动输入2个空格-->

在代码中进行引用:

TextView test = (TextView)findViewById(R.id.test);
test.setText(getResources().getString(R.string.pay, 236.5));

这时候我们得到的内容是:

即数字前后只有一个空格(在string文件中输入的空格大于1个时只显示1个),数字保留小数点后6位。

第二个想法是,使用转义字符&#160;表示空格,如下:

<string name="pay">需要支付&#160;&#160;%1$f&#160;&#160;元</string>

在代码中进行引用(语句同上),得到内容:


(差别比较小但是还是有差别的!)即数字前后确实两个空格,数字保留小数点后6位。

为了解决这个问题,我们可以使用%n$mf。这个格式表示:类型是%f,即浮点类型;引用时使用传入的第n个参数替换;当m是整数时,表示在数字前空出(m-数字所占长度)数量的空格;当m是小数时,表示在数字前空出(m的整数部分-数字所占长度)数量的空格,小数点后保留(m的小数部分)位。下面用一组对比来加深这个记忆:

<string name="pay1">需要支付%1$f元</string>

<string name="pay2">需要支付%1$6f元</string>
<string name="pay3">需要支付%1$10f元</string>
<string name="pay4">需要支付%1$11f元</string>
<string name="pay5">需要支付%1$12f元</string>

<string name="pay6">需要支付%1$.2f元</string>
<string name="pay7">需要支付%1$6.2f元</string>
<string name="pay8">需要支付%1$8.2f元</string>
<string name="pay9">需要支付%1$10.2f元</string>


当在代码中同样传入参数236.5时,得到的结果如下:

如果使用%n$0mf的话,则在表示是最小有m位,右对齐,多余的左边位置补0。(没有加0的话,是以空格补全)

※注:在代码中引用资源(颜色、尺寸、字符串、图片等)时,都需要通过getResource().getxxx(R.xx.xxx)的格式进行引用。

Activity、Fragment等可以直接拿到上下文对象的:

xx.setText(getResource().getString(R.string.xxxxx));
xx.setColor(getResource().getColor(R.color.xxxxx));


Adapter等这种不能直接引用到资源的,需要引入上下文对象,那我们就可以在构造函数中传入当前的上下文对象context,通过context去引用对应的资源:

xx.setText(context.getResource().getString(R.string.xxxxx));
xx.setColor(context.getResource().getColor(R.color.xxxxx));

三、同一段文本的不同样式——SpannableStringBuilder

在ps、word等可以编辑文本的软件之中,为了强调或者补充说明,经常会有以下效果:

进一步熟悉英文数据库的检索性能与特色。(选做至少2个要求)

加入500ml的水(冷水或者温水),一直搅拌直至完全溶解。

对于这种做法,最初级的处理方法就是文本拼接,毕竟一段文本无论在xml中设置text属性或者是在代码中设置setText,这段文本的统一颜色都取决于textColor属性所取的值。但是使用拼接就会遇到换行、string资源过于零散等问题。

处理同一段文本的不同样式,要使用到的类是SpannableStringBuilder。SpannableStringBuilder是一个内容和样式都可以更改的文本类,并且支持使用append进行内容追加连接、使用insert进行内容插入等。我们先来看看用法。

要实现的效果:

利用MeTeL(国外高校外文多媒体教学资源库),寻找自己所学专业的相关课程,选择一门感兴趣的课程,浏览或下载课程的资源和课件。

string:

<string name="description">利用MeTeL(国外高校外文多媒体教学资源库),寻找自己所学专业的相关课程,选择一门感兴趣的课程,浏览或下载课程的资源和课件。</string>

xml:

<TextView
        android:id="@+id/test1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/description"/>

代码:

        TextView mText = (TextView) findViewById(R.id.test1);
        SpannableStringBuilder mBuilder = new SpannableStringBuilder();
        mBuilder.append(getResources().getString(R.string.description));
        ForegroundColorSpan mColorSpan = new ForegroundColorSpan(Color.parseColor("#ff0000"));
        mBuilder.setSpan(mColorSpan, 7, 23, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        mText.setText(mBuilder);

来看看效果:



上面可以看出来,SpannableStringBuilder的setSpan方法就是用于改变文本样式的。setSpan(Object what, int start, int end, int flags)参数如下:

what——样式

设置不同的Span添加不同的样式。上面使用的ForegroundColorSpan表示的是文本颜色。除此以外还有以下样式:

BackgroundColorSpan ::文本背景色

ForegroundColorSpan:文本颜色

StrikethroughSpan:删除线

UnderlineSpan:下划线

StyleSpan:字体样式:粗体、斜体等

TypefaceSpan :文本字体

还有一些图片、文本缩放、上标下标、超链接、点击事件等不常用的样式,需要的时候可以自行百度。

start——文本样式改变的开始位置

end——文本样式改变的结束位置(不包括这个位置)

start和end的位置形式是[start,end),即只包括前不包括后。

flags——取值如下(使用insert插入的时候起效果)

Spannable. SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括。即当insert的文本的位置在[start,end),也就是start到end-1的范围内时,应用span样式

Spannable. SPAN_INCLUSIVE_INCLUSIVE:前面包括,后面包括。即当insert的文本的位置在[start,end],也就是start到end的范围内时,应用span样式

Spannable. SPAN_EXCLUSIVE_EXCLUSIVE:前面不包括,后面不包括。即当insert的文本的位置在(start,end),也就是start+1到end-1的范围内时,应用span样式

Spannable. SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括。即当insert的文本的位置在(start,end],也就是start+1,end的范围内时,应用span样式

定义一个“0123456789”的字符串资源,并令TextView引用。使用setSpan令第3到6位变成红色。代码及效果如下:

	TextView mText = (TextView) findViewById(R.id.test);
        String str = mText.getText().toString();
        SpannableStringBuilder mBuilder = new SpannableStringBuilder(str);
        ForegroundColorSpan mColorSpan = new ForegroundColorSpan(Color.parseColor("#ff0000"));
        mBuilder.setSpan(mColorSpan, 3, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mText.setText(mBuilder);TextView mText = (TextView) findViewById(R.id.test);
        String str = mText.getText().toString();
        SpannableStringBuilder mBuilder = new SpannableStringBuilder(str);
        ForegroundColorSpan mColorSpan = new ForegroundColorSpan(Color.parseColor("#ff0000"));
        mBuilder.setSpan(mColorSpan, 3, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mText.setText(mBuilder);


现在进行在不同的位置插入字符“-”,对比不同flags参数和不同位置的区别。

使用以上的语句还有一个缺点,就是对于不同的文本,都需要自己确定位置。这时候可以插入标识符,通过str.indexOf()和str.lastIndexOf()定位标识符位置,然后传入到start和end中。具体标识符定位使用回顾一下 [一.4.转义字符] 吧。

四、文本的特殊样式

大部分文本的样式都可以使用xml的设定完成,如文字颜色、文字样式(加粗、斜体)、文字大小、文字类型等等。但是有一些特殊样式是无法在xml中设置的。

1.下划线

下划线在UI稿中时不时都会出现。在实习的过程中,我看到我的同事为了表示下划线,使用了一个竖直的线性布局,里边放入了TextView和一个当作下划线使用的View。对于这种做法我感觉有点多此一举。为了表示出下划线,这里给出两种方法:

使用html标签

在对应的string资源的某个文本中,在需要添加下划线的文本内使用html的下划线标记<u></u>可以令标记内的文字加上下划线,如下:

<string name = "underline"><u>下划线文本</u></string>

也可以在java文件中使用代码和html标签进行设置,如下:

TextView mText = (TextView)findViewById(R.id.underline_text);
mText.setText(Html.fromHtml(<u>+getResource().getString(R.string.undeline)+</u>));+</u>));


使用Paint属性

mText.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);//下划线


设置SpannableStringBuilder/SpannableString类的what属性

String str = mText.getText().toString();
SpannableStringBuilder underline = new SpannableString(str);
underline.setSpan(new UnderLineSpan(), 0, str.length(), Spannable. SPAN_INCLUSIVE_EXCLUSIVE);

2.删除线

在做一个购买页面的时候,接到的UI设计稿使用了删除线表示原价。查询了一下,实现方法基本和上面下划线一致。删除线可以采用以下设置。

使用Paint属性

mText.getPiant().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);//删除线

设置SpannableStringBuilder/SpannableString的what属性

String str = mText.getText().toString();
SpannableStringBuilder underline = new SpannableString(str);
underline.setSpan(new StrikethroughSpan(), 0, str.length(), Spannable. SPAN_INCLUSIVE_EXCLUSIVE);

*********************************************************************************************

很惭愧,这是我实习以来才写完的第一篇实战笔记。平时虽然回到宿舍时间也不多,但是也有一些时间可以写的,也算是懒吧。文本样式编辑这篇笔记,一开始没想到会写这么长,但是一边在写一边查询的时候,发现有很多东西查过了资料之后感觉不够详细,需要自己验证结果,结果越拖越久。总的来说第一篇终于结束啦,很高兴能看我的日常废话,比心心。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值