Skip to content

Commit 4e92c92

Browse files
authored
Create README.md
1 parent 9ea4e15 commit 4e92c92

1 file changed

Lines changed: 340 additions & 0 deletions

File tree

README.md

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
# RandomTextView
2+
滚动显示TextView的数字,支持自定义每个字符速度。
3+
最近在掘金这个干货平台上发了几篇博文,[这里进入我的掘金主页](http://gold.xitu.io/user/580f1397da2f60004f422d18)
4+
5+
看掘金APP中文章数据的数字滚动起来很动感,效果很棒,
6+
7+
于是决定把它通过自定义View编写出来,方便自己和大家调用。
8+
9+
本文Github代码链接
10+
https://github.com/AndroidMsky/RandomTextView
11+
12+
先看看掘金的效果:
13+
14+
![这里写图片描述](http://img.blog.csdn.net/20161102161400896)
15+
16+
17+
我们自己实现的效果:
18+
19+
20+
![这里写图片描述](http://img.blog.csdn.net/20161102161502895)
21+
22+
接下来介绍一下我的自定义View RandomTextView的用法和原理
23+
24+
用法
25+
--
26+
考入
27+
28+
[RandomTextView.java](https://github.com/AndroidMsky/RandomTextView/tree/master/app/src/main/java/com/example/liangmutian/randomtextview/view)
29+
30+
只有200行绝对轻量方便。
31+
32+
xml中定义:
33+
34+
```
35+
<com.example.liangmutian.randomtextview.view.RandomTextView
36+
android:id="@+id/rtv"
37+
android:layout_width="wrap_content"
38+
android:layout_height="wrap_content"
39+
android:layout_centerHorizontal="true"
40+
android:layout_centerVertical="true"
41+
android:padding="0px"
42+
android:text="123456"
43+
android:textSize="28sp"/>
44+
```
45+
46+
很开心的事,RandomTextView继承自TextView所以可以使用TextView的所有方法。color,size等等直接去定义就OK啦。
47+
48+
所有位数相同速度滚动:
49+
```
50+
mRandomTextView.setText("876543");
51+
mRandomTextView.setPianyilian(RandomTextView.ALL);
52+
mRandomTextView.start();
53+
```
54+
从左到右侧由快到慢滚动:
55+
56+
```
57+
mRandomTextView.setText("12313288");
58+
mRandomTextView.setPianyilian(RandomTextView.FIRSTF_FIRST);
59+
mRandomTextView.start();
60+
61+
```
62+
从左到右侧由慢到快滚动:
63+
64+
```
65+
mRandomTextView.setText("9078111123");
66+
mRandomTextView.setPianyilian(RandomTextView.FIRSTF_LAST);
67+
mRandomTextView.start();
68+
```
69+
自定义每位数字的速度滚动(每帧滚动的像素):
70+
71+
```
72+
mRandomTextView.setText("909878");
73+
pianyiliang[0] = 7;
74+
pianyiliang[1] = 6;
75+
pianyiliang[2] = 12;
76+
pianyiliang[3] = 8;
77+
pianyiliang[4] = 18;
78+
pianyiliang[5] = 10;
79+
mRandomTextView.setPianyilian(pianyiliang);
80+
mRandomTextView.start();
81+
```
82+
自定义滚动行数(默认10行):
83+
84+
```
85+
mRandomTextView.setMaxLine(20);
86+
```
87+
88+
原理
89+
--
90+
用TextView去绘制10(maxLine可设置)行文字,调用canvas.drawText去绘制出来,在绘制的Y坐标不断增加便宜量,去改变绘制的高度,通过handler.postDelayed(this, 20);不断增加便宜量,并且不断判断所有位数字最后一行绘制完毕的时候,结束handler的循环调用。
91+
92+
需要的变量:
93+
94+
```
95+
//高位快
96+
public static final int FIRSTF_FIRST = 0;
97+
//高位慢
98+
public static final int FIRSTF_LAST = 1;
99+
//速度相同
100+
public static final int ALL = 2;
101+
//用户自定义速度
102+
public static final int USER = 3;
103+
//偏移速度类型
104+
private int pianyiliangTpye;
105+
106+
// 滚动总行数 可设置
107+
private int maxLine = 10;
108+
// 当前字符串长度
109+
private int numLength = 0;
110+
// 当前text
111+
private String text;
112+
113+
114+
//滚动速度数组
115+
private int[] pianyilianglist;
116+
//总滚动距离数组
117+
private int[] pianyiliangSum;
118+
//滚动完成判断
119+
private int[] overLine;
120+
121+
private Paint p;
122+
//第一次绘制
123+
private boolean firstIn = true;
124+
//滚动中
125+
private boolean auto = true;
126+
127+
//text int值列表
128+
private ArrayList<Integer> arrayListText;
129+
130+
//字体宽度
131+
private float f0;
132+
133+
//基准线
134+
private int baseline;
135+
```
136+
137+
OnDraw方法:
138+
139+
```
140+
@Override
141+
protected void onDraw(Canvas canvas) {
142+
143+
if (firstIn) {
144+
firstIn = false;
145+
super.onDraw(canvas);
146+
p = getPaint();
147+
Paint.FontMetricsInt fontMetrics = p.getFontMetricsInt();
148+
baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
149+
float[] widths = new float[4];
150+
p.getTextWidths("9999", widths);
151+
f0 = widths[0];
152+
invalidate();
153+
}
154+
drawNumber(canvas);
155+
156+
```
157+
自一次进入onDraw方法时,做了如下几件事情:
158+
**1.**去获取当前正确的画笔p = getPaint();从而保证xml中配置的大小颜色等有效。
159+
**2.**通过当前画笔去计算正确的drawText基准线。
160+
baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
161+
**3.**等到数字的宽度。方便横向绘制。
162+
p.getTextWidths("9999", widths);f0 = widths[0];
163+
**4.**直接通知view重绘。
164+
invalidate();
165+
166+
我们自己的绘制drawNumber方法:
167+
168+
```
169+
private void drawNumber(Canvas canvas) {
170+
171+
for (int j = 0; j < numLength; j++) {
172+
173+
for (int i = 1; i < maxLine; i++) {
174+
175+
176+
if (i == maxLine - 1 && i * baseline + pianyiliangSum[j] <= baseline)
177+
178+
{
179+
pianyilianglist[j] = 0;
180+
overLine[j] = 1;
181+
int auto = 0;
182+
for (int k = 0; k < numLength; k++) {
183+
auto += overLine[k];
184+
}
185+
if (auto == numLength * 2 - 1) {
186+
this.auto = false;
187+
handler.removeCallbacks(task);
188+
invalidate();
189+
}
190+
191+
}
192+
if (overLine[j] == 0)
193+
194+
canvas.drawText(setBack(arrayListText.get(j), maxLine - i - 1) + "", 0 + f0 * j,
195+
i * baseline + pianyiliangSum[j], p);
196+
197+
else {
198+
//定位后画一次就好啦
199+
if (overLine[j] == 1) {
200+
overLine[j]++;
201+
canvas.drawText(arrayListText.get(j) + "", 0 + f0 * j,
202+
baseline, p);
203+
}
204+
205+
//break;
206+
}}
207+
}}
208+
```
209+
这里逻辑想对复杂时间复杂度达到了O(绘制行数*字符串位数),是个双重循环的绘制。
210+
第一层我们称之为J循环,J循环每次循环的内容是绘制一列。
211+
第二层循环称之为I循环,I循环负责绘制每行的每一个字符。
212+
213+
每次进入I循环的第一件事情是检查当前字符位,是不是最后一个
214+
215+
```
216+
if (i == maxLine - 1 && i * baseline + pianyiliangSum[j] <= baseline)
217+
```
218+
如果是,则归零便宜量,修改标志位
219+
```
220+
pianyilianglist[j] = 0;
221+
overLine[j] = 1;
222+
```
223+
之后去判段所有字符位是否全部绘制到最后一个:
224+
225+
```
226+
int auto = 0;
227+
for (int k = 0; k < numLength; k++) {
228+
auto += overLine[k];}
229+
if (auto == numLength * 2 - 1) {
230+
this.auto = false;
231+
handler.removeCallbacks(task);
232+
invalidate();}
233+
```
234+
如果是则讲自动循环刷新的方法取消掉,并且通知view进行最后一次定位绘制。
235+
以上就是进入i循环先对是否绘制结束的判断。
236+
237+
如果没有结束那么继续绘制:
238+
239+
```
240+
if (overLine[j] == 0)
241+
242+
canvas.drawText(setBack(arrayListText.get(j), maxLine - i - 1) + "", 0 + f0 * j,i * baseline +pianyiliangSum[j], p);
243+
else {
244+
if (overLine[j] == 1) {
245+
//定位后画一次就好啦
246+
overLine[j]++;
247+
canvas.drawText(arrayListText.get(j) + "", 0 + f0 * j,
248+
baseline, p);
249+
}
250+
}
251+
```
252+
253+
overLine[j]中的值的意思为:0表示还没绘制到最后一行,1表示为绘制到最后一行没有进行最后的定位绘制,2表示已经进行了定位绘制。
254+
255+
可能对于初学者最难的就是drawText的坐标问题,x坐标比较简单
256+
就是字符的宽度并且随着循环去变化:
257+
```
258+
0 + f0 * j
259+
```
260+
Y坐标就是当前行的基准值+上当前便宜量:
261+
262+
```
263+
i * baseline + pianyiliangSum[j]
264+
```
265+
266+
每隔20毫秒去计算当前便宜量并通知刷新view:
267+
268+
```
269+
private final Runnable task = new Runnable() {
270+
271+
public void run() {
272+
// TODO Auto-generated method stub
273+
if (auto) {
274+
handler.postDelayed(this, 20);
275+
276+
for (int j = 0; j < numLength; j++) {
277+
pianyiliangSum[j] -= pianyilianglist[j];
278+
279+
}
280+
invalidate();
281+
}
282+
283+
}
284+
};
285+
```
286+
帮助计算9上面的是几。8上面是几
287+
288+
```
289+
//设置上方数字0-9递减
290+
private int setBack(int c, int back) {
291+
292+
if (back == 0) return c;
293+
294+
back = back % 10;
295+
296+
int re = c - back;
297+
298+
if (re < 0) re = re + 10;
299+
300+
return re;
301+
}
302+
```
303+
304+
讲字符串转换为INT数组:
305+
306+
```
307+
private ArrayList<Integer> getList(String s) {
308+
309+
ArrayList<Integer> arrayList = new ArrayList<Integer>();
310+
311+
for (int i = 0; i < s.length(); i++) {
312+
313+
String ss = s.substring(i, i + 1);
314+
315+
int a = Integer.parseInt(ss);
316+
317+
arrayList.add(a);
318+
}
319+
return arrayList;
320+
321+
}
322+
```
323+
绘制原理的逻辑就讲完啦,RandomTextView可以投入使用啦,自定义view并不难,只要你知道安卓API能让你能干什么,你想干什么,你可能马上就知道你应该怎么做啦。
324+
325+
欢迎关注作者。欢迎评论讨论。欢迎拍砖。
326+
327+
如果觉得这篇文章对你有帮助 欢迎打赏,
328+
329+
欢迎star,Fork我的github。
330+
331+
喜欢作者的也可以Follow。也算对作者的一种支持。
332+
本文Github代码链接
333+
https://github.com/AndroidMsky/RandomTextView
334+
335+
欢迎加作者自营安卓开发交流群:308372687
336+
![这里写图片描述](http://img.blog.csdn.net/20161028111556438)
337+
338+
339+
340+
博主原创未经允许不许转载。

0 commit comments

Comments
 (0)