高效快捷解决一个TextView显示多种字体的控件SpannableTextView

这个控件本人强烈推荐,它会使得布局非常的简单且高效; 
下面这个布局如果是你,你会用多少层?多少控件生成?

告诉你吧,一个SpannableTextView控件就搞定了!

它把TextView和Spannable封装在了一起,可以在一个TextView中显示不同的字体颜色,大小,背景色等; 
它支持如下样式:

* Babushka Method      Internal Span 
*     textSize            AbsoluteSizeSpan 
*     textColor           ForegroundColorSpan 
*     textSizeRelative    RelativeSizeSpan 
*     backgroundColor     BackgroundColorSpan 
*     style               StyleSpan 
*     underline           UnderlineSpan 
*     strike              StrikethroughSpan 
*     superscript         SuperscriptSpan 
*     subscript           SubscriptSpan

用法也很简单:

Java代码  

  1. /**
  2. * 为一个TextView设置多种字体(大小,颜色,背景色等)
  3. *
  4. * @param tv
  5. * @param title
  6. * @param content
  7. */
  8. public void createSpannableTextView(SpannableTextView tv, String title, String content)
  9. {
  10. // clear pieces
  11. tv.reset();
  12. // Add the first piece
  13. tv.addPiece(new SpannableTextView.Piece.Builder(title).textColor(App.res.getColor(R.color.text_color_c2))
  14. .textSize((int) App.res.getDimension(R.dimen.font_xbig)).build());
  15. // Add the second piece
  16. tv.addPiece(new SpannableTextView.Piece.Builder(content).textColor(App.res.getColor(R.color.text_color_c8))
  17. .textSize((int) App.res.getDimension(R.dimen.font_middle)).build());
  18. // Display the final, styled text
  19. tv.display();
  20. }

Java代码  

  1. SpannableTextView tv = null;
  2. tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView0));
  3. context.createSpannableTextView(tv, "血糖\n", "记录血糖指数");
  4. tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView1));
  5. context.createSpannableTextView(tv, "血压\n", "记录血压指数");
  6. tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView2));
  7. context.createSpannableTextView(tv, "体重\n", "记录体重");
  8. tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView3));
  9. context.createSpannableTextView(tv, "饮食\n", "记录日常饮食");
  10. tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView4));
  11. context.createSpannableTextView(tv, "运动\n", "记录运动时间");

Xml代码  

  1. <cn.tangdada.tangbang.widget.SpannableTextView
  2. android:id="@+id/spannableTextView0"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:layout_gravity="center_vertical"
  6. android:background="@drawable/line_bottom"
  7. android:drawableRight="@drawable/arrow_right"
  8. android:drawableLeft="@drawable/icon_0"
  9. android:gravity="center_vertical"
  10. android:lineSpacingExtra="4dp"
  11. android:paddingRight="16dp"
  12. android:singleLine="false" />

源码:

Java代码  

  1. package cn.tangdada.tangbang.widget;
  2. /*
  3. * Copyright (C) 2014 Henrique Boregio.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. *      http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * @author Henrique Boregio ([email protected])
  18. */
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import android.content.Context;
  22. import android.graphics.Color;
  23. import android.graphics.Typeface;
  24. import android.text.Spannable;
  25. import android.text.SpannableString;
  26. import android.text.style.AbsoluteSizeSpan;
  27. import android.text.style.BackgroundColorSpan;
  28. import android.text.style.ForegroundColorSpan;
  29. import android.text.style.RelativeSizeSpan;
  30. import android.text.style.StrikethroughSpan;
  31. import android.text.style.StyleSpan;
  32. import android.text.style.SubscriptSpan;
  33. import android.text.style.SuperscriptSpan;
  34. import android.text.style.UnderlineSpan;
  35. import android.util.AttributeSet;
  36. import android.widget.TextView;
  37. /**
  38. * usage:
  39. *
  40. * <pre>
  41. * SpannableTextView tv = (SpannableTextView) findViewById(R.id.spannable_textview);
  42. *
  43. * // Add the first piece &quot;Central Park&quot;
  44. * tv.addPiece(new SpannableTextView.Piece.Builder(&quot;Central Park, NY\n&quot;).textColor(Color.parseColor(&quot;#414141&quot;)).build());
  45. *
  46. * // Add the second piece &quot;1.2 mi&quot;
  47. * tv.addPiece(new SpannableTextView.Piece.Builder(&quot;1.2 mi &quot;).textColor(Color.parseColor(&quot;#0081E2&quot;)).textSizeRelative(0.9f).build());
  48. *
  49. * // Add the third piece &quot;from here&quot;
  50. * tv.addPiece(new SpannableTextView.Piece.Builder(&quot;from here&quot;).textColor(Color.parseColor(&quot;#969696&quot;)).textSizeRelative(0.9f).build());
  51. *
  52. * // Display the final, styled text
  53. * tv.display();
  54. * </pre>
  55. *
  56. * <pre>
  57. * // grab the Piece at position 1
  58. * Piece piece = babushka.getPiece(1);
  59. *
  60. * // modify it‘s text
  61. * piece.setText(&quot;1.9 km &quot;);
  62. *
  63. * // you must always call display after you alter a Piece‘s text
  64. * tv.display();
  65. * </pre>
  66. *
  67. * <pre>
  68. * Babushka Method      Internal Span
  69. *     textSize            AbsoluteSizeSpan
  70. *     textColor           ForegroundColorSpan
  71. *     textSizeRelative    RelativeSizeSpan
  72. *     backgroundColor     BackgroundColorSpan
  73. *     style               StyleSpan
  74. *     underline           UnderlineSpan
  75. *     strike              StrikethroughSpan
  76. *     superscript         SuperscriptSpan
  77. *     subscript           SubscriptSpan
  78. * </pre>
  79. *
  80. * BabushkaText is a TextView which lets you customize the styling of parts of your text via Spannables, but without the
  81. * hassle of having to deal directly with Spannable themselves.
  82. *
  83. * The idea behind a BabushkaText is that it is made up of {@code Piece}s. Each Piece represents a section of the final
  84. * text displayed by this TextView, and each Piece may be styled independently from the other Pieces. When you put it
  85. * all together, the final results is still a a single TextView, but with a a very different graphic output.
  86. *
  87. *
  88. * https://github.com/quiqueqs/BabushkaText
  89. */
  90. public class SpannableTextView extends TextView
  91. {
  92. // some default params
  93. private static int DEFAULT_ABSOLUTE_TEXT_SIZE;
  94. private static float DEFAULT_RELATIVE_TEXT_SIZE = 1;
  95. private List<Piece> mPieces;
  96. /**
  97. * Create a new instance of a this class
  98. *
  99. * @param context
  100. */
  101. public SpannableTextView(Context context)
  102. {
  103. super(context);
  104. init();
  105. }
  106. public SpannableTextView(Context context, AttributeSet attrs)
  107. {
  108. super(context, attrs);
  109. init();
  110. }
  111. public SpannableTextView(Context context, AttributeSet attrs, int defStyleAttr)
  112. {
  113. super(context, attrs, defStyleAttr);
  114. init();
  115. }
  116. private void init()
  117. {
  118. mPieces = new ArrayList<Piece>();
  119. SpannableTextView.DEFAULT_ABSOLUTE_TEXT_SIZE = (int) getTextSize();
  120. }
  121. /**
  122. * Use this method to add a {@link SpannableTextView.BabushkaText.Piece} to a BabushkaText. Each
  123. * {@link SpannableTextView.BabushkaText.Piece } is added sequentially, so the order you call this method matters.
  124. *
  125. * @param aPiece the Piece
  126. */
  127. public void addPiece(Piece aPiece)
  128. {
  129. mPieces.add(aPiece);
  130. }
  131. /**
  132. * Adds a Piece at this specific location. The underlying data structure is a {@link java.util.List}, so expect the
  133. * same type of behaviour.
  134. *
  135. * @param aPiece the Piece to add.
  136. * @param location the index at which to add.
  137. */
  138. public void addPiece(Piece aPiece, int location)
  139. {
  140. mPieces.add(location, aPiece);
  141. }
  142. /**
  143. * Replaces the Piece at the specified location with this new Piece. The underlying data structure is a
  144. * {@link java.util.List}, so expect the same type of behaviour.
  145. *
  146. * @param newPiece the Piece to insert.
  147. * @param location the index at which to insert.
  148. */
  149. public void replacePieceAt(int location, Piece newPiece)
  150. {
  151. mPieces.set(location, newPiece);
  152. }
  153. /**
  154. * Removes the Piece at this specified location. The underlying data structure is a {@link java.util.List}, so
  155. * expect the same type of behaviour.
  156. *
  157. * @param location the index of the Piece to remove
  158. */
  159. public void removePiece(int location)
  160. {
  161. mPieces.remove(location);
  162. }
  163. /**
  164. * Clear all the Pieces, same as reset()
  165. */
  166. public void clearPiece()
  167. {
  168. mPieces.clear();
  169. }
  170. /**
  171. * Get a specific {@link SpannableTextView.BabushkaText.Piece} in position index.
  172. *
  173. * @param location position of Piece (0 based)
  174. * @return Piece o null if invalid index
  175. */
  176. public Piece getPiece(int location)
  177. {
  178. if (location >= 0 && location < mPieces.size())
  179. {
  180. return mPieces.get(location);
  181. }
  182. return null;
  183. }
  184. /**
  185. * Call this method when you‘re done adding {@link SpannableTextView.BabushkaText.Piece}s and want this TextView to
  186. * display the final, styled version of it‘s String contents.
  187. *
  188. * You MUST also call this method whenever you make a modification to the text of a Piece that has already been
  189. * displayed.
  190. */
  191. public void display()
  192. {
  193. // generate the final string based on the pieces
  194. StringBuilder builder = new StringBuilder();
  195. for (Piece aPiece : mPieces)
  196. {
  197. builder.append(aPiece.text);
  198. }
  199. // apply spans
  200. int cursor = 0;
  201. SpannableString finalString = new SpannableString(builder.toString());
  202. for (Piece aPiece : mPieces)
  203. {
  204. applySpannablesTo(aPiece, finalString, cursor, cursor + aPiece.text.length());
  205. cursor += aPiece.text.length();
  206. }
  207. // set the styled text
  208. setText(finalString);
  209. }
  210. private void applySpannablesTo(Piece aPiece, SpannableString finalString, int start, int end)
  211. {
  212. if (aPiece.subscript)
  213. {
  214. finalString.setSpan(new SubscriptSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  215. }
  216. if (aPiece.superscript)
  217. {
  218. finalString.setSpan(new SuperscriptSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  219. }
  220. if (aPiece.strike)
  221. {
  222. finalString.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  223. }
  224. if (aPiece.underline)
  225. {
  226. finalString.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  227. }
  228. // style
  229. finalString.setSpan(new StyleSpan(aPiece.style), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  230. // absolute text size
  231. finalString.setSpan(new AbsoluteSizeSpan(aPiece.textSize), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  232. // relative text size
  233. finalString.setSpan(new RelativeSizeSpan(aPiece.textSizeRelative), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  234. // text color
  235. finalString.setSpan(new ForegroundColorSpan(aPiece.textColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  236. // background color
  237. if (aPiece.backgroundColor != -1)
  238. {
  239. finalString.setSpan(new BackgroundColorSpan(aPiece.backgroundColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  240. }
  241. }
  242. /**
  243. * Resets the styling of this view and sets it‘s content to an empty String.
  244. */
  245. public void reset()
  246. {
  247. mPieces = new ArrayList<Piece>();
  248. setText("");
  249. }
  250. /**
  251. * Change text color of all pieces of textview.
  252. */
  253. public void changeTextColor(int textColor)
  254. {
  255. for (Piece mPiece : mPieces)
  256. {
  257. mPiece.setTextColor(textColor);
  258. }
  259. display();
  260. }
  261. /**
  262. * A Piece represents a part of the text that you want to style. Say for example you want this BabushkaText to
  263. * display "Hello World" such that "Hello" is displayed in Bold and "World" is displayed in Italics. Since these
  264. * have different styles, they are both separate Pieces.
  265. *
  266. * You create a Piece by using it‘s {@link SpannableTextView.BabushkaText.Piece.Builder}
  267. *
  268. */
  269. public static class Piece
  270. {
  271. private String text;
  272. private int textColor;
  273. private final int textSize;
  274. private final int backgroundColor;
  275. private final float textSizeRelative;
  276. private final int style;
  277. private final boolean underline;
  278. private final boolean superscript;
  279. private final boolean strike;
  280. private final boolean subscript;
  281. public Piece(Builder builder)
  282. {
  283. this.text = builder.text;
  284. this.textSize = builder.textSize;
  285. this.textColor = builder.textColor;
  286. this.backgroundColor = builder.backgroundColor;
  287. this.textSizeRelative = builder.textSizeRelative;
  288. this.style = builder.style;
  289. this.underline = builder.underline;
  290. this.superscript = builder.superscript;
  291. this.subscript = builder.subscript;
  292. this.strike = builder.strike;
  293. }
  294. /**
  295. * Sets the text of this Piece. If you‘re creating a new Piece, you should do so using it‘s
  296. * {@link SpannableTextView.BabushkaText.Piece.Builder}.
  297. *
  298. * Use this method if you want to modify the text of an existing Piece that is already displayed. After doing
  299. * so, you MUST call {@code display()} for the changes to show up.
  300. *
  301. * @param text the text to display
  302. */
  303. public void setText(String text)
  304. {
  305. this.text = text;
  306. }
  307. /**
  308. * Sets the text color of this Piece. If you‘re creating a new Piece, you should do so using it‘s
  309. * {@link SpannableTextView.BabushkaText.Piece.Builder}.
  310. *
  311. * Use this method if you want to change the text color of an existing Piece that is already displayed. After
  312. * doing so, you MUST call {@code display()} for the changes to show up.
  313. *
  314. * @param color of text (it is NOT android Color resources ID, use getResources().getColor(R.color.colorId) for
  315. *            it)
  316. */
  317. public void setTextColor(int textColor)
  318. {
  319. this.textColor = textColor;
  320. }
  321. /**
  322. * Builder of Pieces
  323. */
  324. public static class Builder
  325. {
  326. // required
  327. private final String text;
  328. // optional
  329. private int textSize = DEFAULT_ABSOLUTE_TEXT_SIZE;
  330. private int textColor = Color.BLACK;
  331. private int backgroundColor = -1;
  332. private float textSizeRelative = DEFAULT_RELATIVE_TEXT_SIZE;
  333. private int style = Typeface.NORMAL;
  334. private boolean underline = false;
  335. private boolean strike = false;
  336. private boolean superscript = false;
  337. private boolean subscript = false;
  338. /**
  339. * Creates a new Builder for this Piece.
  340. *
  341. * @param text the text of this Piece
  342. */
  343. public Builder(String text)
  344. {
  345. this.text = text;
  346. }
  347. /**
  348. * Sets the absolute text size.
  349. *
  350. * @param textSize text size in pixels
  351. * @return a Builder
  352. */
  353. public Builder textSize(int textSize)
  354. {
  355. this.textSize = textSize;
  356. return this;
  357. }
  358. /**
  359. * Sets the text color.
  360. *
  361. * @param textColor the color
  362. * @return a Builder
  363. */
  364. public Builder textColor(int textColor)
  365. {
  366. this.textColor = textColor;
  367. return this;
  368. }
  369. /**
  370. * Sets the background color.
  371. *
  372. * @param backgroundColor the color
  373. * @return a Builder
  374. */
  375. public Builder backgroundColor(int backgroundColor)
  376. {
  377. this.backgroundColor = backgroundColor;
  378. return this;
  379. }
  380. /**
  381. * Sets the relative text size.
  382. *
  383. * @param textSizeRelative relative text size
  384. * @return a Builder
  385. */
  386. public Builder textSizeRelative(float textSizeRelative)
  387. {
  388. this.textSizeRelative = textSizeRelative;
  389. return this;
  390. }
  391. /**
  392. * Sets a style to this Piece.
  393. *
  394. * @param style see {@link android.graphics.Typeface}
  395. * @return a Builder
  396. */
  397. public Builder style(int style)
  398. {
  399. this.style = style;
  400. return this;
  401. }
  402. /**
  403. * Underlines this Piece.
  404. *
  405. * @return a Builder
  406. */
  407. public Builder underline()
  408. {
  409. this.underline = true;
  410. return this;
  411. }
  412. /**
  413. * Strikes this Piece.
  414. *
  415. * @return a Builder
  416. */
  417. public Builder strike()
  418. {
  419. this.strike = true;
  420. return this;
  421. }
  422. /**
  423. * Sets this Piece as a superscript.
  424. *
  425. * @return a Builder
  426. */
  427. public Builder superscript()
  428. {
  429. this.superscript = true;
  430. return this;
  431. }
  432. /**
  433. * Sets this Piece as a subscript.
  434. *
  435. * @return a Builder
  436. */
  437. public Builder subscript()
  438. {
  439. this.subscript = true;
  440. return this;
  441. }
  442. /**
  443. * Creates a {@link SpannableTextView.BabushkaText.Piece} with the customized parameters.
  444. *
  445. * @return a Piece
  446. */
  447. public Piece build()
  448. {
  449. return new Piece(this);
  450. }
  451. }
  452. }
  453. }

试着结合这个类Phrase.java那就更爽了; 
ColorPhrase实现处理带颜色的字符串 
https://github.com/THEONE10211024/ColorPhrase

https://github.com/quiqueqs/BabushkaText

Spanny实现字符串样式处理 
https://github.com/binaryfork/Spanny

时间: 2024-10-05 07:15:25

高效快捷解决一个TextView显示多种字体的控件SpannableTextView的相关文章

一个TextView显示多种字体

String str="0000000000000000000000000000000"; SpannableStringBuilder ssb=new SpannableStringBuilder(str); ssb.setSpan(new ForegroundColorSpan(Color.RED),0,22, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); mHolder.home_renqi_content.setText(ssb); 用到了spann

扩展GridView实现的一个自定义无刷新分页,排序,支持多种数据源的控件TwfGridView

最近项目View层越来越趋向于无刷新化,特别是数据展示方面,还要对Linq有很好的支持.在WebFrom模式的开发中,GridView是一个功能很强大,很常用的控件,但是他也不是完美的,没有自带的无刷新和排序(有人说UpdatePanel或第三方插件就可以实现无刷新,但是呵呵...那是重量级的无刷新实现,相信不少朋友和我一样讨厌UpdatePanel,引入一大堆很长的js库且不说,用起来感觉不到一点无刷新带来的快速),也不支持部分数据绑定分页(有人说部分数据绑定也可以用aspNetPager等第

WebBrowser无法显示招商银行密码输入控件的问题

本文由CharlesSimonyi发表于CSDN博客:http://blog.csdn.net/charlessimonyi/article/details/30479131转载请注明出处 之前就看到CSDN论坛上有人提问,自己写的程序中的WebBrowser打开招商银行的登录页面后(https://pbnj.ebank.cmbchina.com/CmbBank_GenShell/UI/GenShellPC/Login/Login.aspx),无法显示密码输入控件,但是在IE中可以正常显示. 后

WebBrowser无法显示招商银行password输入控件的问题

本文由CharlesSimonyi发表于CSDN博客:http://blog.csdn.net/charlessimonyi/article/details/30479131转载请注明出处 之前就看到CSDN论坛上有人提问.自己写的程序中的WebBrowser打开招商银行的登录页面后(https://pbnj.ebank.cmbchina.com/CmbBank_GenShell/UI/GenShellPC/Login/Login.aspx),无法显示password输入控件,可是在IE中能够正

一个Activity掌握Android5.0新控件 (转)

原文地址:http://blog.csdn.net/lavor_zl/article/details/51279386 谷歌在推出Android5.0的同时推出了一些新控件,Android5.0中最常用的新控件有下面5种. 1. CardView(卡片视图) CardView顾名思义是卡片视图,它继承FrameLayout.它是一个带圆角的背景和阴影FrameLayout.CardView被包装为一种布局,并且经常在ListView和RecyclerView的Item布局中,作为容器使用. Ca

解决Android中,禁止ScrollView内的控件改变之后自动滚动

问题: 最近在写一个程序界面,有一个scrollVIew,其中有一段内容是需要在线加载的. 当内容加载完成后,ScrollView中内容的长度会发生改变,这时ScrollView会自动下滚,如下图所示: 滚动的那一下体验特别不好,所以要防止这种情况.即不论Scrollview中内容如何,都要保持在最上. 解决办法: 先简单写一下我的xml文件的结构: [html] view plaincopy <ScrollView android:id="@+id/scrollView1" a

一个Activity掌握Android4.0新控件 (转)

原文地址:http://blog.csdn.net/lavor_zl/article/details/51261380 谷歌在推出Android4.0的同时推出了一些新控件,Android4.0中最常用的新控件有下面5种. 1. Switch的使用 Switch顾名思义,就是开关的意思,有开和关两种状态. 当Switch处于关闭状态时: 当Switch处于打开状态时: 怎么在定义xml中定义Switch <Switch android:id="@+id/_switch" andr

如何在XAF中显示自定义窗体和控件

https://www.devexpress.com/Support/Center/Example/Details/E911 如何在XAF中显示自定义窗体和控件,布布扣,bubuko.com

解决tableView中cell动态加载控件的重用问题

tableView的cell,有时候需要在运行时取得对应的数据后才能够动态的创建该cell中的控件并加载到该cell中,此时,你一定会遇到重用问题,即使你能做到该cell只根据数值加载了一回控件,你也没法保证不出现重用问题:) 效果(请注意查看,移动下面的格子时,上面出现了重用的问题) 源码: YXCell.h // // YXCell.h // YXTableView // // Copyright (c) 2014年 Y.X. All rights reserved. // #import