├── .gitignore
├── .idea
    ├── .name
    ├── compiler.xml
    ├── copyright
    │   └── profiles_settings.xml
    ├── encodings.xml
    ├── gradle.xml
    ├── misc.xml
    ├── modules.xml
    ├── runConfigurations.xml
    └── vcs.xml
├── README.MD
├── StyleTextView.iml
├── app
    ├── .gitignore
    ├── app.iml
    ├── build.gradle
    ├── proguard-rules.pro
    └── src
    │   ├── androidTest
    │       └── java
    │       │   └── com
    │       │       └── siyehua
    │       │           └── styletextview
    │       │               └── ApplicationTest.java
    │   ├── main
    │       ├── AndroidManifest.xml
    │       ├── java
    │       │   └── com
    │       │   │   └── siyehua
    │       │   │       └── styletextview
    │       │   │           ├── DrawLineTextView.java
    │       │   │           ├── MainActivity.java
    │       │   │           └── StyleTextView.java
    │       └── res
    │       │   ├── drawable-xxhdpi
    │       │       ├── abc.png
    │       │       └── ic_launcher.png
    │       │   ├── layout
    │       │       ├── _001.xml
    │       │       ├── _002.xml
    │       │       ├── _003.xml
    │       │       ├── _004.xml
    │       │       └── activity_main.xml
    │       │   ├── mipmap-hdpi
    │       │       └── ic_launcher.png
    │       │   ├── mipmap-mdpi
    │       │       └── ic_launcher.png
    │       │   ├── mipmap-xhdpi
    │       │       └── ic_launcher.png
    │       │   ├── mipmap-xxhdpi
    │       │       └── ic_launcher.png
    │       │   ├── mipmap-xxxhdpi
    │       │       └── ic_launcher.png
    │       │   ├── values-w820dp
    │       │       └── dimens.xml
    │       │   └── values
    │       │       ├── colors.xml
    │       │       ├── dimens.xml
    │       │       ├── strings.xml
    │       │       └── styles.xml
    │   └── test
    │       └── java
    │           └── com
    │               └── siyehua
    │                   └── styletextview
    │                       └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
    └── wrapper
    │   ├── gradle-wrapper.jar
    │   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img
    ├── _001.png
    ├── _002.png
    ├── _003.png
    ├── _004.png
    ├── _005.png
    ├── _006.png
    ├── _007.png
    ├── _008.png
    ├── _009.png
    ├── _011.png
    ├── _012.png
    ├── _013.png
    ├── _100.png
    ├── _101.png
    ├── _102.png
    ├── _103.png
    ├── _104.png
    ├── _105.png
    └── _106.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 | 
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | StyleTextView
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |       
 7 |       
 8 |       
 9 |       
10 |       
11 |       
12 |       
13 |       
14 |       
15 |     
16 |     
17 |       
18 |         
19 |       
20 |     
21 |   
22 | 
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 | 
2 |   
3 | 
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |     
5 |   
6 | 
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
22 |   
23 | 
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |   
 6 |   
 7 |     
 8 |     
 9 |     
10 |       
11 |         
12 |           13 |
14 |
15 |
16 |
17 |       
18 |     
19 |     
20 |       
21 |
22 |           23 |
24 |
25 |
26 |
27 |       
28 |     
29 |   
30 |   
31 |     
32 |     
33 |     
34 |     
35 |     
36 |     
37 |     
38 |     
39 |   
40 |   
41 |     
42 |   
43 |   
44 |     
45 |   
46 |   
47 |     
48 |       
49 |         
50 |           1.7
51 |           
52 |             
53 |
54 |                 
55 |               
56 |             
57 |           
58 |         
59 |       
60 |     
61 |   
62 | 
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |     
5 |       
6 |       
7 |     
8 |   
9 | 
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |       
 6 |         
 7 |         
 8 |         
 9 |       
10 |     
11 |   
12 | 
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |     
5 |   
6 | 
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
  1 | # 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
  2 | 
  3 | # StyleTextView
  4 | 
  5 | ## 本文主要探讨TextView控件绘制文字,上下会留有一定空白原因.以及使用canvas.drawText()绘制文字时,baseLine的该如何确定,如何让文字上下没有留白
  6 | 
  7 | 最近做项目的时候遇到个问题
  8 | 
  9 | 
 10 | 
 11 | 当时的布局是这样的(一言不合就上图,具体代码请点击图片)
 12 | 
 13 | [](/app/src/main/res/layout/_001.xml)
 14 | 
 15 | 什么,这百分号和数字怎么对齐?这数字下面的文字怎么居中?这层级为什么这么复杂,关键外面还有好多层父布局,这是要上天呀!
 16 | 
 17 | 
 18 | 
 19 | ## 解决思路
 20 | 
 21 | 薄荷就是醒脑,表情包还没做完思路就出来.
 22 | 
 23 | * 减少层级,采用一个TextView
 24 | 
 25 | ```xml
 26 | 
 27 |     
 28 |     
 29 |     
 30 | 
 31 | ```
 32 | 
 33 | * 每个TextView的大小,用SpannableString控制其大小和颜色.理论上是很简单的,下面是具体的代码
 34 | 
 35 | [布局](/app/src/main/res/layout/_002.xml)
 36 | 
 37 | 代码:
 38 | 
 39 | ```java
 40 | TextView textView = (TextView) findViewById(R.id._001);
 41 |         String text = new String("60%/n主胜");
 42 |         spannableString = new SpannableString(text);
 43 |         int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources()
 44 |                 .getDisplayMetrics());
 45 |         spannableString.setSpan(new AbsoluteSizeSpan(size), 2, 3, Spanned
 46 |                 .SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体大小
 47 |         spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#FF00FF")), 2, 3,
 48 |                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体颜色
 49 | 
 50 |         int size2 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30, getResources
 51 |                 ().getDisplayMetrics());
 52 |         spannableString.setSpan(new AbsoluteSizeSpan(size2), text.length() - 2, text.length(),
 53 |                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体大小
 54 |         spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#000FFF")), text.length
 55 |                 () - 2, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体颜色
 56 |         textView.setText(spannableString);
 57 | ```
 58 | 
 59 | * 最终效果:
 60 | 
 61 | 
 62 | 
 63 | 
 64 | 
 65 | 实践与理论一样简单,完全不是个事.然后我就兴冲冲的把代码提交了.一切都很顺利,同事还夸我脑子灵活.
 66 | 
 67 | ### 当然故事肯定都没有这么简单的,这么简单也什么好写博客的,毕竟天天都有人夸我.
 68 | 
 69 | ## 事故
 70 | 说到事故,先说个故事.
 71 | 
 72 | APP都有个设计,视觉都会有个美女,自从调来了一个美女视觉之后我干活就有劲了,整天乐不思蜀....
 73 | 
 74 | 
 75 | 
 76 | 美女的脾气都不好,她说这个%号要靠上,不能靠下.
 77 | 
 78 | 我好说歹说,说实现起来不容易呀,如果靠上要用复杂的布局,会影响性能...
 79 | 
 80 | ### 不行,必须靠上!!!
 81 | 
 82 | 整个人都斯巴达了,关键是美女没法发脾气,这才是上层把她调过来的真实目的吗?
 83 | 
 84 | ### 百分号%下对齐的原因
 85 | 
 86 | 百分号之所以下对齐,是因为普通图形的绘制,是从图纸的左上角开始绘制的,而文字的绘制则是从左下角开始的.
 87 | 
 88 | 具体可以看一下canvas.draw图形方法,以及canvas.drawText方法参数.
 89 | 
 90 | 问题是知道的,但是没有办法和设计解释,然而也想出好的方法改变baseLine绘制.
 91 | Google一圈没有答案,群里问了一圈也没有,建议自己定义,看来只好自己动手了.
 92 | 
 93 | 
 94 | ## 思路
 95 | SpannableString基本上是可以满足需求的,关键是画%百分号的时候不满足.
 96 | 
 97 | * 看源码看TextView是如何利用SpannableString画的,覆写其关键代码达到目的
 98 | 
 99 |     源码老复杂了看不懂.看资料SpannableString有一个上标的功能,试了一下上标是相对于本身字体大小来上标的,而60与%相差甚远,且无法微调
100 | 
101 | * 画百分号%的时候自己画(看来只能这个思路了)
102 | 
103 | ### 自定义TextView
104 | * 自定义StyleTextView继承TextView
105 | * 定义类TextStyle
106 | 
107 | ```java
108 | public static class TextStyle {
109 |         String content;
110 |         int size;
111 |         int color;
112 |         boolean up = false;//是否上标
113 | 
114 |         public TextStyle() {
115 |         }
116 | 
117 |         public TextStyle(String content, int size, int color, boolean up) {
118 |             this.content = content;
119 |             this.size = size;
120 |             this.color = color;
121 |             this.up = up;
122 |         }
123 |     }
124 | ```
125 | 
126 | * 定义方法setText.
127 | ```java
128 |   /**
129 |      * 设置Text
130 |      * @param content String
131 |      * @param styles
132 |      */
133 |     public void setText(String content, TextStyle... styles) {
134 |         this.content = content;
135 |         spannableString = new SpannableString(content);
136 |         int i = 0;
137 |         for (TextStyle styleContent : styles) {
138 |             if (i == 0) first = styleContent;
139 |             else if (i == 1) second = styleContent;
140 |             i++;
141 |             int start = content.indexOf(styleContent.content);
142 |             int end = start + styleContent.content.length();
143 |             if (styleContent.size != -1)
144 |                 spannableString.setSpan(new AbsoluteSizeSpan(styleContent.size), start, end,
145 |                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
146 |             if (styleContent.color != -1)
147 |                 spannableString.setSpan(new ForegroundColorSpan(styleContent.color), start, end,
148 |                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
149 |             if (styleContent.up) {//上标时设置颜色为透明色,然后在onDraw自己画
150 |                 spannableString.setSpan(new ForegroundColorSpan(Color.TRANSPARENT), start, end,
151 |                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
152 |             }
153 |         }
154 |         setText(spannableString);
155 |     }
156 | ```
157 | 
158 | * 覆写onDraw方法
159 | 
160 | ```java
161 |  canvas.drawText(content, startX, baseLine, mPaint);
162 | ```
163 | 
164 | ### 到此自定义View完全结束.
165 | 
166 | ## 外传
167 | 
168 | 故事到这里就结束肯定不叫故事.
169 | 
170 | 上面所有的都并非关键,关键是drawText()参数.
171 | 
172 | 之前说了,drawText是从左下角开始画的,所以要计算出startX与baseLine的值.
173 | 
174 | startX:计算出百分号之前的"60"的宽度即可.
175 | 
176 | baseLine:baseLine默认是等于-top(后文证明),但TextView上下有一定的空白,导致直接写-top不满足需求
177 | 
178 | 
179 | 
180 | 图片来源于网络
181 | 
182 | 当文字字号过大时,空白非常的明显.设计要求"60%"百分号与60对齐,所以必须量出空白的高度.
183 | 
184 | ### 测试上图中的各个属性
185 | 
186 | 按照上图的说法,我们打印一下这几个值
187 | 
188 | ```xml
189 |   
195 | ```
196 | ```java
197 |  final TextView textView2 = (TextView) findViewById(R.id._test);
198 |         textView2.setOnClickListener(new View.OnClickListener() {
199 |             @Override
200 |             public void onClick(View v) {
201 |                 Paint mPaint = textView2.getPaint();
202 |                 Log.e("siyehua", "top: " + mPaint.getFontMetrics().top + "  ascent: " + mPaint
203 |                         .getFontMetrics().ascent + "  descent: " + mPaint.getFontMetrics()
204 |                         .descent + "  " + "bottom: " + mPaint.getFontMetrics().bottom + "  " +
205 |                         "leading: " + mPaint.getFontMetrics().leading + "  /nview-top: " +
206 |                         textView2.getTop() + "  view-bottom: " + textView2.getBottom() + " " +
207 |                         "textSize: " + textView2.getTextSize());
208 |             }
209 |         });
210 | ```
211 | 
212 | 结果如下:(单位px,后文无特殊说明,单位均默认为像素px)
213 | ```
214 | top: -126.73828  ascent: -111.328125  descent: 29.296875  bottom: 32.51953  leading: 0.0
215 | view-top: 0  view-bottom: 160 textSize: 120.0
216 | ```
217 | 
218 | 
219 | 
220 | ### 其中top与ascent是负数,是因为baseline是0.
221 | 
222 | ### 根据上图,默认状态下,top与ascent在baseline上面,而安卓手机的Y轴正方向是向下的,故top与ascent是负数,所以前面提到的baseline实际上就等于-top.
223 | 
224 | 按照网上的说法,TextView的高度实际上是 top与 bottom的距离,与结果一致
225 | 
226 | 文字的高度是 ascent与descent之间的距离 111.328125 + 29.296875 ≈ 140.63px,而打印出来的文字的实际大小是120px,这个结果与预期不符.
227 | 
228 | * 假设ascent与descent是动态变化的,可能是"Hello !"这个字符串并没有达到ascent的最小值.
229 | 
230 | 我们知道 a 与 b 两个字符绘制的结果,b明显要冒出一个头.所以有可能是某些字符会突破天际,达到ascent与descent值
231 | 
232 | Google一圈没有发现到底用什么字符测试测试到上限值,但是不妨换一个思考方式,既然无法得到上限,可以突破下限.把TextView的字符串改为ac,看ascent与descent变化了没有.
233 | 
234 | 
235 | 
236 | * 可见ascent与descent不是动态变化的,知乎里看过有人提到,TextView上下有留白,是因为默认添加了一个上下的留白.
237 | 
238 | TextView本身包含一定的FontPadding.看TextView的setIncludeFontPadding()方法.一言不合上代码
239 | 
240 | ```java
241 |  /**
242 |      * Set whether the TextView includes extra top and bottom padding to make
243 |      * room for accents that go above the normal ascent and descent.
244 |      * The default is true.
245 |      *
246 |      * @see #getIncludeFontPadding()
247 |      *
248 |      * @attr ref android.R.styleable#TextView_includeFontPadding
249 |      */
250 |     public void setIncludeFontPadding(boolean includepad) {
251 |         if (mIncludePad != includepad) {
252 |             mIncludePad = includepad;
253 | 
254 |             if (mLayout != null) {
255 |                 nullLayouts();
256 |                 requestLayout();
257 |                 invalidate();
258 |             }
259 |         }
260 |     }
261 | ```
262 | 
263 | 源码不重要,关键是注释,注释里写默认是有一定的间距的,view的高度是top与bottom之间的间距,而设置为false之后,view的高度是ascent与descent之间的间距
264 | 重新设置并打印值
265 | 
266 | ```xml
267 | 
274 | ```
275 | 
276 | 结果view的高度等于ascent与descent之间的高度.
277 | 
278 | ```
279 | top: -126.73828  ascent: -111.328125  descent: 29.296875  bottom: 32.51953  leading: 0.0
280 | view-top: 0  view-bottom: 140 textSize: 120.0
281 | ```
282 | 
283 | 结果符合源码的解释,同时完善一下上面的关于baseline的结论.
284 | 
285 | ### 假设设置了android:includeFontPadding="false",则baseline实际的值等于-ascent
286 | 
287 | 但是,并没有得到:
288 | 
289 | ```
290 | ascent与descent之间的距离等于textSize的大小.
291 | ```
292 | 
293 | 这个结论.
294 | 
295 | 那会不会是textSize的大小实际上指的并不是文字的高度,可能只是一个需要转换的值.
296 | 
297 | 
298 | 
299 | 截屏后使用Mark Man一量,这文字的高度妥妥的就是120px.换个说法就是
300 | 
301 | ```
302 | ascent与descent之间的距离不等于textSize的大小/高度.
303 | ```
304 | 
305 | ## 分析
306 | 
307 | 
308 | 
309 | 假设top与ascent之间的空白是firstSpace,ascent 与文字顶端的空白是secondSpace,
310 | 
311 | ```
312 | 则文字最顶端的Y坐标topTextY = firstSpace + secondSpace;(如TextView已经设置了android:includeFontPadding="false"则不需要加上firstSpace)
313 | firstSpace = ascent - top;
314 | secondSpace = descent - ascent - textSize;
315 | ```
316 | 
317 | 按照这个理论,画一条线.
318 | ```java
319 |     @Override
320 |     protected void onDraw(Canvas canvas) {
321 |         super.onDraw(canvas);
322 |         Paint mPaint = getPaint();
323 |         float lineY = mPaint.getFontMetrics().ascent - mPaint.getFontMetrics().top + mPaint
324 |                 .getFontMetrics().descent - mPaint.getFontMetrics().ascent - mPaint.getTextSize();
325 |         mPaint.setColor(Color.parseColor("#FF00FF"));
326 |         canvas.drawLine(0, lineY, getWidth(), lineY, mPaint);
327 |     }
328 | ```
329 | 
330 | 
331 | 
332 | 非常标准,刚好对齐,深得我意.
333 | 
334 | 所以画百分号的baseline等于
335 | 
336 | ```
337 | baseLine = topTextY + -top(默认状态下,百分号的baseline) - 百分号的topTextY;
338 | ```
339 | 
340 | 代码(详情请看自定义的[StyleTextView](/app/src/main/java/com/siyehua/styletextview/StyleTextView.java))
341 | 
342 | ```java
343 |  Paint mPaint = getPaint();
344 |             mPaint.setTextSize(first.size);
345 |             float startX = mPaint.measureText(first.content);
346 |             float space = topSpace(mPaint);
347 |             
348 |             //画顶部基准线
349 |             float lineY = mPaint.getFontMetrics().ascent - mPaint.getFontMetrics().top + mPaint
350 |                     .getFontMetrics().descent - mPaint.getFontMetrics().ascent - mPaint
351 |                     .getTextSize();
352 |             mPaint.setColor(Color.parseColor("#FF00FF"));
353 |             canvas.drawLine(0, lineY, getWidth(), lineY, mPaint);
354 | 
355 |             //画百分号
356 |             mPaint.setTextSize(second.size);
357 |             float baseLine = space + -mPaint.getFontMetrics().top - topSpace(mPaint);
358 |             mPaint.setColor(second.color);
359 |             canvas.drawText(second.content, startX, baseLine, mPaint);
360 | ```
361 | 
362 | 结果(60这个字符串本身距离直线有一点间距是因为字不够长,假设使用字母 'l' 刚刚好)
363 | 
364 | 
365 | 
366 | ### 总结
367 | 
368 | 终于要完了吗?实际上还没有
369 | 
370 | 
371 | 
372 | 假设TextView的宽度是match_parent,让内容居中
373 | 
374 | ```xml
375 | 
382 | ```
383 | 
384 | 
385 | 
386 | 会发现百分号并没有跟着跑,实际上是因为canvas.drawText()这个方法的参数,startX与BaseLine还受内容的对齐方式影响
387 | 
388 | 而我绘制百分号并没有考虑这方面的因素.
389 | 
390 | 假设TextView的对齐方式是居中,则startX是TextView文字的中点.
391 | 
392 | 
393 | 
394 | 图中红框的右边便是文字的右边,而我们需要计算文字右边减去粉色百分号%,得到到即是上标百分号%的startY
395 | 
396 | ```
397 | 上标startY = 文字右边 - "%"宽度
398 | 文字右边距 = TextView宽度/2.0f + 需要绘制的文字的宽度/2.0f
399 | 需要绘制的文字的宽度 =  "60"串的宽度 + "%"百分号的宽度
400 | ```
401 | 
402 | ```java
403 | startX = getWidth() / 2.0f + (startX + mPaint.measureText(second.content)) / 2.0f -
404 |                     mPaint.measureText(second.content) * 1.5f;
405 | ```
406 | 
407 | 
408 | 
409 | 结果
410 | 
411 | 
412 | 
413 | 可以看到百分号的已经设置到了正确的位置.
414 | 
415 | 同理可得(其实我懒得算了)
416 | 
417 | #### 当TextView的高度设置match_parent,且内容设置居中时,需要用同样的方法计算baseline.
418 | 
419 | 这里就不在举例了.毕竟制作表情包太累了.
420 | 
421 | 就酱紫.如有任何疑问请留言讨论,或者扫下方二维码联系我
422 | 
423 | 
424 | 
--------------------------------------------------------------------------------
/StyleTextView.iml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |       
 6 |         
 7 |         
 8 |       
 9 |     
10 |   
11 |   
12 |     
13 |     
14 |       
15 |     
16 |     
17 |     
18 |   
19 | 
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | 
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 |   
  4 |     
  5 |       
  6 |         
  7 |       
  8 |     
  9 |     
 10 |       
 11 |         
 12 |         
 13 |         
 14 |         
 15 |         
 16 |           generateDebugSources
 17 |         
 18 |         
 19 |         
 20 |         
 21 |         
 22 |         
 23 |       
 24 |     
 25 |   
 26 |   
 27 |     
 28 |     
 29 |     
 30 |     
 31 |       
 32 |       
 33 |       
 34 |       
 35 |       
 36 |       
 37 |       
 38 |       
 39 |       
 40 |       
 41 |       
 42 |       
 43 |       
 44 |       
 45 |       
 46 |       
 47 |       
 48 |       
 49 |       
 50 |       
 51 |       
 52 |       
 53 |       
 54 |       
 55 |       
 56 |       
 57 |       
 58 |       
 59 |       
 60 |       
 61 |       
 62 |       
 63 |       
 64 |       
 65 |       
 66 |       
 67 |       
 68 |       
 69 |       
 70 |       
 71 |       
 72 |       
 73 |       
 74 |       
 75 |       
 76 |       
 77 |       
 78 |       
 79 |       
 80 |       
 81 |       
 82 |       
 83 |       
 84 |       
 85 |       
 86 |       
 87 |       
 88 |       
 89 |       
 90 |       
 91 |       
 92 |       
 93 |       
 94 |       
 95 |       
 96 |       
 97 |     
 98 |     
 99 |     
100 |     
101 |     
102 |     
103 |     
104 |     
105 |     
106 |     
107 |   
108 | 
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
 1 | apply plugin: 'com.android.application'
 2 | 
 3 | android {
 4 |     compileSdkVersion 23
 5 |     buildToolsVersion "23.0.2"
 6 | 
 7 |     defaultConfig {
 8 |         applicationId "com.siyehua.styletextview"
 9 |         minSdkVersion 15
10 |         targetSdkVersion 23
11 |         versionCode 1
12 |         versionName "1.0"
13 |     }
14 |     buildTypes {
15 |         release {
16 |             minifyEnabled false
17 |             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 |         }
19 |     }
20 | }
21 | 
22 | dependencies {
23 |     compile fileTree(dir: 'libs', include: ['*.jar'])
24 |     testCompile 'junit:junit:4.12'
25 |     compile 'com.android.support:appcompat-v7:23.2.1'
26 | }
27 | 
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
 1 | # Add project specific ProGuard rules here.
 2 | # By default, the flags in this file are appended to flags specified
 3 | # in E:\adt-bundle-windows-x86_64-20140702\sdk/tools/proguard/proguard-android.txt
 4 | # You can edit the include path and order by changing the proguardFiles
 5 | # directive in build.gradle.
 6 | #
 7 | # For more details, see
 8 | #   http://developer.android.com/guide/developing/tools/proguard.html
 9 | 
10 | # Add any project specific keep options here:
11 | 
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | #   public *;
17 | #}
18 | 
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/siyehua/styletextview/ApplicationTest.java:
--------------------------------------------------------------------------------
 1 | package com.siyehua.styletextview;
 2 | 
 3 | import android.app.Application;
 4 | import android.test.ApplicationTestCase;
 5 | 
 6 | /**
 7 |  * Testing Fundamentals
 8 |  */
 9 | public class ApplicationTest extends ApplicationTestCase {
10 |     public ApplicationTest() {
11 |         super(Application.class);
12 |     }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 4 | 
 5 |     
11 |         
12 |             
13 |                 
14 | 
15 |                 
16 |             
17 |         
18 |     
19 | 
20 | 
21 | 
--------------------------------------------------------------------------------
/app/src/main/java/com/siyehua/styletextview/DrawLineTextView.java:
--------------------------------------------------------------------------------
 1 | package com.siyehua.styletextview;/**
 2 |  * Created by huangxk on 2016/8/22.
 3 |  */
 4 | 
 5 | import android.annotation.TargetApi;
 6 | import android.content.Context;
 7 | import android.graphics.Canvas;
 8 | import android.graphics.Color;
 9 | import android.graphics.Paint;
10 | import android.os.Build;
11 | import android.util.AttributeSet;
12 | import android.widget.TextView;
13 | 
14 | /**
15 |  * @method
16 |  * @pram
17 |  * @return
18 |  */
19 | public class DrawLineTextView extends TextView {
20 |     public DrawLineTextView(Context context) {
21 |         super(context);
22 |     }
23 | 
24 |     public DrawLineTextView(Context context, AttributeSet attrs) {
25 |         super(context, attrs);
26 |     }
27 | 
28 |     public DrawLineTextView(Context context, AttributeSet attrs, int defStyleAttr) {
29 |         super(context, attrs, defStyleAttr);
30 |     }
31 | 
32 |     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
33 |     public DrawLineTextView(Context context, AttributeSet attrs, int defStyleAttr, int
34 |             defStyleRes) {
35 |         super(context, attrs, defStyleAttr, defStyleRes);
36 |     }
37 | 
38 |     @Override
39 |     protected void onDraw(Canvas canvas) {
40 | //        if (flag) {
41 |         Paint mPaint = getPaint();
42 |         float lineY = mPaint.getFontMetrics().ascent - mPaint.getFontMetrics().top + mPaint
43 |                 .getFontMetrics().descent - mPaint.getFontMetrics().ascent - mPaint.getTextSize();
44 | 
45 |         if (type == 0) {
46 |             super.onDraw(canvas);
47 |         } else if (type == 1) {
48 |             mPaint.setColor(Color.parseColor("#0000F0"));
49 |             canvas.drawText(getText().toString(), 0, getTextSize(), mPaint);
50 |         } else if (type == 2) {
51 |             mPaint.setColor(Color.parseColor("#F00000"));
52 |             canvas.drawText(getText().toString(), 0, -mPaint.getFontMetrics().top, mPaint);
53 |         }
54 |         mPaint.setColor(Color.parseColor("#FF00FF"));
55 |         canvas.drawLine(0, lineY, getWidth(), lineY, mPaint);
56 | //        }
57 |     }
58 | 
59 |     private int type = 0;
60 | 
61 |     public void setType(int type) {
62 |         this.type = type;
63 |         postInvalidate();
64 |     }
65 | }
66 | 
--------------------------------------------------------------------------------
/app/src/main/java/com/siyehua/styletextview/MainActivity.java:
--------------------------------------------------------------------------------
  1 | package com.siyehua.styletextview;
  2 | 
  3 | import android.graphics.Color;
  4 | import android.os.Bundle;
  5 | import android.support.v7.app.AppCompatActivity;
  6 | import android.text.SpannableString;
  7 | import android.util.TypedValue;
  8 | 
  9 | public class MainActivity extends AppCompatActivity {
 10 |     SpannableString spannableString;
 11 | 
 12 |     @Override
 13 |     protected void onCreate(Bundle savedInstanceState) {
 14 |         super.onCreate(savedInstanceState);
 15 |         setContentView(R.layout.activity_main);
 16 | //        final DrawLineTextView textView2 = (DrawLineTextView) findViewById(R.id._test);
 17 | //        assert textView2 != null;
 18 | //        textView2.setOnClickListener(new View.OnClickListener() {
 19 | //            @Override
 20 | //            public void onClick(View v) {
 21 | //                Paint mPaint = textView2.getPaint();
 22 | //                textView2.setLinePositionAndDraw(mPaint.getFontMetrics().top, mPaint
 23 | //                        .getFontMetrics().ascent, mPaint.getFontMetrics().descent, mPaint
 24 | //                        .getFontMetrics().bottom);
 25 | //                Log.e("siyehua", "top: " + mPaint.getFontMetrics().top + "  ascent: " + mPaint
 26 | //                        .getFontMetrics().ascent + "  descent: " + mPaint.getFontMetrics()
 27 | //                        .descent + "  " + "bottom: " + mPaint.getFontMetrics().bottom + "  " +
 28 | //                        "leading: " + mPaint.getFontMetrics().leading + " mPaintSize: " + mPaint
 29 | //                        .getTextSize() + "  \nview-top: " +
 30 | //                        textView2.getTop() + "  view-bottom: " + textView2.getBottom() + " " +
 31 | //                        "textSize: " + textView2.getTextSize());
 32 | //            }
 33 | //        });
 34 | //        final DrawLineTextView textView3 = (DrawLineTextView) findViewById(R.id._test2);
 35 | //        assert textView3 != null;
 36 | //        textView3.setOnClickListener(new View.OnClickListener() {
 37 | //            @Override
 38 | //            public void onClick(View v) {
 39 | //                Paint mPaint = textView2.getPaint();
 40 | //                textView3.setLinePositionAndDraw(mPaint.getFontMetrics().top, mPaint
 41 | //                        .getFontMetrics().ascent, mPaint.getFontMetrics().descent, mPaint
 42 | //                        .getFontMetrics().bottom);
 43 | //
 44 | //                Log.e("siyehua", "top: " + mPaint.getFontMetrics().top + "  ascent: " + mPaint
 45 | //                        .getFontMetrics().ascent + "  descent: " + mPaint.getFontMetrics()
 46 | //                        .descent + "  " + "bottom: " + mPaint.getFontMetrics().bottom + "  " +
 47 | //                        "leading: " + mPaint.getFontMetrics().leading + " mPaintSize: " + mPaint
 48 | //                        .getTextSize() + "  \nview-top: " +
 49 | //                        textView2.getTop() + "  view-bottom: " + textView2.getBottom() + " " +
 50 | //                        "textSize: " + textView2.getTextSize());
 51 | //            }
 52 | //        });
 53 | 
 54 | 
 55 | //        TextView textView = (TextView) findViewById(R.id._001);
 56 | //        String text = new String("60%\n主胜");
 57 | //        spannableString = new SpannableString(text);
 58 | //        int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources()
 59 | //                .getDisplayMetrics());
 60 | //        spannableString.setSpan(new AbsoluteSizeSpan(size), 2, 3, Spanned
 61 | //                .SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体大小
 62 | //        spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#FF00FF")), 2, 3,
 63 | //                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体颜色
 64 | //
 65 | //        int size2 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30, getResources
 66 | //                ().getDisplayMetrics());
 67 | //        spannableString.setSpan(new AbsoluteSizeSpan(size2), text.length() - 2, text.length(),
 68 | //                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//设置字体大小
 69 | //        spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#000FFF")), text.length
 70 | //                        () - 2, text.length(), Spanned.SPA
 71 | //
 72 | //                N_EXCLUSIVE_EXCLUSIVE);//设置字体颜色
 73 | //        textView.setText(spannableString);
 74 | 
 75 | 
 76 | 
 77 |         StyleTextView textView = (StyleTextView) findViewById(R.id.tv_content);
 78 |         assert textView != null;
 79 |         int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources()
 80 |                 .getDisplayMetrics());
 81 |         int color = Color.parseColor("#FF00FF");
 82 |         int size2 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 24, getResources
 83 |                 ().getDisplayMetrics());
 84 |         int color2 = Color.parseColor("#0000FF");
 85 |         int size3 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 60, getResources
 86 |                 ().getDisplayMetrics());
 87 |         int color3 = Color.parseColor("#464646");
 88 |         textView.setText("6 0%\n主胜", new StyleTextView.TextStyle("6 0", size3, color3, false), new
 89 |                 StyleTextView.TextStyle("%", size, color, true), new StyleTextView.TextStyle
 90 |                 ("主胜", size2, color2, false));
 91 | 
 92 | 
 93 | //        DrawLineTextView textView1 = (DrawLineTextView) findViewById(R.id.tv_001);
 94 | //        DrawLineTextView textView2 = (DrawLineTextView) findViewById(R.id.tv_002);
 95 | //        textView2.setType(1);
 96 | //        DrawLineTextView textView3 = (DrawLineTextView) findViewById(R.id.tv_003);
 97 | //        textView3.setType(2);
 98 | 
 99 |     }
100 | 
101 | }
102 | 
--------------------------------------------------------------------------------
/app/src/main/java/com/siyehua/styletextview/StyleTextView.java:
--------------------------------------------------------------------------------
  1 | package com.siyehua.styletextview;/**
  2 |  * Created by huangxk on 2016/8/18.
  3 |  */
  4 | 
  5 | import android.annotation.TargetApi;
  6 | import android.content.Context;
  7 | import android.graphics.Canvas;
  8 | import android.graphics.Color;
  9 | import android.graphics.Paint;
 10 | import android.os.Build;
 11 | import android.text.SpannableString;
 12 | import android.text.Spanned;
 13 | import android.text.style.AbsoluteSizeSpan;
 14 | import android.text.style.ForegroundColorSpan;
 15 | import android.util.AttributeSet;
 16 | import android.util.Log;
 17 | import android.widget.TextView;
 18 | 
 19 | /**
 20 |  * @method
 21 |  * @pram
 22 |  * @return
 23 |  */
 24 | public class StyleTextView extends TextView {
 25 |     public StyleTextView(Context context) {
 26 |         super(context);
 27 |     }
 28 | 
 29 |     public StyleTextView(Context context, AttributeSet attrs) {
 30 |         super(context, attrs);
 31 |     }
 32 | 
 33 |     public StyleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
 34 |         super(context, attrs, defStyleAttr);
 35 |     }
 36 | 
 37 |     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 38 |     public StyleTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
 39 |         super(context, attrs, defStyleAttr, defStyleRes);
 40 |     }
 41 | 
 42 |     @Override
 43 |     protected void onDraw(Canvas canvas) {
 44 |         super.onDraw(canvas);
 45 |         if (first != null) {
 46 |             Paint mPaint = getPaint();
 47 |             mPaint.setTextSize(first.size);
 48 |             float startX = mPaint.measureText(first.content);
 49 |             float space = topSpace(mPaint);
 50 | 
 51 |             float lineY = mPaint.getFontMetrics().ascent - mPaint.getFontMetrics().top + mPaint
 52 |                     .getFontMetrics().descent - mPaint.getFontMetrics().ascent - mPaint
 53 |                     .getTextSize();
 54 |             mPaint.setColor(Color.parseColor("#FF00FF"));
 55 |             canvas.drawLine(0, lineY, getWidth(), lineY, mPaint);
 56 | 
 57 |             mPaint.setTextSize(second.size);
 58 |             startX = getWidth() / 2.0f + (startX + mPaint.measureText(second.content)) / 2.0f -
 59 |                     mPaint.measureText(second.content);
 60 | 
 61 |             float baseLine = space + -mPaint.getFontMetrics().top - topSpace(mPaint);
 62 |             mPaint.setColor(second.color);
 63 |             canvas.drawText(second.content, startX, baseLine, mPaint);
 64 | 
 65 |             Log.e("siyehua", "width: " + getWidth() + "  height: " + getHeight() + " startY: " +
 66 |                     startX + "  baseLine: " + baseLine);
 67 |         }
 68 | 
 69 |     }
 70 | 
 71 | 
 72 | 
 73 |     private float topSpace(Paint mPaint) {
 74 |         return (mPaint.getFontMetrics().ascent - mPaint.getFontMetrics().top) //最上层空白
 75 |                 + secondSpace(mPaint);
 76 |     }
 77 | 
 78 |     private float secondSpace(Paint mPaint) {
 79 |         return mPaint.getFontMetrics().descent - mPaint.getFontMetrics().ascent - mPaint
 80 |                 .getTextSize();
 81 |     }
 82 | 
 83 | 
 84 |     SpannableString spannableString;
 85 |     String content;
 86 |     TextStyle first, second;
 87 | 
 88 | 
 89 |     /**
 90 |      * 设置Text
 91 |      *
 92 |      * @param content String
 93 |      * @param styles
 94 |      */
 95 |     public void setText(String content, TextStyle... styles) {
 96 |         this.content = content;
 97 |         spannableString = new SpannableString(content);
 98 |         int i = 0;
 99 |         for (TextStyle styleContent : styles) {
100 |             if (i == 0) first = styleContent;
101 |             else if (i == 1) second = styleContent;
102 |             i++;
103 |             int start = content.indexOf(styleContent.content);
104 |             int end = start + styleContent.content.length();
105 |             if (styleContent.size != -1)
106 |                 spannableString.setSpan(new AbsoluteSizeSpan(styleContent.size), start, end,
107 |                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
108 |             if (styleContent.color != -1)
109 |                 spannableString.setSpan(new ForegroundColorSpan(styleContent.color), start, end,
110 |                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
111 |             if (styleContent.up) {//上标时设置颜色为透明色,然后再onDraw自己画
112 |                 spannableString.setSpan(new ForegroundColorSpan(Color.TRANSPARENT), start, end,
113 |                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
114 |             }
115 |         }
116 |         setText(spannableString);
117 |     }
118 | 
119 | 
120 |     public static class TextStyle {
121 |         String content;
122 |         int size;
123 |         int color;
124 |         boolean up = false;//是否上标
125 | 
126 |         public TextStyle() {
127 |         }
128 | 
129 |         public TextStyle(String content, int size, int color, boolean up) {
130 |             this.content = content;
131 |             this.size = size;
132 |             this.color = color;
133 |             this.up = up;
134 |         }
135 |     }
136 | 
137 | }
138 | 
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/abc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/drawable-xxhdpi/abc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/_001.xml:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  9 | 
 10 |     
 14 | 
 15 |         
 19 | 
 20 |             
 26 | 
 27 |             
 33 | 
 34 |             
 40 |         
 41 |     
 42 | 
 43 |     
 47 | 
 48 |         
 52 | 
 53 |             
 59 | 
 60 |             
 66 | 
 67 |             
 73 |         
 74 |     
 75 | 
 76 |     
 80 | 
 81 |         
 85 | 
 86 |             
 92 | 
 93 |             
 99 | 
100 |             
106 |         
107 |     
108 | 
109 | 
--------------------------------------------------------------------------------
/app/src/main/res/layout/_002.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 9 | 
10 |     
18 | 
19 |     
27 | 
28 |     
36 | 
37 | 
38 | 
--------------------------------------------------------------------------------
/app/src/main/res/layout/_003.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 9 | 
10 |     
19 | 
20 |     
29 | 
30 | 
--------------------------------------------------------------------------------
/app/src/main/res/layout/_004.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 9 | 
10 |     
17 | 
18 |     
25 | 
26 |     
34 | 
35 | 
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 9 | 
10 |     
17 | 
18 | 
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 | 
2 |     
5 |     64dp
6 | 
7 | 
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |     #3F51B5
4 |     #303F9F
5 |     #FF4081
6 | 
7 | 
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 | 
2 |     
3 |     16dp
4 |     16dp
5 | 
6 | 
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 | 
2 |     StyleTextView
3 | 
4 | 
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |     
10 | 
11 | 
12 | 
--------------------------------------------------------------------------------
/app/src/test/java/com/siyehua/styletextview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
 1 | package com.siyehua.styletextview;
 2 | 
 3 | import org.junit.Test;
 4 | 
 5 | import static org.junit.Assert.*;
 6 | 
 7 | /**
 8 |  * To work on unit tests, switch the Test Artifact in the Build Variants view.
 9 |  */
10 | public class ExampleUnitTest {
11 |     @Test
12 |     public void addition_isCorrect() throws Exception {
13 |         assertEquals(4, 2 + 2);
14 |     }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
 2 | 
 3 | buildscript {
 4 |     repositories {
 5 |         jcenter()
 6 |     }
 7 |     dependencies {
 8 |         classpath 'com.android.tools.build:gradle:1.3.0'
 9 | 
10 |         // NOTE: Do not place your application dependencies here; they belong
11 |         // in the individual module build.gradle files
12 |     }
13 | }
14 | 
15 | allprojects {
16 |     repositories {
17 |         jcenter()
18 |     }
19 | }
20 | 
21 | task clean(type: Delete) {
22 |     delete rootProject.buildDir
23 | }
24 | 
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
 1 | # Project-wide Gradle settings.
 2 | 
 3 | # IDE (e.g. Android Studio) users:
 4 | # Gradle settings configured through the IDE *will override*
 5 | # any settings specified in this file.
 6 | 
 7 | # For more details on how to configure your build environment visit
 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
 9 | 
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 | 
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 18 10:41:17 CST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
7 | 
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
  1 | #!/usr/bin/env bash
  2 | 
  3 | ##############################################################################
  4 | ##
  5 | ##  Gradle start up script for UN*X
  6 | ##
  7 | ##############################################################################
  8 | 
  9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 10 | DEFAULT_JVM_OPTS=""
 11 | 
 12 | APP_NAME="Gradle"
 13 | APP_BASE_NAME=`basename "$0"`
 14 | 
 15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
 16 | MAX_FD="maximum"
 17 | 
 18 | warn ( ) {
 19 |     echo "$*"
 20 | }
 21 | 
 22 | die ( ) {
 23 |     echo
 24 |     echo "$*"
 25 |     echo
 26 |     exit 1
 27 | }
 28 | 
 29 | # OS specific support (must be 'true' or 'false').
 30 | cygwin=false
 31 | msys=false
 32 | darwin=false
 33 | case "`uname`" in
 34 |   CYGWIN* )
 35 |     cygwin=true
 36 |     ;;
 37 |   Darwin* )
 38 |     darwin=true
 39 |     ;;
 40 |   MINGW* )
 41 |     msys=true
 42 |     ;;
 43 | esac
 44 | 
 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
 46 | if $cygwin ; then
 47 |     [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
 48 | fi
 49 | 
 50 | # Attempt to set APP_HOME
 51 | # Resolve links: $0 may be a link
 52 | PRG="$0"
 53 | # Need this for relative symlinks.
 54 | while [ -h "$PRG" ] ; do
 55 |     ls=`ls -ld "$PRG"`
 56 |     link=`expr "$ls" : '.*-> \(.*\)$'`
 57 |     if expr "$link" : '/.*' > /dev/null; then
 58 |         PRG="$link"
 59 |     else
 60 |         PRG=`dirname "$PRG"`"/$link"
 61 |     fi
 62 | done
 63 | SAVED="`pwd`"
 64 | cd "`dirname \"$PRG\"`/" >&-
 65 | APP_HOME="`pwd -P`"
 66 | cd "$SAVED" >&-
 67 | 
 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 69 | 
 70 | # Determine the Java command to use to start the JVM.
 71 | if [ -n "$JAVA_HOME" ] ; then
 72 |     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
 73 |         # IBM's JDK on AIX uses strange locations for the executables
 74 |         JAVACMD="$JAVA_HOME/jre/sh/java"
 75 |     else
 76 |         JAVACMD="$JAVA_HOME/bin/java"
 77 |     fi
 78 |     if [ ! -x "$JAVACMD" ] ; then
 79 |         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
 80 | 
 81 | Please set the JAVA_HOME variable in your environment to match the
 82 | location of your Java installation."
 83 |     fi
 84 | else
 85 |     JAVACMD="java"
 86 |     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 87 | 
 88 | Please set the JAVA_HOME variable in your environment to match the
 89 | location of your Java installation."
 90 | fi
 91 | 
 92 | # Increase the maximum file descriptors if we can.
 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
 94 |     MAX_FD_LIMIT=`ulimit -H -n`
 95 |     if [ $? -eq 0 ] ; then
 96 |         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
 97 |             MAX_FD="$MAX_FD_LIMIT"
 98 |         fi
 99 |         ulimit -n $MAX_FD
100 |         if [ $? -ne 0 ] ; then
101 |             warn "Could not set maximum file descriptor limit: $MAX_FD"
102 |         fi
103 |     else
104 |         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 |     fi
106 | fi
107 | 
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 |     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 | 
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 |     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 |     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 | 
118 |     # We build the pattern for arguments to be converted via cygpath
119 |     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 |     SEP=""
121 |     for dir in $ROOTDIRSRAW ; do
122 |         ROOTDIRS="$ROOTDIRS$SEP$dir"
123 |         SEP="|"
124 |     done
125 |     OURCYGPATTERN="(^($ROOTDIRS))"
126 |     # Add a user-defined pattern to the cygpath arguments
127 |     if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 |         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 |     fi
130 |     # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 |     i=0
132 |     for arg in "$@" ; do
133 |         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 |         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
135 | 
136 |         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
137 |             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 |         else
139 |             eval `echo args$i`="\"$arg\""
140 |         fi
141 |         i=$((i+1))
142 |     done
143 |     case $i in
144 |         (0) set -- ;;
145 |         (1) set -- "$args0" ;;
146 |         (2) set -- "$args0" "$args1" ;;
147 |         (3) set -- "$args0" "$args1" "$args2" ;;
148 |         (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 |         (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 |         (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 |         (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 |         (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 |         (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 |     esac
155 | fi
156 | 
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 |     JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 | 
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 | 
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
 1 | @if "%DEBUG%" == "" @echo off
 2 | @rem ##########################################################################
 3 | @rem
 4 | @rem  Gradle startup script for Windows
 5 | @rem
 6 | @rem ##########################################################################
 7 | 
 8 | @rem Set local scope for the variables with windows NT shell
 9 | if "%OS%"=="Windows_NT" setlocal
10 | 
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 | 
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 | 
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 | 
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 | 
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 | 
32 | goto fail
33 | 
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 | 
38 | if exist "%JAVA_EXE%" goto init
39 | 
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 | 
46 | goto fail
47 | 
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 | 
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 | 
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 | 
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 | 
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 | 
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 | 
69 | :execute
70 | @rem Setup the command line
71 | 
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 | 
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 | 
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 | 
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 | 
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 | 
90 | :omega
91 | 
--------------------------------------------------------------------------------
/img/_001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_001.png
--------------------------------------------------------------------------------
/img/_002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_002.png
--------------------------------------------------------------------------------
/img/_003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_003.png
--------------------------------------------------------------------------------
/img/_004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_004.png
--------------------------------------------------------------------------------
/img/_005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_005.png
--------------------------------------------------------------------------------
/img/_006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_006.png
--------------------------------------------------------------------------------
/img/_007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_007.png
--------------------------------------------------------------------------------
/img/_008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_008.png
--------------------------------------------------------------------------------
/img/_009.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_009.png
--------------------------------------------------------------------------------
/img/_011.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_011.png
--------------------------------------------------------------------------------
/img/_012.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_012.png
--------------------------------------------------------------------------------
/img/_013.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_013.png
--------------------------------------------------------------------------------
/img/_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_100.png
--------------------------------------------------------------------------------
/img/_101.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_101.png
--------------------------------------------------------------------------------
/img/_102.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_102.png
--------------------------------------------------------------------------------
/img/_103.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_103.png
--------------------------------------------------------------------------------
/img/_104.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_104.png
--------------------------------------------------------------------------------
/img/_105.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_105.png
--------------------------------------------------------------------------------
/img/_106.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siyehua/StyleTextView/ab25536739f14dcacd526089b215219ae629d44f/img/_106.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | 
--------------------------------------------------------------------------------