-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
535 lines (426 loc) · 208 KB
/
atom.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
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>芦苇</title>
<subtitle>芦苇的博客</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://luweicheng24.github.io/"/>
<updated>2017-08-21T07:10:59.076Z</updated>
<id>https://luweicheng24.github.io/</id>
<author>
<name>luweicheng24</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>商品购物动画</title>
<link href="https://luweicheng24.github.io/2017/08/21/shoping/"/>
<id>https://luweicheng24.github.io/2017/08/21/shoping/</id>
<published>2017-08-21T06:56:25.000Z</published>
<updated>2017-08-21T07:10:59.076Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>引言<br>对于android人员来说,肯定接触过电商类的app开发,而商品的添加动画会让用户体验提升一大截。</p>
</blockquote>
<p>下面我给大家介绍一下如何制作商品的添加动画,先来看一下效果图:<br>怎么样,是不是还不错啊,接下来我们来看一下如何做到的:</p>
<a id="more"></a>
<p><img src="http://img.blog.csdn.net/20161222122906649?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<ol>
<li>创建动画的层</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 创建执行的动画层</div><div class="line"> *</div><div class="line"> * @return 动画的执行的ViewGroup</div><div class="line"> */</div><div class="line"> private ViewGroup createAnimLayout() {</div><div class="line"> ViewGroup rootView = (ViewGroup) ((Activity) mContext).getWindow().getDecorView();</div><div class="line"> LinearLayout animLayout = new LinearLayout(mContext);</div><div class="line"> LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);</div><div class="line"> animLayout.setLayoutParams(lp);</div><div class="line"> rootView.addView(animLayout);</div><div class="line"> return animLayout;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>2.创建执行动画</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 添加执行动画的view的布局</div><div class="line"> *</div><div class="line"> * @param view 执行动画的View</div><div class="line"> * @param startLocation 动画的开始位置</div><div class="line"> * @return 执行动画的view</div><div class="line"> */</div><div class="line"> private View addViewToAnimLayout(View view, int[] startLocation) {</div><div class="line"> LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);</div><div class="line"> lp.leftMargin = startLocation[0];</div><div class="line"> lp.topMargin = startLocation[1];</div><div class="line"> view.setLayoutParams(lp);</div><div class="line"> return view;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>3.执行动画</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 执行动画</div><div class="line"> *</div><div class="line"> * @param view 执行动画的View</div><div class="line"> * @param startLocation 执行动画的起始位置坐标</div><div class="line"> */</div><div class="line"> private void setAnim(final View view, int[] startLocation) {</div><div class="line"> anim_layout = createAnimLayout();//创建动画执行层</div><div class="line"> anim_layout.addView(view);//将动画小球添加到执行层</div><div class="line"> final View ballView = addViewToAnimLayout(view, startLocation);</div><div class="line"> int[] endLocation = new int[2];</div><div class="line"> MainActivity.shopCar.getLocationInWindow(endLocation);</div><div class="line"></div><div class="line"> int animLocationX = endLocation[0] - startLocation[0] + 80;</div><div class="line"> int animLocatiopnY = endLocation[1] - startLocation[1] + 40;</div><div class="line"> Log.e(TAG, "setAnim: X=" + animLocationX + ":Y=" + animLocatiopnY);</div><div class="line"> /**</div><div class="line"> * 创建动画</div><div class="line"> */</div><div class="line"> //左右移动画</div><div class="line"> TranslateAnimation translateAnimationX = new TranslateAnimation(0, animLocationX, 0, 0);</div><div class="line"> translateAnimationX.setInterpolator(new LinearInterpolator());</div><div class="line"> translateAnimationX.setRepeatCount(0);// 动画重复执行的次数</div><div class="line"> translateAnimationX.setFillAfter(true);</div><div class="line"> //上下移动画</div><div class="line"> TranslateAnimation translateAnimationY = new TranslateAnimation(0, 0, 0, animLocatiopnY);</div><div class="line"> translateAnimationY.setInterpolator(new AccelerateInterpolator());</div><div class="line"> translateAnimationY.setRepeatCount(0);// 动画重复执行的次数</div><div class="line"> translateAnimationX.setFillAfter(true);</div><div class="line"></div><div class="line"> //缩放动画</div><div class="line"> ScaleAnimation scaleAnimation = new ScaleAnimation(0.3f, 0.1f, 0.3f, 0.1f);</div><div class="line"> scaleAnimation.setDuration(1);</div><div class="line"> scaleAnimation.setFillAfter(true);</div><div class="line"></div><div class="line"> //动画集合</div><div class="line"> AnimationSet animationSet = new AnimationSet(false);</div><div class="line"> animationSet.setFillAfter(false);</div><div class="line"> animationSet.addAnimation(scaleAnimation);</div><div class="line"> animationSet.addAnimation(translateAnimationX);</div><div class="line"> animationSet.addAnimation(translateAnimationY);</div><div class="line"> animationSet.setDuration(400);</div><div class="line"> ballView.startAnimation(animationSet);</div><div class="line"></div><div class="line"> animationSet.setAnimationListener(new Animation.AnimationListener() {</div><div class="line"> @Override</div><div class="line"> public void onAnimationStart(Animation animation) {</div><div class="line"> ballView.setVisibility(View.VISIBLE);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onAnimationEnd(Animation animation) {</div><div class="line"> ballView.setVisibility(View.GONE);</div><div class="line"> MainActivity.redCircle.setText(++n + "");</div><div class="line"> /**</div><div class="line"> * 动画结束,下面可以执行向数据库添加购买的货物</div><div class="line"> */</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onAnimationRepeat(Animation animation) {</div><div class="line"></div><div class="line"> }</div><div class="line"> });</div><div class="line"></div><div class="line"> }</div></pre></td></tr></table></figure>
<p>好了,其实代码也不复杂,<a href="https://github.com/luweicheng24/ShopCarAnimation" target="_blank" rel="external">点击查看GitHub源码</a></p>
]]></content>
<summary type="html">
<blockquote>
<p>引言<br>对于android人员来说,肯定接触过电商类的app开发,而商品的添加动画会让用户体验提升一大截。</p>
</blockquote>
<p>下面我给大家介绍一下如何制作商品的添加动画,先来看一下效果图:<br>怎么样,是不是还不错啊,接下来我们来看一下如何做到的:</p>
</summary>
<category term="自定义ViewGroup" scheme="https://luweicheng24.github.io/tags/%E8%87%AA%E5%AE%9A%E4%B9%89ViewGroup/"/>
</entry>
<entry>
<title>rxjava</title>
<link href="https://luweicheng24.github.io/2017/08/21/rxjava/"/>
<id>https://luweicheng24.github.io/2017/08/21/rxjava/</id>
<published>2017-08-21T06:53:59.000Z</published>
<updated>2017-08-21T06:55:04.414Z</updated>
<content type="html"><![CDATA[<p>####RXJava简单理解<br> 首先,rxjava是什么?其实对于刚接触rxjava的宝宝而言,只需要掌握两点:</p>
<ul>
<li>观察者模式</li>
<li>异步处理<br><img src="http://img.blog.csdn.net/20161209182910300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"><br>观察上图,清楚生动刻画出了rxjava的观察者模式:</li>
<li>开关(被观察者)作为的是事件的产生方(产生“on”和“off”这两个 Event),有它发起这起开关的事件。</li>
<li>台灯(观察者)作为事件的处理方(处理的是“on”和“off”这两个事件),被动的执行on和off。</li>
<li>在产生和完成中间,即在事件由产生方传递到处理方的过程中需要被加<br>工,过滤和装换等操作。<a id="more"></a>
####<strong>重点来了</strong><br>既然rxjava是基于观察者来组建自己的逻辑的,那么我们就来创建观察者(Observer/Subscriber),被观察者(Observable),然后二者建立订阅的关系(就好像那根电线连接台灯和开关)实现台灯观察开关的具体模式,并且在传递过程中对事件进行处理(比如:降低电压)。<br><strong>Tips:</strong><br>Observer是观察者的接口,Subscriber是实现该接口的抽象类,因此这两个类都可以作为观察者,只是Subscriber在Observer的基础上加入了一下拓展,加入了新的一些方法,所以一般更倾向于Subscriber作为观察者,下面我们就来敲一遍:</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">//创建被观察者(开关)</div><div class="line">Observable switch = Observable.create(new Observable.onSubscribe<String>(){</div><div class="line">@override</div><div class="line">pubic void call(Subscriber<? super String> subscriber)</div><div class="line"> {</div><div class="line"> subscriber.onNext("on"); </div><div class="line"> subscriber.onNext("off");</div><div class="line"> subscriber.onNext("on");</div><div class="line"> subscribere.onCompleted();</div><div class="line"> }</div><div class="line">});</div></pre></td></tr></table></figure>
<p>这是最原始的写法,创建了一个开关类(被观察者),产生了四个事件,开,关,开,结束,以上写法比较繁琐,下面两种比较偷懒的写法:</p>
<ul>
<li>模式一:</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Observeable switch = Observable.just("on","off","on");</div></pre></td></tr></table></figure>
<ul>
<li>模式二</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">String[] events = {"on","off","on"}; </div><div class="line">Observable switch = Observable.from(events);</div></pre></td></tr></table></figure>
<p>其实以上两种写法都是对原生的写法进行了更加严密的封装,其实也是将<strong>被观察者(开关)</strong>的那些事件”on”,”off”,”on”进行包装成onNext(“on”)将这样的事件依次发送给<strong>观察者(台灯)</strong>,最后再自己补上onComplete()事件。接下里我们创建观察者:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">//创建观察者(原生模式)</div><div class="line">Subscriber light = new Subscriber<String> {</div><div class="line"> @override</div><div class="line"> public void onCompleted(){</div><div class="line"> Log.d(TAG,"has completed"); //事件处理完成时回调</div><div class="line"> }</div><div class="line"> @override</div><div class="line"> public void onError(Throwable e){//事件出错回调 Log.e(TAG,"has error");</div><div class="line"> }</div><div class="line"> @override</div><div class="line"> public void onNext(String s){//事件发生时回调</div><div class="line"> Log.e(TAG,"handle this ..."+s);</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>以上写法为原生的观察者写法,也是表较常见的写法,下面来个偷懒的写法:</p>
<ul>
<li>偷懒模式(非正式写法)</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">Action1 light = new Action1<String>{</div><div class="line">@override</div><div class="line">public void call(String s){</div><div class="line"> Log.e(TAG,"handle this"+s);</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure>
<p>为什么说它是非正式的写法,首先因为Action1是一个单纯的人畜无害的接口,和Observer没有任何关系,只不过Action1也可以当做观察者来使用,只不过它只能专门处理onNext)()事件,其中Action0,1,2…,0,1,2…代表call()方法能接收的参数个数,接下来我们把观察者和被观察者联系起来:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">//订阅</div><div class="line">switch.subscribe(light);//大功告成</div></pre></td></tr></table></figure>
<p>但是刚开始的时候就是不理解为什么是被观察者订阅观察者,这是搞事情呢!到底谁观察着谁啊,别急有话好好说,询问了度娘之后才理解为什么这样写,按理说台灯观察开关从而开关,没毛病,应该是:<code>light.subscribe(switch);</code>才对啊,之所以开关订阅台灯是为了保证<strong>流失api的调用风格</strong>,那什么优势流式API的调用风格呢?</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">//这就是流式API调用风格</div><div class="line">Oservable.just("on","off","on")//被观察者产生事件</div><div class="line"> .filter(new Fun1(String,Boolean){//将事件进行过滤</div><div class="line"> @override</div><div class="line"> public Boolean call(String s){</div><div class="line"> return s! = null;</div><div class="line"> }</div><div class="line"> })</div><div class="line"> .subscribe(mSubscriber); //将过滤后的事件订阅给观察者是不是感觉看起来很流畅啊</div></pre></td></tr></table></figure>
<p><strong>操作符(Operators)</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">Observable.just("ON","OFF","ON")</div><div class="line"> .map(new Func1<String, Object>() {</div><div class="line"> @Override</div><div class="line"> public Object call(String s) {</div><div class="line"> if(s.contentEquals("F")){</div><div class="line"> return "false";</div><div class="line"> }else {</div><div class="line"> return true;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }).subscribe(new Action1<Object>() {</div><div class="line"> @Override</div><div class="line"> public void call(Object o) {</div><div class="line"> Log.e(TAG, "call: "+o.toString() ;</div><div class="line"> }</div><div class="line"> });</div></pre></td></tr></table></figure>
<p>利用map操作符将被观察者传递的行为进行过滤,将字符串中含有<strong>F</strong>返回false,不含的返回true,而对于map的参数中第一个为被观察者传递的对象第二个为转换过滤后的对象,通过上面的代码也可以清楚地表现出<strong>流式API的调用</strong>。<br>下面我们来看一下rxjava中如何异步处理:<br>在rxjava中有一个<strong>Scheduler —调度器</strong>,相当于线程控制器用来控制当前代码执行在哪个线程中,目前rxjava中内置了三种Scheduler:</p>
<ul>
<li><strong>Schedulers.immedate()</strong>表明直接运行在当前线程,不指定默认为该值;</li>
<li><strong>Schedulers.newThread()</strong>表明每次执行将开启新的线程;</li>
<li><strong>Schedulers.io()</strong> I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。</li>
<li><strong>Schedulers.computation()</strong>计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。</li>
<li><strong>AndroidSchedulers.mainThread()</strong>表明事件发生在主线程中。<br>有了以上几种线程调度器,就可以使用subscribeOn()和observerOn()来对线程进行控制了,subscribeOn():指定subscribe()发生的线程,即Observable.onSubscribe()被激活的线程(事件产生),observableOn():指定Subscriber执行的线程,即事件消费的线程;光说不练假把式:</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">Observable.just("1","2","3")</div><div class="line"> .subscribeOn(Schedulers.io())//指定subscribe()执行的线程为io线程</div><div class="line"> .observeOn(AndroidSchedulers.mainThread())//指定Subscriber回调执行线程为主线程</div><div class="line"> .map(new Func1<String, Integer>(){</div><div class="line"> @Override</div><div class="line"> public Integer call(String s) {</div><div class="line"> return Integer.valueOf(s);</div><div class="line"> }</div><div class="line"> }).subscribe(new Subscriber<Integer>() {</div><div class="line"> @Override</div><div class="line"> public void onCompleted() {</div><div class="line"> Log.d(TAG, "onCompleted: ");</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onError(Throwable e) {</div><div class="line"> Log.d(TAG, "onError: ");</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onNext(Integer integer) {</div><div class="line"> tv_age.setText(integer+"");</div><div class="line"> Log.d(TAG, "onNext: "+integer);</div><div class="line"> }</div><div class="line"> });</div></pre></td></tr></table></figure>
<p>以上代码编写在Androidstudio中,必须添加依赖库:<br><strong>compile ‘io.reactivex:rxjava:1.0.9’</strong><br><strong>compile ‘io.reactivex:rxandroid:1.1.0’</strong></p>
]]></content>
<summary type="html">
<p>####RXJava简单理解<br> 首先,rxjava是什么?其实对于刚接触rxjava的宝宝而言,只需要掌握两点:</p>
<ul>
<li>观察者模式</li>
<li>异步处理<br><img src="http://img.blog.csdn.net/20161209182910300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"><br>观察上图,清楚生动刻画出了rxjava的观察者模式:</li>
<li>开关(被观察者)作为的是事件的产生方(产生“on”和“off”这两个 Event),有它发起这起开关的事件。</li>
<li>台灯(观察者)作为事件的处理方(处理的是“on”和“off”这两个事件),被动的执行on和off。</li>
<li>在产生和完成中间,即在事件由产生方传递到处理方的过程中需要被加<br>工,过滤和装换等操作。
</summary>
<category term="rxjava" scheme="https://luweicheng24.github.io/tags/rxjava/"/>
</entry>
<entry>
<title>自定义弹出式菜单</title>
<link href="https://luweicheng24.github.io/2017/08/21/menu/"/>
<id>https://luweicheng24.github.io/2017/08/21/menu/</id>
<published>2017-08-21T06:51:21.000Z</published>
<updated>2017-08-21T07:01:37.388Z</updated>
<content type="html"><![CDATA[<h4 id="自定义ViewGroup实现弹出式菜单"><a href="#自定义ViewGroup实现弹出式菜单" class="headerlink" title="自定义ViewGroup实现弹出式菜单"></a>自定义ViewGroup实现弹出式菜单</h4><p>在看了鸿洋大神的自定义ArcMenu之后,自己动手实现了功能相同的ArcMenu,记录一下:<br>首先来个效果图:<br><img src="http://img.blog.csdn.net/20170508120615801?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<a id="more"></a>
<ol>
<li>自定义属性(创建attr.xml)</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">//创建自定义属性值(中心Button的位置和Item中心Button的半径)</div><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><resources></div><div class="line"> <attr name="position"></div><div class="line"> <enum name="left_top" value="0"/></div><div class="line"> <enum name="left_bottom" value="1"/></div><div class="line"> <enum name="right_top" value="2"/></div><div class="line"> <enum name="right_bottom" value="3"/></div><div class="line"> </attr></div><div class="line"> <attr name="radius" format="dimension"/></div><div class="line"> <declare-styleable name="ArcMenu"></div><div class="line"> <attr name="position"/></div><div class="line"> <attr name="radius"/></div><div class="line"> </declare-styleable></div><div class="line"></div><div class="line"></resources></div></pre></td></tr></table></figure>
<ol>
<li>创建ArcMenu继承ViewGroup</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div><div class="line">199</div><div class="line">200</div><div class="line">201</div><div class="line">202</div><div class="line">203</div><div class="line">204</div><div class="line">205</div><div class="line">206</div><div class="line">207</div><div class="line">208</div><div class="line">209</div><div class="line">210</div><div class="line">211</div><div class="line">212</div><div class="line">213</div><div class="line">214</div><div class="line">215</div><div class="line">216</div><div class="line">217</div><div class="line">218</div><div class="line">219</div><div class="line">220</div><div class="line">221</div><div class="line">222</div><div class="line">223</div><div class="line">224</div><div class="line">225</div><div class="line">226</div><div class="line">227</div><div class="line">228</div><div class="line">229</div><div class="line">230</div><div class="line">231</div><div class="line">232</div><div class="line">233</div><div class="line">234</div><div class="line">235</div><div class="line">236</div><div class="line">237</div><div class="line">238</div><div class="line">239</div><div class="line">240</div><div class="line">241</div><div class="line">242</div><div class="line">243</div><div class="line">244</div><div class="line">245</div><div class="line">246</div><div class="line">247</div><div class="line">248</div><div class="line">249</div><div class="line">250</div><div class="line">251</div><div class="line">252</div><div class="line">253</div><div class="line">254</div><div class="line">255</div><div class="line">256</div><div class="line">257</div><div class="line">258</div><div class="line">259</div><div class="line">260</div><div class="line">261</div><div class="line">262</div><div class="line">263</div><div class="line">264</div><div class="line">265</div><div class="line">266</div><div class="line">267</div><div class="line">268</div><div class="line">269</div><div class="line">270</div><div class="line">271</div><div class="line">272</div><div class="line">273</div><div class="line">274</div><div class="line">275</div><div class="line">276</div><div class="line">277</div><div class="line">278</div><div class="line">279</div><div class="line">280</div><div class="line">281</div><div class="line">282</div><div class="line">283</div><div class="line">284</div><div class="line">285</div><div class="line">286</div><div class="line">287</div><div class="line">288</div><div class="line">289</div><div class="line">290</div><div class="line">291</div><div class="line">292</div><div class="line">293</div><div class="line">294</div><div class="line">295</div><div class="line">296</div><div class="line">297</div><div class="line">298</div><div class="line">299</div><div class="line">300</div><div class="line">301</div><div class="line">302</div><div class="line">303</div><div class="line">304</div><div class="line">305</div><div class="line">306</div><div class="line">307</div><div class="line">308</div><div class="line">309</div><div class="line">310</div><div class="line">311</div><div class="line">312</div><div class="line">313</div><div class="line">314</div><div class="line">315</div><div class="line">316</div><div class="line">317</div><div class="line">318</div><div class="line">319</div><div class="line">320</div><div class="line">321</div><div class="line">322</div><div class="line">323</div><div class="line">324</div><div class="line">325</div><div class="line">326</div><div class="line">327</div><div class="line">328</div><div class="line">329</div><div class="line">330</div><div class="line">331</div><div class="line">332</div><div class="line">333</div><div class="line">334</div><div class="line">335</div><div class="line">336</div><div class="line">337</div><div class="line">338</div><div class="line">339</div><div class="line">340</div><div class="line">341</div><div class="line">342</div><div class="line">343</div><div class="line">344</div><div class="line">345</div><div class="line">346</div><div class="line">347</div><div class="line">348</div><div class="line">349</div><div class="line">350</div><div class="line">351</div><div class="line">352</div><div class="line">353</div><div class="line">354</div><div class="line">355</div><div class="line">356</div><div class="line">357</div><div class="line">358</div><div class="line">359</div><div class="line">360</div><div class="line">361</div><div class="line">362</div><div class="line">363</div><div class="line">364</div><div class="line">365</div><div class="line">366</div><div class="line">367</div><div class="line">368</div><div class="line">369</div><div class="line">370</div><div class="line">371</div><div class="line">372</div><div class="line">373</div><div class="line">374</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"></div><div class="line">import android.content.Context;</div><div class="line">import android.content.res.TypedArray;</div><div class="line">import android.util.AttributeSet;</div><div class="line">import android.util.Log;</div><div class="line">import android.util.TypedValue;</div><div class="line">import android.view.View;</div><div class="line">import android.view.ViewGroup;</div><div class="line">import android.view.animation.AlphaAnimation;</div><div class="line">import android.view.animation.Animation;</div><div class="line">import android.view.animation.AnimationSet;</div><div class="line">import android.view.animation.OvershootInterpolator;</div><div class="line">import android.view.animation.RotateAnimation;</div><div class="line">import android.view.animation.ScaleAnimation;</div><div class="line">import android.view.animation.TranslateAnimation;</div><div class="line"></div><div class="line">/**</div><div class="line"> * Author : luweicheng on 2017/5/3 0003 18:56</div><div class="line"> * E-mail :1769005961@qq.com</div><div class="line"> * GitHub : https://github.com/luweicheng24</div><div class="line"> * funcation: 自定义ViewGroup</div><div class="line"> */</div><div class="line"></div><div class="line">public class ArcMenu extends ViewGroup implements View.OnClickListener {</div><div class="line"> private Position mPosition = Position.LEFT_BOTTOM;</div><div class="line"> private Statu mStatu = Statu.CLOSE;</div><div class="line"> private int radius = 100;</div><div class="line"> private View mCbutton;</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onClick(View v) {</div><div class="line"> toggleButton();</div><div class="line"> }</div><div class="line"> private void toggleButton() {</div><div class="line"> final int count = getChildCount();</div><div class="line"> for (int i = 0; i < count - 1; i++) {</div><div class="line"></div><div class="line"> final View childView = getChildAt(i + 1);</div><div class="line"> childView.setVisibility(View.VISIBLE);</div><div class="line"></div><div class="line"> int xflag = 1;</div><div class="line"> int yflag = 1;</div><div class="line"></div><div class="line"> if (mPosition == Position.LEFT_TOP</div><div class="line"> || mPosition == Position.LEFT_BOTTOM)</div><div class="line"> xflag = -1;</div><div class="line"> if (mPosition == Position.LEFT_TOP</div><div class="line"> || mPosition == Position.RIGHT_TOP)</div><div class="line"> yflag = -1;</div><div class="line"></div><div class="line"> // child left</div><div class="line"> int cl = (int) (radius * Math.sin(Math.PI / 2 / (count - 2) * i));</div><div class="line"> // child top</div><div class="line"> int ct = (int) (radius * Math.cos(Math.PI / 2 / (count - 2) * i));</div><div class="line"></div><div class="line"> AnimationSet animSet = new AnimationSet(true);</div><div class="line"> TranslateAnimation translateAnimation = null;</div><div class="line"> switch (mStatu) {</div><div class="line"> case CLOSE:</div><div class="line"> //to open</div><div class="line"> translateAnimation = new TranslateAnimation(xflag * cl, 0f, yflag * ct, 0f);</div><div class="line"> childView.setClickable(true);</div><div class="line"> childView.setFocusable(true);</div><div class="line"> break;</div><div class="line"> case OPEN:</div><div class="line"> //to close</div><div class="line"> translateAnimation= new TranslateAnimation(0f, xflag * cl, 0f, yflag * ct);</div><div class="line"> childView.setClickable(false);</div><div class="line"> childView.setFocusable(false);</div><div class="line"> break;</div><div class="line"> }</div><div class="line"></div><div class="line"> translateAnimation.setAnimationListener(new Animation.AnimationListener() {</div><div class="line"> @Override</div><div class="line"> public void onAnimationStart(Animation animation) {</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onAnimationEnd(Animation animation) {</div><div class="line"> Log.e("", "onAnimationEnd: ");</div><div class="line"> if (mStatu == Statu.CLOSE) {</div><div class="line"> childView.setVisibility(GONE);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onAnimationRepeat(Animation animation) {</div><div class="line"></div><div class="line"> }</div><div class="line"> });</div><div class="line"> translateAnimation.setFillAfter(true);</div><div class="line"> translateAnimation.setDuration(300);</div><div class="line"> translateAnimation.setStartOffset((i * 100) / (count - 1));</div><div class="line"> translateAnimation.setInterpolator(new OvershootInterpolator(2F));</div><div class="line"> RotateAnimation rotateAnimation = new RotateAnimation(0, 720, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);</div><div class="line"> rotateAnimation.setFillAfter(true);</div><div class="line"> rotateAnimation.setDuration(300);</div><div class="line"></div><div class="line"> animSet.addAnimation(rotateAnimation);</div><div class="line"> animSet.addAnimation(translateAnimation);</div><div class="line"> childView.startAnimation(animSet);</div><div class="line"> final int index = i+1;</div><div class="line"> childView.setOnClickListener(new OnClickListener() {</div><div class="line"> @Override</div><div class="line"> public void onClick(View v) {</div><div class="line"> if(onMenuItemClickListener!=null){</div><div class="line"> onMenuItemClickListener.itemClick(index);</div><div class="line"> menuItemAnim(index);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> });</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> changeMenuStaus();</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * Menu的Item动画监听</div><div class="line"> * @param index</div><div class="line"> */</div><div class="line"> private void menuItemAnim(int index) {</div><div class="line"> for (int i = 0; i < getChildCount()-1; i++) {</div><div class="line"> View view = getChildAt(i+1);</div><div class="line"> if(index == i+1){</div><div class="line"> scaleItem(view);</div><div class="line"> }else{</div><div class="line"> smallScale(view);</div><div class="line"> }</div><div class="line"> view.setClickable(false);</div><div class="line"> view.setFocusable(false);</div><div class="line"> mStatu = Statu.CLOSE;</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 点击菜单项放大缩小</div><div class="line"> * @param childView</div><div class="line"> */</div><div class="line"> private void scaleItem(View childView) {</div><div class="line"> AnimationSet set = new AnimationSet(true);</div><div class="line"> ScaleAnimation scale1= new ScaleAnimation(1.0f,1.5f,1.0f,1.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);</div><div class="line"> scale1.setDuration(200);</div><div class="line"> ScaleAnimation scale2= new ScaleAnimation(1.5f,1.0f,1.5f,1.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);</div><div class="line"> scale2.setStartOffset(200);</div><div class="line"> scale2.setDuration(200);</div><div class="line"> scale2.setFillAfter(true);</div><div class="line"> Animation alphaAnimation = new AlphaAnimation(1, 0);</div><div class="line"> alphaAnimation.setFillAfter(true);</div><div class="line"> alphaAnimation.setDuration(200);</div><div class="line"> set.addAnimation(scale1);</div><div class="line"> set.addAnimation(scale2);</div><div class="line"> set.addAnimation(alphaAnimation);</div><div class="line"> set.setFillAfter(true);</div><div class="line"> childView.startAnimation(set);</div><div class="line"></div><div class="line"> }</div><div class="line"> private void smallScale(View v){</div><div class="line"> Animation alphaAnimation = new AlphaAnimation(1, 0);</div><div class="line"> alphaAnimation.setFillAfter(true);</div><div class="line"> alphaAnimation.setDuration(200);</div><div class="line"> v.startAnimation(alphaAnimation);</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"> /**</div><div class="line"> * 菜单点击监听</div><div class="line"> */</div><div class="line"> public interface OnMenuItemClickListener{</div><div class="line"> void itemClick(int index);</div><div class="line"> }</div><div class="line"></div><div class="line"> public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {</div><div class="line"> this.onMenuItemClickListener = onMenuItemClickListener;</div><div class="line"> }</div><div class="line"></div><div class="line"> private OnMenuItemClickListener onMenuItemClickListener;</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 切换按钮状态</div><div class="line"> */</div><div class="line"> private void changeMenuStaus() {</div><div class="line"> switch (mStatu) {</div><div class="line"> case OPEN:</div><div class="line"> rotateView(mCbutton, 0, 45f);</div><div class="line"> mStatu = Statu.CLOSE;</div><div class="line"> break;</div><div class="line"> case CLOSE:</div><div class="line"> rotateView(mCbutton, 45f, 0f);</div><div class="line"> mStatu = Statu.OPEN;</div><div class="line"> break;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"> public void rotateView(View v, float from, Float to) {</div><div class="line"> /**</div><div class="line"> * 创建旋转动画,</div><div class="line"> * from 开始的旋转角 to 终止的旋转角</div><div class="line"> * piovXType piovYType 旋转的类型 Animation.RELATIVE_TO_DELF 以自身为标准</div><div class="line"> *</div><div class="line"> * pivotXValue (0 - 1)0 代表以该View 的左上角为中心, 1代表以该View 的右底角为中心旋转</div><div class="line"> */</div><div class="line"> RotateAnimation anim = new RotateAnimation(from, to, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);</div><div class="line"> anim.setDuration(200);</div><div class="line"> anim.setFillAfter(true);</div><div class="line"> mCbutton.setAnimation(anim);</div><div class="line"> anim.start();</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 打开和关闭的枚举类</div><div class="line"> */</div><div class="line"> public enum Statu {</div><div class="line"> CLOSE,</div><div class="line"> OPEN</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 位置的枚举类</div><div class="line"> */</div><div class="line"> public enum Position {</div><div class="line"> LEFT_TOP,</div><div class="line"> LEFT_BOTTOM,</div><div class="line"> RIGHT_TOP,</div><div class="line"> RIGHT_BOTTOM</div><div class="line"> }</div><div class="line"></div><div class="line"> public ArcMenu(Context context) {</div><div class="line"> this(context, null);</div><div class="line"> }</div><div class="line"></div><div class="line"> public ArcMenu(Context context, AttributeSet attrs) {</div><div class="line"> this(context, attrs, 0);</div><div class="line"> }</div><div class="line"></div><div class="line"> public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) {</div><div class="line"> super(context, attrs, defStyleAttr);</div><div class="line"></div><div class="line"></div><div class="line"> //dp转化成px</div><div class="line"> radius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, getResources().getDisplayMetrics());</div><div class="line"> TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0);</div><div class="line"> int count = a.getIndexCount();</div><div class="line"> /**</div><div class="line"> * 遍历自定义属性赋值</div><div class="line"> */</div><div class="line"> for (int i = 0; i < count; i++) {</div><div class="line"> int attr = a.getIndex(i);</div><div class="line"> switch (attr) {</div><div class="line"> case R.styleable.ArcMenu_position:</div><div class="line"> int index = a.getInt(attr, 0);</div><div class="line"> switch (index) {</div><div class="line"> case 0:</div><div class="line"> mPosition = Position.LEFT_TOP;</div><div class="line"> break;</div><div class="line"> case 1:</div><div class="line"> mPosition = Position.LEFT_BOTTOM;</div><div class="line"> break;</div><div class="line"> case 2:</div><div class="line"> mPosition = Position.RIGHT_TOP;</div><div class="line"> break;</div><div class="line"> case 3:</div><div class="line"> mPosition = Position.RIGHT_BOTTOM;</div><div class="line"> break;</div><div class="line"> }</div><div class="line"> break;</div><div class="line"> case R.styleable.ArcMenu_radius:</div><div class="line"> radius = a.getDimensionPixelSize(attr, 100);</div><div class="line"> break;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> a.recycle();</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {</div><div class="line"> super.onMeasure(widthMeasureSpec, heightMeasureSpec);</div><div class="line"> /**</div><div class="line"> * 测量子View</div><div class="line"> */</div><div class="line"> int count = getChildCount();</div><div class="line"> for (int i = 0; i < count; i++) {</div><div class="line"> View v = getChildAt(i);</div><div class="line"> measureChild(v, MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> protected void onLayout(boolean changed, int l, int t, int r, int b) {</div><div class="line"> if (changed) {</div><div class="line"> layoutCenterButton();</div><div class="line"> int count = getChildCount() - 2;</div><div class="line"> for (int i = 0; i < count + 1; i++) {</div><div class="line"> View view = getChildAt(i + 1);</div><div class="line"> int w = view.getMeasuredWidth();</div><div class="line"> int h = view.getMeasuredHeight();</div><div class="line"> int left = 0;</div><div class="line"> int top = 0;</div><div class="line"> int right = 0;</div><div class="line"> int bottom = 0;</div><div class="line"> switch (mPosition) {</div><div class="line"> case LEFT_TOP:</div><div class="line"> left = (int) (radius * Math.sin(Math.PI / 2 / count * i));</div><div class="line"> top = (int) (radius * Math.cos(Math.PI / 2 / count * i));</div><div class="line"> right = left + w;</div><div class="line"> bottom = top + h;</div><div class="line"> break;</div><div class="line"> case LEFT_BOTTOM:</div><div class="line"> left = (int) (radius * Math.sin(Math.PI / 2 / count * i));</div><div class="line"> bottom = getMeasuredHeight() - (int) (radius * Math.cos(Math.PI / 2 / count * i));</div><div class="line"> right = left + w;</div><div class="line"> top = bottom - h;</div><div class="line"> break;</div><div class="line"> case RIGHT_BOTTOM:</div><div class="line"> right = getMeasuredWidth() - (int) (radius * Math.sin(Math.PI / 2 / count * i));</div><div class="line"> bottom = getMeasuredHeight() - (int) (radius * Math.cos(Math.PI / 2 / count * i));</div><div class="line"> top = bottom - h;</div><div class="line"> left = right - w;</div><div class="line"> break;</div><div class="line"> case RIGHT_TOP:</div><div class="line"> right = getMeasuredWidth() - (int) (radius * Math.sin(Math.PI / 2 / count * i));</div><div class="line"> top = (int) (radius * Math.cos(Math.PI / 2 / count * i));</div><div class="line"> bottom = top + h;</div><div class="line"> left = right - w;</div><div class="line"> break;</div><div class="line"></div><div class="line"> }</div><div class="line"> view.layout(left, top, right, bottom);</div><div class="line"> view.setVisibility(GONE);</div><div class="line"> mStatu = Statu.CLOSE;</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 根据布局中设置的position属性来确定中间按钮的位置</div><div class="line"> */</div><div class="line"> private void layoutCenterButton() {</div><div class="line"> int left = 0;</div><div class="line"> int top = 0;</div><div class="line"> mCbutton = getChildAt(0);</div><div class="line"> mCbutton.setOnClickListener(this);</div><div class="line"> int but_width = mCbutton.getMeasuredWidth();</div><div class="line"> int but_height = mCbutton.getMeasuredHeight();</div><div class="line"> switch (mPosition) {</div><div class="line"> case LEFT_TOP:</div><div class="line"> mCbutton.layout(left, top, left + but_width, top + but_height);</div><div class="line"> break;</div><div class="line"> case LEFT_BOTTOM:</div><div class="line"> mCbutton.layout(left, getMeasuredHeight() - but_width, left + but_width, getMeasuredHeight());</div><div class="line"></div><div class="line"> break;</div><div class="line"> case RIGHT_TOP:</div><div class="line"> mCbutton.layout(getMeasuredWidth() - but_width, top, getMeasuredWidth(), top + but_height);</div><div class="line"> break;</div><div class="line"> case RIGHT_BOTTOM:</div><div class="line"> mCbutton.layout(getMeasuredWidth() - but_width, getMeasuredHeight() - but_height, getMeasuredWidth(), getMeasuredHeight());</div><div class="line"> break;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>Github源码链接<a href="https://github.com/luweicheng24/ArcMenu" target="_blank" rel="external">这里写链接内容</a></p>
]]></content>
<summary type="html">
<h4 id="自定义ViewGroup实现弹出式菜单"><a href="#自定义ViewGroup实现弹出式菜单" class="headerlink" title="自定义ViewGroup实现弹出式菜单"></a>自定义ViewGroup实现弹出式菜单</h4><p>在看了鸿洋大神的自定义ArcMenu之后,自己动手实现了功能相同的ArcMenu,记录一下:<br>首先来个效果图:<br><img src="http://img.blog.csdn.net/20170508120615801?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
</summary>
<category term="android" scheme="https://luweicheng24.github.io/categories/android/"/>
<category term="自定义ViewGroup" scheme="https://luweicheng24.github.io/tags/%E8%87%AA%E5%AE%9A%E4%B9%89ViewGroup/"/>
</entry>
<entry>
<title>android与js互调</title>
<link href="https://luweicheng24.github.io/2017/08/21/android-is/"/>
<id>https://luweicheng24.github.io/2017/08/21/android-is/</id>
<published>2017-08-21T06:48:50.000Z</published>
<updated>2017-08-21T06:59:16.921Z</updated>
<content type="html"><![CDATA[<p> Android传输据给JS<br> 在Android中将数据传给js,首先在AndroidStudio中创建一个项目,在认识目录下创建一个文件夹为:assets ,之后将写好的html界面放在这个目录下,为了界面好看点,我在该目录下放了一个图片,这里我为了方便就没有将该html放在Tomcat上。下面是我的html代码:</p>
<a id="more"></a>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><!DOCTYPE html></div><div class="line"><html></div><div class="line"><head></div><div class="line"> <title>Android调用js代码</title></div><div class="line"></head></div><div class="line"><body></div><div class="line"> 用户:<div id="name">游客</div></div><div class="line"> <img src = "girl_14.jpg" width="350px"/></div><div class="line"></div><div class="line"> <button id="but_click" onclick="show()" >点击传数据给Android</button></div><div class="line"> <!-- JS调用Android原生方法 Android中的方法为showToast--></div><div class="line"></div><div class="line"> <!--Android调用js方法 webView.loaduri("javascript:showUser('"+user+"','"+pswword+"'')") --></div><div class="line"> <script type="text/javascript"></div><div class="line"></div><div class="line"> function showUser(user,psw) {</div><div class="line"></div><div class="line"> document.getElementById("name").innerHTML = user+"密码:"+psw;</div><div class="line"> alert(user+psw);</div><div class="line"></div><div class="line"> }</div><div class="line"> </script></div><div class="line"></body></div><div class="line"></html></div></pre></td></tr></table></figure>
<p>下面我在Android布局文件里添加WebView,以及两个输入框,为了将账户数据传递给WebView中的h5界面:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><LinearLayout</div><div class="line"> android:orientation="vertical"</div><div class="line"> xmlns:android="http://schemas.android.com/apk/res/android"</div><div class="line"> xmlns:app="http://schemas.android.com/apk/res-auto"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="match_parent"</div><div class="line">></div><div class="line"> <EditText</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="50dp"</div><div class="line"> android:id="@+id/et_name"</div><div class="line"> /></div><div class="line"> <EditText</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="50dp"</div><div class="line"> android:id="@+id/et_psw"</div><div class="line"> /></div><div class="line"> <Button</div><div class="line"> android:text="登录"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:id="@+id/but_login"</div><div class="line"> android:layout_height="50dp"</div><div class="line"> /></div><div class="line"> <WebView</div><div class="line"> android:id="@+id/wb"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="match_parent"></div><div class="line"></div><div class="line"></div><div class="line"> </WebView></div><div class="line"></div><div class="line"></LinearLayout></div></pre></td></tr></table></figure>
<p>下面就是布局控件初始化,这里最重要的是对WebView的设置,并且将assets下的html文件加载进来:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">webView = (WebView) findViewById(R.id.wb);</div><div class="line"> webView.loadUrl("file:///android_asset/demo01.html");</div><div class="line"> webView.setWebChromeClient(new WebChromeClient());</div><div class="line"> //设置浏览器为Android自带的浏览器</div><div class="line"> webView.addJavascriptInterface(new AndroidInterface(), "android");</div><div class="line"> WebSettings settings = webView.getSettings();</div><div class="line"> settings.setJavaScriptEnabled(true);//必须设置表示支持js</div><div class="line"> settings.setBuiltInZoomControls(true);</div><div class="line"> settings.setDefaultFontSize(20);</div></pre></td></tr></table></figure>
<p>好了,下面就是当点击登录按钮时在Android中传数据给h5:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">user = name.getText().toString().trim();</div><div class="line"> password = psw.getText().toString().trim();</div><div class="line"> String login = "javascript:showUser('"+user+"','"+password+"')";</div><div class="line"> Log.e("q", "onClick: "+login );</div><div class="line"> webView.loadUrl(login);</div></pre></td></tr></table></figure>
<p>好了,这样h5中通过执行js而使h5界面发生改变。</p>
<blockquote>
<p>h5中数据通过js传数据给Android</p>
</blockquote>
<ol>
<li>给h5中的按钮添加点击事件(js执行):</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"> <button id="but_click" onclick="show()" >点击传数据给Android</button></div><div class="line"></div><div class="line"><script type="text/javascript"></div><div class="line"> function show(){</div><div class="line"> var msg = document.getElementById("name").innerText;</div><div class="line"> //alert(msg);</div><div class="line"> window.android.show(msg);</div><div class="line"> /**</div><div class="line"> *这里window是固定的 android是在你Android代码中给WebView添加js接口的第二个数据 show(msg)是Android中的调用的方法</div><div class="line"> *</div><div class="line"> */</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> </script></div></pre></td></tr></table></figure>
<p>js中的代码就是这样,下面如何在h5中点击后Android如何响应,Android首先就是创建一个js需要调用的方法,根据webView.addJavascriptInterface(new AndroidInterface(), “android”);这个设置知道创建的类为AndroidInterface类,所以创建一个非静态内部类,在该类中编写一个在js中需要调用的方法:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">class AndroidInterface{</div><div class="line"> public AndroidInterface(){</div><div class="line"></div><div class="line"> } </div><div class="line"> //由于在api17以后需要用注解申明,所以该方法必须添加下面的注解,api17以前不用申明</div><div class="line"> @JavascriptInterface</div><div class="line"> public void show(String msg){</div><div class="line"> Toast.makeText(MainActivity.this, "Html传过来数据了"+msg, Toast.LENGTH_SHORT).show();</div><div class="line"> }</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>好了,基本的js和android之间的交互就完成了,<a href="https://github.com/luweicheng24/AndroidCallJS" target="_blank" rel="external">点击查看源码</a></p>
]]></content>
<summary type="html">
<p> Android传输据给JS<br> 在Android中将数据传给js,首先在AndroidStudio中创建一个项目,在认识目录下创建一个文件夹为:assets ,之后将写好的html界面放在这个目录下,为了界面好看点,我在该目录下放了一个图片,这里我为了方便就没有将该html放在Tomcat上。下面是我的html代码:</p>
</summary>
<category term="android" scheme="https://luweicheng24.github.io/categories/android/"/>
<category term="android & javascript" scheme="https://luweicheng24.github.io/tags/android-javascript/"/>
</entry>
<entry>
<title>ViewPager实现轮播图</title>
<link href="https://luweicheng24.github.io/2017/08/21/viewpager/"/>
<id>https://luweicheng24.github.io/2017/08/21/viewpager/</id>
<published>2017-08-21T06:45:19.000Z</published>
<updated>2017-08-21T07:11:18.733Z</updated>
<content type="html"><![CDATA[<p>ViewPager实现轮播图<br>对于轮播图的实现,我上次已经在博客中通过自定义ViewGroup实现了,不过过程比较复杂,设置到动画以及图片位置的计算,今天通过Android原生的ViewPager来实现开一个效果比较好的轮播图,<br><a id="more"></a><br>先上个效果图:<br><img src="http://img.blog.csdn.net/20170616094436328?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="轮播图"><br>在实现之前在ViewGroup中有个属性值:clipChilder=”true|false”这个值默认是true,就是当父布局设置为true时,子控件设置的宽和高都必须裁剪成和父布局一样大,但是设置为false时,子控件如过设置的比父控件小,多出的部分将不展示其他控件,在ViewPager中如果固定好了Viewpager的宽,设置margin给左右两边之后,两边将会显示ViewPager中的其他视图,下面是ViewPager的布局:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><RelativeLayout</div><div class="line"> xmlns:android="http://schemas.android.com/apk/res/android"</div><div class="line"> xmlns:app="http://schemas.android.com/apk/res-auto"</div><div class="line"> android:layout_height="match_parent"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:orientation="horizontal"</div><div class="line"> android:clipChildren="false"</div><div class="line"> ></div><div class="line"> <ImageView</div><div class="line"> android:id="@+id/img_bg"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="match_parent" /></div><div class="line"> <android.support.v4.view.ViewPager</div><div class="line"> android:id="@+id/viewPager"</div><div class="line"> android:layout_centerInParent="true"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="350dp"</div><div class="line"> android:layout_marginLeft="55dp"</div><div class="line"> android:layout_marginRight="55dp"</div><div class="line"> ></div><div class="line"></div><div class="line"> </android.support.v4.view.ViewPager></div><div class="line"></div><div class="line"></RelativeLayout></div></pre></td></tr></table></figure>
<p>在布局中这样设置后屏幕就会出现ViewPager中的三个视图,中间最大,两边只是视图的一部分,然后就是如何实现两边的视图高度比中间的小,通过滑动到中间时高度又增加,这是通过自定义ViewPager.PagerTransform来实现的,该类中包含一个方法 public void transformPage(View page, float position),该方法实在ViewPager中视图滑动时调用,其中的position当取值范围分为三个阶段:(-视图个数 , -1),[-1,1] ,(1,视图个数);其中第一个取值表示当视图从中间滑到坐边时,第二个表示视图从右边滑动到中间时,第三个表示视图从右边滑到右边可是框内时调用,核心代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">public static final float MIN_SCALE = 0.6f;</div><div class="line"> @Override</div><div class="line"> public void transformPage(View page, float position) {</div><div class="line"> if(position<-1){</div><div class="line"> page.setScaleY(MIN_SCALE);</div><div class="line"> page.setAlpha(MIN_SCALE);</div><div class="line"> }else if(position<=1){</div><div class="line"> float scale = Math.max(MIN_SCALE,1-Math.abs(position));</div><div class="line"> page.setScaleY(scale);</div><div class="line"> page.setAlpha(scale);</div><div class="line"> }else {</div><div class="line"> page.setScaleY(MIN_SCALE);</div><div class="line"> page.setAlpha(MIN_SCALE);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> }</div></pre></td></tr></table></figure>
<p>这样就出现了两边的视图缩小透明度增加,接下来就是如何实现重复活动,让开始就可以向由滑动,这里我通过设置给Adapter的getCount()返回值为Integer.Max-Value,在一开始就让viewpager纸箱中间位置即Integer.Max-Value/2(),核心代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">int currentItem = getStartSelectItem();</div><div class="line"> vp.setCurrentItem(currentItem,true);</div><div class="line"> public int getStartSelectItem() {</div><div class="line"> int currentItem = Integer.MAX_VALUE/2;</div><div class="line"> if(currentItem%list_image.length==0){</div><div class="line"> return currentItem;</div><div class="line"> }</div><div class="line"> while(currentItem%list_image.length!=0){</div><div class="line"> currentItem++;</div><div class="line"> }</div><div class="line"></div><div class="line"> return currentItem;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>由于在适配器中返回的视图个数为Integer.Max_Value,所以在适配器的instantiateItem和destroyItem中添加以及删除的视图进行取余处理:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">@Override</div><div class="line"> public void destroyItem(ViewGroup container, int position, Object object) {</div><div class="line"></div><div class="line"> container.removeView(data.get(position%data.size()));</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public Object instantiateItem(View container, int position) {</div><div class="line"> ((ViewPager)container).addView(data.get(position%data.size()),0);</div><div class="line"> return data.get(position%data.size());</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>接下来就是实现自动轮播,这里可以采用Handler来进行图片的轮播,通过每个三秒发送一个消息在主线程中切换视图:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">private Handler mHandler = new Handler(){</div><div class="line"> @Override</div><div class="line"> public void handleMessage(Message msg) {</div><div class="line"> super.handleMessage(msg);</div><div class="line"> int pos = msg.what;</div><div class="line"> pos++;</div><div class="line"> vp.setCurrentItem(pos);</div><div class="line"></div><div class="line"> }</div><div class="line"> };</div><div class="line"></div><div class="line"></div><div class="line">new Thread(){</div><div class="line"> @Override</div><div class="line"> public void run() {</div><div class="line"> while(isPlay){</div><div class="line"> try {</div><div class="line"> sleep(3000);</div><div class="line"> } catch (InterruptedException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> mHandler.sendEmptyMessage(vp.getCurrentItem());</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }.start();</div></pre></td></tr></table></figure>
<p>好了,自定义的轮播图就这样实现了。</p>
]]></content>
<summary type="html">
<p>ViewPager实现轮播图<br>对于轮播图的实现,我上次已经在博客中通过自定义ViewGroup实现了,不过过程比较复杂,设置到动画以及图片位置的计算,今天通过Android原生的ViewPager来实现开一个效果比较好的轮播图,<br>
</summary>
<category term="android" scheme="https://luweicheng24.github.io/categories/android/"/>
<category term="android轮播图" scheme="https://luweicheng24.github.io/tags/android%E8%BD%AE%E6%92%AD%E5%9B%BE/"/>
</entry>
<entry>
<title>多线程文件下载</title>
<link href="https://luweicheng24.github.io/2017/08/21/down/"/>
<id>https://luweicheng24.github.io/2017/08/21/down/</id>
<published>2017-08-21T06:43:00.000Z</published>
<updated>2017-08-21T07:03:08.569Z</updated>
<content type="html"><![CDATA[<h4 id="多线程下载文件"><a href="#多线程下载文件" class="headerlink" title="多线程下载文件"></a>多线程下载文件</h4><p>平时开发中有时会用到文件下载,为了提高文件的下载速率,采用多线程下载能够达到事半功倍的效果,已经网上存在着很多的已经完全封装的完善的下载工具类,但是知其然必要知其所以然,于是自己动手撸了一个,里面包含了很多的基本功:</p>
<a id="more"></a>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div></pre></td><td class="code"><pre><div class="line">package test;</div><div class="line">/**</div><div class="line"> * 文件下载类</div><div class="line"> * @author luweicheng</div><div class="line"> *</div><div class="line"> */</div><div class="line"></div><div class="line">import java.io.FileInputStream;</div><div class="line">import java.io.FileNotFoundException;</div><div class="line">import java.io.IOException;</div><div class="line">import java.io.InputStream;</div><div class="line">import java.io.RandomAccessFile;</div><div class="line">import java.net.HttpURLConnection;</div><div class="line">import java.net.URL;</div><div class="line">import java.net.URLConnection;</div><div class="line"></div><div class="line">public class DownFile {</div><div class="line"> private URL fileUrl;// 文件下载路径</div><div class="line"> private int threadCount;// 文件下载的线程数</div><div class="line"> private int startPos;// 每个线程下载文件的开始位置</div><div class="line"> private int size;// 每个线程下载文件的长度</div><div class="line"> private int fileLength;// 文件总程度</div><div class="line"> private String pathName;// 下载的文件路径(包含文件名)</div><div class="line"> private Downthread[] tDownthreads;// 线程数组</div><div class="line"></div><div class="line"> public DownFile(URL url, int threadCount, String pathName) throws IOException {</div><div class="line"> fileUrl = url;</div><div class="line"> this.threadCount = threadCount;</div><div class="line"> this.pathName = pathName;</div><div class="line"> init();</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 初始化</div><div class="line"> * </div><div class="line"> * @throws IOException</div><div class="line"> */</div><div class="line"> private void init() throws IOException {</div><div class="line"> tDownthreads = new Downthread[threadCount];</div><div class="line"> HttpURLConnection conn = (HttpURLConnection) fileUrl.openConnection();</div><div class="line"> conn.setConnectTimeout(5000);</div><div class="line"> conn.setRequestMethod("GET");</div><div class="line"> conn.setRequestProperty("connection", "keep-alive");</div><div class="line"> fileLength = conn.getContentLength();</div><div class="line"> System.out.println("文件长度" + fileLength);</div><div class="line"> size = fileLength / threadCount;</div><div class="line"> System.out.println("每个下载量==" + size);</div><div class="line"> conn.disconnect();// 断开链接</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> public URL getFileUrl() {</div><div class="line"> return fileUrl;</div><div class="line"> }</div><div class="line"></div><div class="line"> public int getThreadCount() {</div><div class="line"> return this.threadCount;</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 开始下载</div><div class="line"> */</div><div class="line"> public void startDown() {</div><div class="line"> for (int i = 0; i < threadCount; i++) {</div><div class="line"> try {</div><div class="line"> RandomAccessFile raFile = new RandomAccessFile(pathName, "rw");</div><div class="line"> tDownthreads[i] = new Downthread(i * size, raFile, i);</div><div class="line"> tDownthreads[i].start();</div><div class="line"> } catch (FileNotFoundException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 下载线程类</div><div class="line"> * </div><div class="line"> * @author luweicheng</div><div class="line"> *</div><div class="line"> */</div><div class="line"> class Downthread extends Thread {</div><div class="line"> private int startPos;// 开始的位置</div><div class="line"> private InputStream is;</div><div class="line"> private RandomAccessFile raFile;</div><div class="line"> private int length;// 下载的文件长度</div><div class="line"> private int flag;// 线程标志</div><div class="line"></div><div class="line"> public Downthread(int startPos, RandomAccessFile raFile, int i) {</div><div class="line"> this.startPos = startPos;</div><div class="line"> this.raFile = raFile;</div><div class="line"> flag = i;</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void run() {</div><div class="line"> try {</div><div class="line"> HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();</div><div class="line"> connection.setRequestMethod("GET");</div><div class="line"> connection.setRequestProperty("connection", "keep-alive");</div><div class="line"> connection.setConnectTimeout(5 * 1000);</div><div class="line"> is = connection.getInputStream();</div><div class="line"> is.skip(startPos);</div><div class="line"> raFile.seek(startPos);</div><div class="line"> byte[] buf = new byte[8 * 1024];</div><div class="line"> int hasread = 0;// 读出的字节数</div><div class="line"> // 将位置在 startPos - startPos 位置的数据读出写入</div><div class="line"> while (length < size && (hasread = is.read(buf)) != -1) {</div><div class="line"> raFile.write(buf, 0, hasread);</div><div class="line"> length += hasread;</div><div class="line"> System.out.println("*****线程" + flag + "下载了*********" + length);</div><div class="line"> }</div><div class="line"> System.out.println("*******线程" + flag + "下载完成*********");</div><div class="line"></div><div class="line"> } catch (IOException e) {</div><div class="line"></div><div class="line"> } finally {</div><div class="line"></div><div class="line"> try {</div><div class="line"> is.close();</div><div class="line"> raFile.close();</div><div class="line"> } catch (IOException e) {</div><div class="line"></div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="多线程下载文件"><a href="#多线程下载文件" class="headerlink" title="多线程下载文件"></a>多线程下载文件</h4><p>平时开发中有时会用到文件下载,为了提高文件的下载速率,采用多线程下载能够达到事半功倍的效果,已经网上存在着很多的已经完全封装的完善的下载工具类,但是知其然必要知其所以然,于是自己动手撸了一个,里面包含了很多的基本功:</p>
</summary>
<category term="JAVA" scheme="https://luweicheng24.github.io/categories/JAVA/"/>
<category term="IO" scheme="https://luweicheng24.github.io/tags/IO/"/>
</entry>
<entry>
<title>记一次挑战15k的编程记录</title>
<link href="https://luweicheng24.github.io/2017/08/21/%E9%9D%A2%E8%AF%95/"/>
<id>https://luweicheng24.github.io/2017/08/21/面试/</id>
<published>2017-08-21T06:36:26.000Z</published>
<updated>2017-08-21T07:11:44.268Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>引言<br>今天去北京某公司面试一个Android的sdk开发工程师,到达公司后直接商家根据需求完成相应的编码工作,20分钟写不出来没有面试机会,结果不出意外的我没有完全写出来,被pass掉,内心虽然有些失落,但是一想,毕竟这个岗位薪资是是相对可观的,没有那么容易。也就释然了,在回来的路上才想到了如何写出来这个,欲哭无泪啊,于是想起一句话:机会随时都有,就看你准备好了没。</p>
</blockquote>
<p>下面是我回到房子后重新写的那个面试题,编写完成,测试没毛病:</p>
<blockquote>
<p>要求:</p>
<ol>
<li>采用io流读出res文件夹下worlds.file 的文本<br>2.对文本内容进行压缩输出压缩后的字符串,用Junit来测试<br>eg:我我我是一个个小小鸟 压缩后的字符串:我3是1一1个2小2鸟1</li>
</ol>
</blockquote>
<a id="more"></a>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div></pre></td><td class="code"><pre><div class="line">package main;</div><div class="line"></div><div class="line">import java.io.File;</div><div class="line">import java.io.FileInputStream;</div><div class="line">import java.io.FileNotFoundException;</div><div class="line">import java.io.IOException;</div><div class="line"></div><div class="line">public class Compress {</div><div class="line"> public String compress() {</div><div class="line"> StringBuilder result = new StringBuilder();</div><div class="line"> File file = new File("src/res/words.file");</div><div class="line"> FileInputStream fis = null;</div><div class="line"> String content = null;</div><div class="line"> try {</div><div class="line"> fis = new FileInputStream(file);</div><div class="line"> /*</div><div class="line"> * file.lenth()表示文本内容所占的字节数</div><div class="line"> */</div><div class="line"> // 创建一个与文本长度一直的字节缓冲区</div><div class="line"> byte[] buf = new byte[(int) file.length()];</div><div class="line"> System.out.println("文件的字节数:" + file.length());</div><div class="line"> int i;// 一次读取的字节数</div><div class="line"> while ((i = fis.read(buf)) != -1) {</div><div class="line"> content = new String(buf);</div><div class="line"> }</div><div class="line"> } catch (FileNotFoundException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> } catch (IOException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> } finally {</div><div class="line"> try {</div><div class="line"> fis.close();//关流</div><div class="line"> } catch (IOException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> int count = content.length();// 该长度以字符为单位</div><div class="line"> char c1 = content.charAt(0);// 获取第一个字符</div><div class="line"> int sum = 1;// 重复的个数</div><div class="line"> for (int j = 1; j < count; j++) {</div><div class="line"> char c2 = content.charAt(j);</div><div class="line"> if (c1 == c2) {</div><div class="line"> sum++;</div><div class="line"> continue;</div><div class="line"> }</div><div class="line"> result.append(c1).append(sum);</div><div class="line"> sum = 1;</div><div class="line"> c1 = c2;</div><div class="line"></div><div class="line"> }</div><div class="line"> result.append(c1).append(sum);// 将最后一个添加上</div><div class="line"> System.out.println(result.toString());</div><div class="line"> return result.toString();</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>测试代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line">package main;</div><div class="line"></div><div class="line">import static org.junit.Assert.*;</div><div class="line"></div><div class="line">import java.io.IOException;</div><div class="line"></div><div class="line">import org.junit.Test;</div><div class="line"></div><div class="line">public class CompressTest {</div><div class="line"></div><div class="line"> @Test</div><div class="line"> public void test() throws Exception {</div><div class="line"> Compress compress = new Compress();</div><div class="line"> try {</div><div class="line"> String reString = compress.compress();</div><div class="line"> if (!reString.equals("我3哦1我1是1一1个1小2鸟2a3b3c3")) {</div><div class="line"> throw new Exception("对不起,测试错误");</div><div class="line"> } else {</div><div class="line"> System.out.println("恭喜您,通过上机测试");</div><div class="line"> }</div><div class="line"> } catch (IOException e) {</div><div class="line"> // TODO Auto-generated catch block</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>worlds.file的文本内容:我我我哦我是一个小小鸟鸟aaabbbccc</p>
]]></content>
<summary type="html">
<blockquote>
<p>引言<br>今天去北京某公司面试一个Android的sdk开发工程师,到达公司后直接商家根据需求完成相应的编码工作,20分钟写不出来没有面试机会,结果不出意外的我没有完全写出来,被pass掉,内心虽然有些失落,但是一想,毕竟这个岗位薪资是是相对可观的,没有那么容易。也就释然了,在回来的路上才想到了如何写出来这个,欲哭无泪啊,于是想起一句话:机会随时都有,就看你准备好了没。</p>
</blockquote>
<p>下面是我回到房子后重新写的那个面试题,编写完成,测试没毛病:</p>
<blockquote>
<p>要求:</p>
<ol>
<li>采用io流读出res文件夹下worlds.file 的文本<br>2.对文本内容进行压缩输出压缩后的字符串,用Junit来测试<br>eg:我我我是一个个小小鸟 压缩后的字符串:我3是1一1个2小2鸟1</li>
</ol>
</blockquote>
</summary>
<category term="JAVA" scheme="https://luweicheng24.github.io/categories/JAVA/"/>
<category term="io" scheme="https://luweicheng24.github.io/tags/io/"/>
</entry>
<entry>
<title>load_circle</title>
<link href="https://luweicheng24.github.io/2017/08/21/load-circle/"/>
<id>https://luweicheng24.github.io/2017/08/21/load-circle/</id>
<published>2017-08-21T06:33:01.000Z</published>
<updated>2017-08-21T06:34:57.422Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>引言</p>
<p>功能来源于需求 ,给我一盒画笔,我将画出整个世界。</p>
</blockquote>
<p>本篇记录一次自定义类似加速球的自定义实现:</p>
<ul>
<li>效果图<br><img src="http://img.blog.csdn.net/20170801101147935?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"><a id="more"></a></li>
<li>具体实现<br> 为了实现这样的一个效果,就必须自定义View,进行自定义布局初始 化以及定义变量等:<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div></pre></td><td class="code"><pre><div class="line">private Paint mPaint; //基本画笔</div><div class="line"> private Paint textPaint; //文字画笔</div><div class="line"> private Path path; //路径</div><div class="line"> private int mWidth = DimentionUtils.px2Dp(getContext(), 50); //默认的view的宽度</div><div class="line"> private int mHeight = DimentionUtils.px2Dp(getContext(), 50);//默认view的高度</div><div class="line"> private int textSize = DimentionUtils.px2Sp(getContext(), 10);//默认文字的大小</div><div class="line"> private String content = "卢";//文字内容</div><div class="line"> private float curPercent; //波浪线水平移动的速率</div><div class="line"> private int color; //文字颜色(默认颜色为红色)</div><div class="line"> private float ratio = 0.5f;// 波浪的高度与view的比值,默认0.5</div><div class="line"></div><div class="line"> public WaveLoadCircle(Context context) {</div><div class="line"> this(context, null);</div><div class="line"> }</div><div class="line"></div><div class="line"> public WaveLoadCircle(Context context, @Nullable AttributeSet attrs) {</div><div class="line"> this(context, attrs, 0);</div><div class="line"> }</div><div class="line"></div><div class="line"> public WaveLoadCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {</div><div class="line"> super(context, attrs, defStyleAttr);</div><div class="line"> init(attrs);</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {</div><div class="line"> super.onMeasure(widthMeasureSpec, heightMeasureSpec);</div><div class="line"> int widthMode = MeasureSpec.getMode(widthMeasureSpec);</div><div class="line"> int width = MeasureSpec.getSize(widthMeasureSpec);</div><div class="line"> int heightMode = MeasureSpec.getMode(heightMeasureSpec);</div><div class="line"> int height = MeasureSpec.getSize(heightMeasureSpec);</div><div class="line"> if (widthMode == MeasureSpec.EXACTLY) {// 确定值或者match_parent</div><div class="line"> mWidth = width;</div><div class="line"> }</div><div class="line"> if (heightMode == MeasureSpec.EXACTLY) {</div><div class="line"> mHeight = height;</div><div class="line"> }</div><div class="line"> setMeasuredDimension(mWidth, mHeight);</div><div class="line"> textSize = mWidth / 4;//文字大小为宽度的四分之一</div><div class="line"> textPaint.setTextSize(textSize);</div><div class="line"> }</div><div class="line">/**</div><div class="line"> * 初始化画笔和路径</div><div class="line"> *</div><div class="line"> * @param attr</div><div class="line"> */</div><div class="line"> private void init(AttributeSet attr) {</div><div class="line"> TypedArray arr = getContext().obtainStyledAttributes(attr, R.styleable.WaveLoadCircle);</div><div class="line"> //自定义颜色和文字,默认蓝色</div><div class="line"> int c = arr.getColor(R.styleable.WaveLoadCircle_color, Color.BLUE);</div><div class="line"> String text = arr.getString(R.styleable.WaveLoadCircle_text);</div><div class="line"> if (c != 0) {</div><div class="line"> Log.i("tag", "init:color " + c);</div><div class="line"> color = c;</div><div class="line"> }</div><div class="line"> if (text != null) {</div><div class="line"> content = text;</div><div class="line"> Log.i("tag", "init:text " + text);</div><div class="line"></div><div class="line"> }</div><div class="line"> arr.recycle();//回收资源</div><div class="line"></div><div class="line"> //初始化画笔</div><div class="line"> mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//去除锯齿</div><div class="line"> mPaint.setDither(true);</div><div class="line"> mPaint.setStyle(Paint.Style.FILL);//填充</div><div class="line"> mPaint.setColor(color);</div><div class="line"></div><div class="line"> //初始化文字画笔</div><div class="line"> textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//反锯齿标志</div><div class="line"> textPaint.setColor(color);</div><div class="line"> textPaint.setStyle(Paint.Style.FILL);</div><div class="line"> textPaint.setDither(true);</div><div class="line"></div><div class="line"> //闭合的波浪路径</div><div class="line"> path = new Path();</div><div class="line"> </div><div class="line"> }</div></pre></td></tr></table></figure>
</li>
</ul>
<p>自定义属性:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><resources></div><div class="line"> <declare-styleable name="WaveLoadCircle"></div><div class="line"> <attr name="color" format="color"/></div><div class="line"> <attr name="text" format="string"/></div><div class="line"> </declare-styleable></div><div class="line"> </div><div class="line"></resources></div></pre></td></tr></table></figure>
<p>实现这样的View是通过Canvas、Paint、Path来画了四层效果图将其叠加在一起:</p>
<p><img src="http://img.blog.csdn.net/20170801102632645?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<p>那么首先就是画最底下那个文字,这里有个问题就是如何将文字画到画布的中间呢,下面的这句代码其实只是对齐了x轴,也就是水平居中了,所以就是如何才能让其垂直居中呢,</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">Rect rect = new Rect(0, 0, mWidth, mHeight);</div><div class="line">paint.setTextAlign(Paint.Align.CENTER);</div></pre></td></tr></table></figure>
<p>先来看一个文字绘制时如何的定位:</p>
<p><img src="http://img.blog.csdn.net/20170801103127617?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<p>所以,文字的y轴居中坐标:centerY = (画布高度 - 字体.assent - 字体.descent)/2,这样画到画布的文字才会居中显示:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 为了将文字画在画布的中央,centerY = (画布高度 - 字体.assent - 字体.descent)/2</div><div class="line"> *</div><div class="line"> * @param canvas</div><div class="line"> * @param paint</div><div class="line"> */</div><div class="line"> private void drawCentertext(Canvas canvas, Paint paint) {</div><div class="line"> Rect rect = new Rect(0, 0, mWidth, mHeight);</div><div class="line"> paint.setTextAlign(Paint.Align.CENTER);</div><div class="line"> Paint.FontMetrics pf = paint.getFontMetrics();</div><div class="line"> int centerY = (int) ((mHeight - pf.ascent - pf.descent) / 2);</div><div class="line"> canvas.drawText(content, rect.centerX(), centerY, paint);</div><div class="line"></div><div class="line"> }</div></pre></td></tr></table></figure>
<p>最底下的文字画好以后,就是第二层画波浪线,利用Path来完成这个使命,示意图如下:</p>
<p><img src="http://upload-images.jianshu.io/upload_images/2198310-06ae6f9ad5309b7f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="这里写图片描述"></p>
<p>图中的灰色就是我们的画布,为了能够实现波浪的波动,因为Path中没有画sin 或者 cos的曲线,所以就选择用贝塞尔曲线来画一段曲线。要想实现波浪的波动,图中左边的起点会不断向右滑动,所以绘制一个上边是图中所示的闭合矩形:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">/**</div><div class="line"> * 绘制一个上边是由4段二阶贝塞尔曲线的矩形,区间位置-mWidth ~ mWidth</div><div class="line"> *</div><div class="line"> * @param percent</div><div class="line"> * @return</div><div class="line"> */</div><div class="line">public Path getWavePath(float percent) {</div><div class="line"> Path path = new Path();</div><div class="line"> float x = -mWidth * percent;</div><div class="line"> path.moveTo(x, mHeight * (1 - ratio));</div><div class="line"> //控制点的相对宽度</div><div class="line"> int qWidth = mWidth / 4;</div><div class="line"> //控制点的相对高度</div><div class="line"> int qHeight = qWidth / 2;</div><div class="line"> //第一个波浪</div><div class="line"> path.rQuadTo(qWidth, qHeight, qWidth * 2, 0);</div><div class="line"> path.rQuadTo(qWidth, -qHeight, qWidth * 2, 0);</div><div class="line"> //第二个波浪</div><div class="line"> path.rQuadTo(qWidth, qHeight, qWidth * 2, 0);</div><div class="line"> path.rQuadTo(qWidth, -qHeight, qWidth * 2, 0);</div><div class="line"> //右侧的直线</div><div class="line"> path.lineTo(x + mWidth * 2, mHeight);</div><div class="line"></div><div class="line"> path.lineTo(x, mHeight);</div><div class="line"> //自动闭合补出左边的直线</div><div class="line"> path.close();</div><div class="line"> return path;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>接着裁剪该path的闭合路径:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">// 获取path路径为一个上边为贝塞尔曲线的矩形</div><div class="line"> path = getWavePath(curPercent);</div><div class="line"> Log.i("tag", "onDraw:percent " + curPercent);</div><div class="line"> // 在画布上面裁剪该path</div><div class="line"> canvas.clipPath(path);</div></pre></td></tr></table></figure>
<p>在裁剪后的画布上面画圆(画圆的画笔颜色是波浪的颜色):</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">// 画圆</div><div class="line"> canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint);</div></pre></td></tr></table></figure>
<p>最后一层就是再画一个文字和最底层文字一样,但是颜色为白色的文字:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">textPaint.setColor(Color.WHITE);</div><div class="line"> // 再画一个颜色与上面字体颜色不一样的字</div><div class="line"> drawCentertext(canvas, textPaint);</div></pre></td></tr></table></figure>
<p>通过ValueAnimator来设置波浪的移动距离:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">// 波浪水平移动的速率</div><div class="line"> ValueAnimator anim = ValueAnimator.ofFloat(0, 1);</div><div class="line"> anim.setDuration(1000);</div><div class="line"> anim.setRepeatCount(ValueAnimator.INFINITE); // 无限重复</div><div class="line"> anim.setRepeatMode(ValueAnimator.RESTART);//重头再来</div><div class="line"> anim.setInterpolator(new LinearInterpolator());</div><div class="line"> anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {</div><div class="line"> @Override</div><div class="line"> public void onAnimationUpdate(ValueAnimator animation) {</div><div class="line"> curPercent = animation.getAnimatedFraction();// 将0~1 的动画值不断得赋值当前的进度</div><div class="line"> Log.i("tag", "onAnimationUpdate: " + curPercent);</div><div class="line"> invalidate();</div><div class="line"> }</div><div class="line"> });</div><div class="line"> anim.start();</div></pre></td></tr></table></figure>
<p>添加一个设置波浪高度的方法:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 设置波浪的高度与view高度的比值(0f ~ 1f)</div><div class="line"> *</div><div class="line"> * @param ratio</div><div class="line"> */</div><div class="line"> public void setWaveHeightRatio(float ratio) {</div><div class="line"> this.ratio = ratio;</div><div class="line"> invalidate();</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>好了,基本流程就是这样。<a href="https://github.com/luweicheng24/CircleWaveLoad" target="_blank" rel="external">github源码链接</a></p>
]]></content>
<summary type="html">
<blockquote>
<p>引言</p>
<p>功能来源于需求 ,给我一盒画笔,我将画出整个世界。</p>
</blockquote>
<p>本篇记录一次自定义类似加速球的自定义实现:</p>
<ul>
<li>效果图<br><img src="http://img.blog.csdn.net/20170801101147935?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述">
</summary>
<category term="Android" scheme="https://luweicheng24.github.io/categories/Android/"/>
<category term="自定义View" scheme="https://luweicheng24.github.io/tags/%E8%87%AA%E5%AE%9A%E4%B9%89View/"/>
</entry>
<entry>
<title>自定义轮播图</title>
<link href="https://luweicheng24.github.io/2017/08/21/banner/"/>
<id>https://luweicheng24.github.io/2017/08/21/banner/</id>
<published>2017-08-21T06:28:57.000Z</published>
<updated>2017-08-21T07:12:34.636Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>引言<br>作为一名Android开发者对于自定义View的掌握体现利润他对控件的深入理解,我下面是自定义ViewGroup实现轮播图;</p>
</blockquote>
<a id="more"></a>
<blockquote>
<p>效果图</p>
</blockquote>
<p><img src="http://img.blog.csdn.net/20170327084841849?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="轮播图效果图"></p>
<p>效果图就是这样,自动轮播,可对每张图片进行点击监听,接下来我们先看一下自定义ViewGroup实现实现的代码:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div></pre></td><td class="code"><pre><div class="line">public class ImageBannerViewGroup extends ViewGroup {</div><div class="line"> private int lastX; //滑动的上一次位置</div><div class="line"> private int childerCount; //子控件的个数</div><div class="line"> private int width; //屏幕的宽度</div><div class="line"> private int height; //Banner图的高度</div><div class="line"> private int index = 0; //Banner图索引</div><div class="line"> private int startX; //滑动的起始位置</div><div class="line"> private Timer timer;</div><div class="line"> private List<Integer> banners;</div><div class="line"> private Boolean isClick = true; //是否点击</div><div class="line"> private Boolean isAuto = true; //是否自动轮播</div><div class="line"> private Handler mHandler = new Handler() {</div><div class="line"> @Override</div><div class="line"> public void handleMessage(Message msg) {</div><div class="line"> super.handleMessage(msg);</div><div class="line"> if (msg.what == 0) {</div><div class="line"> if (++index >= childerCount) {</div><div class="line"> index = 0;</div><div class="line"> }</div><div class="line"> if (bannerDotListener != null) {</div><div class="line"> bannerDotListener.bannerDotListener(index);</div><div class="line"> }</div><div class="line"> scrollTo(index * width, 0);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> };</div><div class="line"></div><div class="line"> public void setAuto(Boolean isAuto) {</div><div class="line"> this.isAuto = isAuto;</div><div class="line"> }</div><div class="line"></div><div class="line"> public ImageBannerViewGroup(Context context) {</div><div class="line"> this(context, null);</div><div class="line"> }</div><div class="line"></div><div class="line"> public ImageBannerViewGroup(Context context, @Nullable AttributeSet attrs) {</div><div class="line"> this(context, attrs, 0);</div><div class="line"> }</div><div class="line"></div><div class="line"> public ImageBannerViewGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {</div><div class="line"> super(context, attrs, defStyleAttr);</div><div class="line"> timer = new Timer();</div><div class="line"> timer.schedule(new TimerTask() {</div><div class="line"> @Override</div><div class="line"> public void run() {</div><div class="line"> if (isAuto) {</div><div class="line"> mHandler.sendEmptyMessage(0);</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"> }, 1000, 3000);</div><div class="line"> }</div><div class="line"></div><div class="line"> //测量</div><div class="line"> @Override</div><div class="line"> protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {</div><div class="line"> childerCount = getChildCount();</div><div class="line"> if (childerCount == 0) {</div><div class="line"> setMeasuredDimension(0, 0);</div><div class="line"> } else {</div><div class="line"> measureChild(getChildAt(0), widthMeasureSpec, heightMeasureSpec);</div><div class="line"> DisplayMetrics dm = new DisplayMetrics();</div><div class="line"> ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm);</div><div class="line"> width = dm.widthPixels;</div><div class="line"> height = dm.heightPixels / 3;//轮播图为手机全屏高度的三分之一</div><div class="line"> setMeasuredDimension(width * childerCount, height);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> @Override</div><div class="line"> protected void onLayout(boolean changed, int l, int t, int r, int b) {</div><div class="line"> if (changed) {</div><div class="line"> int leftMargin = 0;</div><div class="line"> for (int i = 0; i < childerCount; i++) {</div><div class="line"> View view = getChildAt(i);</div><div class="line"> view.layout(leftMargin, 0, leftMargin + width, height);</div><div class="line"> leftMargin += width;</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public boolean onInterceptTouchEvent(MotionEvent ev) {</div><div class="line"> return true;</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public boolean onTouchEvent(MotionEvent event) {</div><div class="line"> switch (event.getAction()) {</div><div class="line"></div><div class="line"> case MotionEvent.ACTION_DOWN:</div><div class="line"> isClick = true;</div><div class="line"> isAuto = false;</div><div class="line"> startX = (int) event.getX();</div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_MOVE:</div><div class="line"> isClick = false;</div><div class="line"> lastX = (int) event.getX();</div><div class="line"> int offsetX = startX - lastX;</div><div class="line"> if (index == 0 && offsetX < 0) {</div><div class="line"> return true;</div><div class="line"> } else if (index == childerCount - 1 && offsetX > 0) {</div><div class="line"> return true;</div><div class="line"> }</div><div class="line"></div><div class="line"> scrollBy(offsetX, 0);</div><div class="line"> startX = lastX;</div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_UP:</div><div class="line"> index = (getScrollX() + width / 2) / width;</div><div class="line"> Log.e("点击", "onTouchEvent:click " + isClick);</div><div class="line"></div><div class="line"> if (isClick && bannerImagClickListener != null) {</div><div class="line"> bannerImagClickListener.bannerClick(index);</div><div class="line"> Log.e("点击", "onTouchEvent:click " + index);</div><div class="line"> } else {</div><div class="line"></div><div class="line"> if (index < 0) {</div><div class="line"> index = 0;</div><div class="line"></div><div class="line"> } else if (index == childerCount - 1) {</div><div class="line"></div><div class="line"> index = childerCount - 1;</div><div class="line"> }</div><div class="line"></div><div class="line"> if (bannerDotListener != null) {</div><div class="line"> bannerDotListener.bannerDotListener(index);</div><div class="line"> }</div><div class="line"> scrollTo(index * width, 0);</div><div class="line"> isAuto = true;</div><div class="line"> }</div><div class="line"> break;</div><div class="line"></div><div class="line"> }</div><div class="line"> return true;</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * banner图点击事件回调接口</div><div class="line"> */</div><div class="line"> public interface BannerImagClickListener {</div><div class="line"> void bannerClick(int pos);</div><div class="line"> }</div><div class="line"></div><div class="line"> private BannerImagClickListener bannerImagClickListener;</div><div class="line"></div><div class="line"> public void setBannerImagClickListener(BannerImagClickListener bannerImagClickListener) {</div><div class="line"> this.bannerImagClickListener = bannerImagClickListener;</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * banner图的dot点的滑动监听</div><div class="line"> */</div><div class="line"> public interface BannerDotListener {</div><div class="line"> void bannerDotListener(int pos);</div><div class="line"> }</div><div class="line"></div><div class="line"> private BannerDotListener bannerDotListener;</div><div class="line"></div><div class="line"> public void setBannerDotListener(BannerDotListener bannerDotListener) {</div><div class="line"> this.bannerDotListener = bannerDotListener;</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>虽然代码不多,但是逻辑要理清,对于自定义ViewGroup,分三步走:</p>
<ol>
<li>onMeasure()测量</li>
<li>onLayout()布局</li>
<li>onDraw()绘制<br>这里我们只用了前两个对父布局和子布局进行了测量和,布置,具体看上面的代码,打了很多注释,多看应该很清楚,这里有个知识点就是ScrollerTo和ScrollerBy的使用规则,其实就是绝对滑动和相对滑动,在ViewGroup中滑动的是子布局,在其他子View中,比如TextView,实现滑动的话,将会是内部内容也就是TextView中的字体进行滑动,还有就是在OnTouchEvent中对触摸事件的判断逻辑,以及在ViewGroup中如何进行事件传递,就是责任链模式,这里我大概说一下ViewGroup中事件的传递,首先在Activity中接收到触摸事件,在ViewGroup中首先对调用自身的onInterceptTouchEvent事件,根据返回的Boolean值判断该事件是否阻断然后自身使用,如果返回False,将调用自身的dispatchTouchEvent来将事件分发给子View,如果是True,将会调用自身的OnTouchEvent来进行事件分类和处理。上面的代码实现了的轮播和点击,没有轮播图下面的索引点的切换,所以我继图片续自定义了一个ViewGroup继承FrameLayout来添加上面的ViewGroup和一个Linearalayout,在LinearLayout中添加索引的指示布局:</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div></pre></td><td class="code"><pre><div class="line">package com.gsww.www.scrollertest;</div><div class="line"></div><div class="line">import android.content.Context;</div><div class="line">import android.support.annotation.AttrRes;</div><div class="line">import android.support.annotation.NonNull;</div><div class="line">import android.support.annotation.Nullable;</div><div class="line">import android.util.AttributeSet;</div><div class="line">import android.view.Gravity;</div><div class="line">import android.view.ViewGroup;</div><div class="line">import android.widget.FrameLayout;</div><div class="line">import android.widget.ImageView;</div><div class="line">import android.widget.LinearLayout;</div><div class="line"></div><div class="line">/**</div><div class="line"> * Author : luweicheng on 2017/3/24 0024 16:46</div><div class="line"> * E-mail :1769005961@qq.com</div><div class="line"> * GitHub : https://github.com/luweicheng24</div><div class="line"> */</div><div class="line"></div><div class="line">public class BannerFrameLayout extends FrameLayout implements ImageBannerViewGroup.BannerDotListener {</div><div class="line"> private ImageBannerViewGroup mImageBannerViewGroup;</div><div class="line"> private LinearLayout mLinearLayout;</div><div class="line"></div><div class="line"> public ImageBannerViewGroup getmImageBannerViewGroup() {</div><div class="line"> return mImageBannerViewGroup;</div><div class="line"> }</div><div class="line"></div><div class="line"> public void setmImageBannerViewGroup(ImageBannerViewGroup mImageBannerViewGroup) {</div><div class="line"> this.mImageBannerViewGroup = mImageBannerViewGroup;</div><div class="line"> }</div><div class="line"></div><div class="line"> public LinearLayout getmLinearLayout() {</div><div class="line"> return mLinearLayout;</div><div class="line"> }</div><div class="line"></div><div class="line"> public void setmLinearLayout(LinearLayout mLinearLayout) {</div><div class="line"> this.mLinearLayout = mLinearLayout;</div><div class="line"> }</div><div class="line"></div><div class="line"> private Integer[] banners;</div><div class="line"></div><div class="line"> public BannerFrameLayout(@NonNull Context context) {</div><div class="line"> this(context, null);</div><div class="line"> }</div><div class="line"></div><div class="line"> public BannerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {</div><div class="line"> this(context, attrs, 0);</div><div class="line"> }</div><div class="line"></div><div class="line"> public BannerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {</div><div class="line"> super(context, attrs, defStyleAttr);</div><div class="line"> initDragView();</div><div class="line"> initLinearLayout();</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 设置Banner图的集合</div><div class="line"> *</div><div class="line"> * @param banners</div><div class="line"> * @param screenWidth 屏幕宽度</div><div class="line"> * @param screenHeight 屏幕高度</div><div class="line"> */</div><div class="line"> public void addBanners(final Integer[] banners, int screenWidth, int screenHeight) {</div><div class="line"> this.banners = banners;</div><div class="line"> for (int i = 0; i < banners.length; i++) {</div><div class="line"> ImageView img = new ImageView(getContext());</div><div class="line"> img.setBackgroundResource(banners[i]);</div><div class="line"> img.setId(i);</div><div class="line"> ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(screenWidth * banners.length, screenHeight / 4);</div><div class="line"> img.setScaleType(ImageView.ScaleType.CENTER_CROP);</div><div class="line"> img.setLayoutParams(lp);</div><div class="line"> mImageBannerViewGroup.addView(img);</div><div class="line"> }</div><div class="line"> addDotToLinearLayout(banners.length);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> private void addDotToLinearLayout(int dotCount) {</div><div class="line"> for (int i = 0; i < dotCount; i++) {</div><div class="line"> ImageView dot = new ImageView(getContext());</div><div class="line"> LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);</div><div class="line"> lp.setMargins(5, 0, 0, 0);</div><div class="line"> dot.setBackgroundResource(R.drawable.dot_drawable);</div><div class="line"> dot.setLayoutParams(lp);</div><div class="line"> mLinearLayout.addView(dot);</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> private void initLinearLayout() {</div><div class="line"> mLinearLayout = new LinearLayout(getContext());</div><div class="line"> FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 100);</div><div class="line"> lp.gravity = Gravity.BOTTOM;</div><div class="line"> mLinearLayout.setLayoutParams(lp);</div><div class="line"> mLinearLayout.setGravity(Gravity.CENTER);</div><div class="line"></div><div class="line"> addView(mLinearLayout);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> private void initDragView() {</div><div class="line"> mImageBannerViewGroup = new ImageBannerViewGroup(getContext());</div><div class="line"> ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);</div><div class="line"> mImageBannerViewGroup.setLayoutParams(lp);</div><div class="line"> addView(mImageBannerViewGroup);</div><div class="line"> mImageBannerViewGroup.setBannerDotListener(this);</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void bannerDotListener(int pos) {</div><div class="line"> for (int i = 0; i < mLinearLayout.getChildCount(); i++) {</div><div class="line"> if (pos == i) {</div><div class="line"> ImageView img = (ImageView) mLinearLayout.getChildAt(i);</div><div class="line"> img.setBackgroundResource(R.drawable.dot_select);</div><div class="line"> } else {</div><div class="line"> ImageView img = (ImageView) mLinearLayout.getChildAt(i);</div><div class="line"> img.setBackgroundResource(R.drawable.dot_no_select);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>在自定义FrameLayout中我初始化了图片轮播的ViewGroup和索引布局LinearLayout,在使用的时候如下布局和使用:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><com.gsww.www.scrollertest.BannerFrameLayout</div><div class="line"> xmlns:android="http://schemas.android.com/apk/res/android"</div><div class="line"> android:id="@+id/mBannerFrameLayout"</div><div class="line"> android:layout_width="match_parent"</div><div class="line"> android:layout_height="wrap_content"></div><div class="line"></com.gsww.www.scrollertest.BannerFrameLayout></div><div class="line"></div><div class="line"></div><div class="line">package com.gsww.www.scrollertest;</div><div class="line"></div><div class="line">import android.os.Bundle;</div><div class="line">import android.support.v7.app.AppCompatActivity;</div><div class="line">import android.util.DisplayMetrics;</div><div class="line">import android.widget.Toast;</div><div class="line"></div><div class="line">public class MainActivity extends AppCompatActivity implements ImageBannerViewGroup.BannerImagClickListener {</div><div class="line"> private BannerFrameLayout banner;</div><div class="line"> private Integer[] imgs = {R.drawable.girl_3, R.drawable.girl_5, R.drawable.girl_6,</div><div class="line"> R.drawable.girl_4, R.drawable.girl_7, R.drawable.girl_9};</div><div class="line"> private int screenWidth;</div><div class="line"> private int screenHeight;</div><div class="line"></div><div class="line"> @Override</div><div class="line"> protected void onCreate(Bundle savedInstanceState) {</div><div class="line"> super.onCreate(savedInstanceState);</div><div class="line"> getSupportActionBar().hide();</div><div class="line"> setContentView(R.layout.main);</div><div class="line"> banner = (BannerFrameLayout) findViewById(R.id.mBannerFrameLayout);</div><div class="line"> DisplayMetrics dm = new DisplayMetrics();</div><div class="line"> getWindowManager().getDefaultDisplay().getMetrics(dm);</div><div class="line"> screenWidth = dm.widthPixels;</div><div class="line"> screenHeight = dm.heightPixels;</div><div class="line"> banner.addBanners(imgs, screenWidth, screenHeight);</div><div class="line"> banner.getmImageBannerViewGroup().setBannerImagClickListener(this);</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void bannerClick(int pos) {</div><div class="line"> Toast.makeText(this, ""+pos, Toast.LENGTH_SHORT).show();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>好了,自定义轮播图就这样完成了,<a href="https://github.com/luweicheng24/ScrollerBanners" target="_blank" rel="external">源码点击下载</a></p>
]]></content>
<summary type="html">
<blockquote>
<p>引言<br>作为一名Android开发者对于自定义View的掌握体现利润他对控件的深入理解,我下面是自定义ViewGroup实现轮播图;</p>
</blockquote>
</summary>
<category term="Android" scheme="https://luweicheng24.github.io/categories/Android/"/>
<category term="自定义ViewGroup" scheme="https://luweicheng24.github.io/tags/%E8%87%AA%E5%AE%9A%E4%B9%89ViewGroup/"/>
</entry>
<entry>
<title>踩黑块</title>
<link href="https://luweicheng24.github.io/2017/08/21/%E8%B8%A9%E9%BB%91%E5%9D%97/"/>
<id>https://luweicheng24.github.io/2017/08/21/踩黑块/</id>
<published>2017-08-21T06:12:29.000Z</published>
<updated>2017-08-21T06:25:28.752Z</updated>
<content type="html"><![CDATA[<p>这篇文章通过自定义ViewGroup实现前段时间挺火的一个游戏——别踩白块。好了先看一下效果图:</p>
<p><img src="http://img.blog.csdn.net/20170503141750007?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<a id="more"></a>
<p>好了,下面我说一下我的思路,大家都知道重写ViewGroup的步骤:onMesure(),onDraw( ),onLayout(),这里我只需要重写onDraw()和onTouchEvent();好了,我首先创建的一个矩形类继承RectF类,创建了误了静态常量和两个构造函数:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line">import android.graphics.RectF;</div><div class="line"></div><div class="line">/**</div><div class="line"> * Author : luweicheng on 2017/4/30 0030 12:16</div><div class="line"> * E-mail :1769005961@qq.com</div><div class="line"> * GitHub : https://github.com/luweicheng24</div><div class="line"> * funcation: 矩形框类</div><div class="line"> */</div><div class="line"></div><div class="line">public class PiecesRectF extends RectF {</div><div class="line"></div><div class="line"> private int type;</div><div class="line"></div><div class="line"> public final static int BLAKE = 0;//黑块</div><div class="line"> public final static int WRITE = 1;//白块</div><div class="line"> public final static int BLUE = 2;//黑块按下时的显示蓝块</div><div class="line"> public final static int START = 3;//标记有开始的黑块</div><div class="line"> public final static int RED = 4;//按到白块,或有黑块漏按,游戏结束时的红块</div><div class="line"></div><div class="line"> public PiecesRectF(){</div><div class="line"> super();</div><div class="line"> type = Math.random() > 0.5 ? 0:1;//初始化时,给type随机一个白块或黑块</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 创建最后一行的矩形</div><div class="line"> * @param isLast</div><div class="line"> */</div><div class="line"> public PiecesRectF(Boolean isLast){</div><div class="line"> super();</div><div class="line"> }</div><div class="line"> public void setType(int type) {</div><div class="line"> this.type = type;</div><div class="line"> }</div><div class="line"></div><div class="line"> public int getType() {</div><div class="line"> return type;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>该类对象就想到于每个矩形框,类型有五种类型,注释也已经写的很清楚了。下面我们就来继承ViewGroup来自定义我们的ViewGroup:继承之后我们先来对初始化五行四列的二维数组来存放矩形框,由于第五行的矩形框要作为开始按钮,所以单独创建了第五行,第五行只有一个类型的开始的矩形框,其他的都是类型为白色的矩形框:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 初始化5行4列的矩形框</div><div class="line"> */</div><div class="line"> private void initRect() {</div><div class="line"> /**</div><div class="line"> * 创建4行4列的方块(每行1,2列最少有一个黑块,3,4列最少有一个黑块)</div><div class="line"> */</div><div class="line"></div><div class="line"> for (int i = 0; i < 4; i++) {</div><div class="line"> for (int j = 0; j < 4; j++) {</div><div class="line"> recfs[i][j] = new PiecesRectF();</div><div class="line"> if (j == 1) {</div><div class="line"></div><div class="line"> if (recfs[i][j - 1].getType() == PiecesRectF.BLAKE || recfs[i][j - 1].getType() == PiecesRectF.START) {</div><div class="line"> recfs[i][j].setType(PiecesRectF.WRITE);</div><div class="line"> }</div><div class="line"> } else if (j == 3) {</div><div class="line"> if (recfs[i][j - 1].getType() == PiecesRectF.BLAKE || recfs[i][j - 1].getType() == PiecesRectF.START) {</div><div class="line"> recfs[i][j].setType(PiecesRectF.WRITE);</div><div class="line"> }</div><div class="line"> if (recfs[i][j - 2].getType() == PiecesRectF.WRITE && recfs[i][j - 3].getType() == PiecesRectF.WRITE) {</div><div class="line"> recfs[i][j].setType(PiecesRectF.BLAKE);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> }</div><div class="line"> }//创建第五行的数据,只需要一个类型为开始的矩形,其他的都是白色</div><div class="line"> for (int i = 0; i < 4; i++) {</div><div class="line"> recfs[4][i]= new PiecesRectF(true);</div><div class="line"> if(i==1){</div><div class="line"> recfs[4][i].setType(PiecesRectF.START);</div><div class="line"> }else {</div><div class="line"> recfs[4][i].setType(PiecesRectF.WRITE);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div></pre></td></tr></table></figure>
<p>初始化好了矩形框,接下来就是绘制矩形框绘制的时候由于要保持界面只呈现四行四列的黑白快,并且界面是从上往下滑动,所以我们初始化的时候将第一行的矩形框根据左右上下的设置将其基本是绘制成了一条线,因此用户看见的第一行矩形框其实就是第二行矩形框,下面是重写OnDraw方法根据二位数据里面矩形框的类型来绘制:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">/**</div><div class="line"> * 绘制矩形框</div><div class="line"> *</div><div class="line"> * @param canvas</div><div class="line"> */</div><div class="line">private void drawRects(Canvas canvas) {</div><div class="line"> int w = getWidth() / 4;</div><div class="line"> int h = getHeight() / 4;</div><div class="line"> if (isGameOver) {</div><div class="line"> if(onBalckCheckListener !=null){</div><div class="line"> onBalckCheckListener.gameOver();</div><div class="line"> }</div><div class="line"> isGameOver = false;</div><div class="line"> }</div><div class="line"> for (int i = 0; i < 5; i++) {</div><div class="line"> for (int j = 0; j < 4; j++) {</div><div class="line"> recfs[i][j].left = w * j;</div><div class="line"> recfs[i][j].right = w * (j + 1);</div><div class="line"> recfs[i][j].bottom = topRectHeight + i * h;</div><div class="line"> recfs[i][j].top = recfs[i][j].bottom - h;</div><div class="line"> paint.setStyle(Paint.Style.FILL);//设置画笔为填充整个矩形</div><div class="line"> if (recfs[i][j].getType() == PiecesRectF.WRITE) {</div><div class="line"></div><div class="line"> paint.setColor(Color.WHITE);</div><div class="line"> canvas.drawRect(recfs[i][j], paint);</div><div class="line"></div><div class="line"> } else if (recfs[i][j].getType() == PiecesRectF.BLAKE) {</div><div class="line"></div><div class="line"> paint.setColor(Color.BLACK);</div><div class="line"> canvas.drawRect(recfs[i][j], paint);</div><div class="line"></div><div class="line"> } else if (recfs[i][j].getType() == PiecesRectF.BLUE) {</div><div class="line"></div><div class="line"> paint.setColor(Color.BLUE);</div><div class="line"> canvas.drawRect(recfs[i][j], paint);</div><div class="line"></div><div class="line"> } else if (recfs[i][j].getType() == PiecesRectF.RED) {</div><div class="line"></div><div class="line"> paint.setColor(Color.RED);</div><div class="line"> canvas.drawRect(recfs[i][j], paint);</div><div class="line"></div><div class="line"> } else if (recfs[i][j].getType() == PiecesRectF.START) {</div><div class="line"></div><div class="line"> paint.setColor(Color.BLACK);</div><div class="line"> canvas.drawRect(recfs[i][j], paint);</div><div class="line"></div><div class="line"> //在绘制文字</div><div class="line"> paint.setColor(Color.parseColor("#ffffff"));</div><div class="line"> paint.setTextAlign(Paint.Align.CENTER);</div><div class="line"> paint.setTextSize(50);</div><div class="line"></div><div class="line"> String start = "开始";</div><div class="line"> Rect bounds = new Rect();</div><div class="line"> paint.getTextBounds(start, 0, start.length(), bounds);</div><div class="line"> float x = recfs[i][j].left / 2 + recfs[i][j].right / 2;</div><div class="line"> float y = recfs[i][j].top / 2 + recfs[i][j].bottom / 2 + bounds.bottom / 2 - bounds.top / 2;</div><div class="line"> canvas.drawText(start, x, y, paint);</div><div class="line"> }</div><div class="line"> /**</div><div class="line"> * 绘制边框</div><div class="line"> */</div><div class="line"> paint.setStyle(Paint.Style.STROKE);</div><div class="line"> paint.setColor(Color.parseColor("#cccccc"));</div><div class="line"> paint.setStrokeWidth(3);</div><div class="line"> canvas.drawRect(recfs[i][j], paint);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>可以看到由于topRectHeight的初始化为0,所以绘制的第一行在界面看不见,所以我们可以根据不断增加该值之后的绘制实现向下滑动,绘制结果如下:</p>
<p><img src="http://img.blog.csdn.net/20170503143912052?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<p>好了,绘制成功喽,下面就是对它每个矩形点击的监听处理:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div></pre></td><td class="code"><pre><div class="line">@Override</div><div class="line"> public boolean onTouchEvent(MotionEvent event) {</div><div class="line"> int index = event.getActionIndex();</div><div class="line"> switch (event.getActionMasked()){</div><div class="line"> case ACTION_DOWN:</div><div class="line"> case MotionEvent.ACTION_POINTER_DOWN:{</div><div class="line"> int id = event.getPointerId(index);</div><div class="line"> //判断点击的是那个矩形块</div><div class="line"> for (int i = 0; i < 5; i++) {</div><div class="line"> for (int j = 0; j < 4; j++) {</div><div class="line"> PiecesRectF f = recfs[i][j];</div><div class="line"> if (event.getX() > f.left && event.getX() < f.right</div><div class="line"> && event.getY() < f.bottom && event.getY() > f.top) {</div><div class="line"> selectRecfs.put(id, f);</div><div class="line"> if (f.getType() == PiecesRectF.BLAKE) {</div><div class="line"> f.setType(PiecesRectF.BLUE);</div><div class="line"> score++;</div><div class="line"> } else if (f.getType() == PiecesRectF.WRITE) {</div><div class="line"> f.setType(PiecesRectF.RED);</div><div class="line"> isGameOver = true;</div><div class="line"> postInvalidate();</div><div class="line"> } else if (f.getType() == PiecesRectF.START) {</div><div class="line"> f.setType(PiecesRectF.BLUE);</div><div class="line"> startThread();</div><div class="line"> }</div><div class="line"> if(onBalckCheckListener !=null){</div><div class="line"> onBalckCheckListener.score(score);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_UP:</div><div class="line"> case MotionEvent.ACTION_POINTER_UP: {</div><div class="line"> int id = event.getPointerId(index);</div><div class="line"> PiecesRectF f = selectRecfs.get(id, null);//得到某个手指选中的方块</div><div class="line"> if (f != null && f.getType() == PiecesRectF.BLUE) {</div><div class="line"> //手指抬起后,将蓝色重新变红</div><div class="line"> f.setType(PiecesRectF.WRITE);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> break;</div><div class="line"></div><div class="line"> }</div><div class="line"> return true;//事件终止传递</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>在事件处理中对矩形的类型进行判断处理,将点击的矩形保存在SparseArray数组中,如果点击的是开始,将开启一个线程对矩形数组和检查是否有黑框漏点:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 开启线程不断的对界面进行绘制</div><div class="line"> */</div><div class="line"> private void startThread() {</div><div class="line"></div><div class="line"> new Thread(){</div><div class="line"> @Override</div><div class="line"> public void run() {</div><div class="line"></div><div class="line"> while (true) {</div><div class="line"> /**</div><div class="line"> * 判断是否含有黑块接触屏幕底端</div><div class="line"> */</div><div class="line"> if(topRectHeight>0){</div><div class="line"> if(checkHasBlack()){</div><div class="line"> isGameOver = true;</div><div class="line"> postInvalidate();</div><div class="line"> return;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> topRectHeight += getSpeed();//固定的矩形下滑速度</div><div class="line"> if(isGameOver){</div><div class="line"> return;</div><div class="line"> }</div><div class="line"> if (topRectHeight > getHeight() / 4) {//如果顶层的方块高度超出清零</div><div class="line"> topRectHeight = 0;</div><div class="line"> updateView();//更新矩形块</div><div class="line"> }</div><div class="line"> try {</div><div class="line"> sleep(15);</div><div class="line"> } catch (InterruptedException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line"> postInvalidate();</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }.start();</div><div class="line"> }</div></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 检查最后一行是否含有黑块</div><div class="line"> * @return</div><div class="line"> */</div><div class="line"> private Boolean checkHasBlack() {</div><div class="line"> Boolean hasBlack = false;</div><div class="line"> for (int i = 0; i < 4; i++) {</div><div class="line"> if (recfs[4][i].getType() == PiecesRectF.BLAKE||recfs[4][i].getType() == PiecesRectF.START){</div><div class="line"> recfs[4][i].setType(PiecesRectF.RED);</div><div class="line"> hasBlack = true;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> return hasBlack;</div><div class="line"> }</div><div class="line"></div><div class="line"> /**</div><div class="line"> * 从倒数第二行开始跟新到未出现的第一行</div><div class="line"> */</div><div class="line"> private void updateView(){</div><div class="line"></div><div class="line"> for (int i = 4; i >=0; i--) {</div><div class="line"> for (int j = 0; j < 4; j++) {</div><div class="line"> if(i==0){</div><div class="line"> recfs[i][j] = new PiecesRectF();</div><div class="line"> if (j == 1){</div><div class="line"> if (recfs[i][j-1].getType() == PiecesRectF.BLAKE)</div><div class="line"> recfs[i][j].setType(PiecesRectF.WRITE);</div><div class="line"> }else if (j == 3){</div><div class="line"> if (recfs[i][j-1].getType() == PiecesRectF.BLAKE)</div><div class="line"> recfs[i][j].setType(PiecesRectF.WRITE);</div><div class="line"> else if (recfs[i][j-2].getType() == PiecesRectF.WRITE &&</div><div class="line"> recfs[i][j-3].getType() == PiecesRectF.WRITE)</div><div class="line"> recfs[i][j].setType(PiecesRectF.BLAKE);</div><div class="line"> }</div><div class="line"> }else{</div><div class="line"> recfs[i][j] = recfs[i-1][j];</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> </div><div class="line"> }</div></pre></td></tr></table></figure>
<p>创建一个接口来监听分数和游戏是否结束:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 重新开始游戏</div><div class="line"> */</div><div class="line"> public void restart(){</div><div class="line"> isGameOver = false;</div><div class="line"> topRectHeight= 0;//顶层高度归零</div><div class="line"> score = 0;//分数归零</div><div class="line"> onBalckCheckListener.score(score);</div><div class="line"> initRect();//重新初始化</div><div class="line"> invalidate();//再次绘制</div><div class="line"> }</div><div class="line"></div><div class="line"> public interface OnBalckCheckListener{</div><div class="line"> void score(int score);</div><div class="line"> void gameOver();</div><div class="line"> }</div><div class="line"> private OnBalckCheckListener onBalckCheckListener;</div><div class="line"></div><div class="line"> public void setOnBalckCheckListener(OnBalckCheckListener onBalckCheckListener){</div><div class="line"> this.onBalckCheckListener = onBalckCheckListener;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>ok,核心代码就是这样<a href="https://github.com/luweicheng24/ClickWhiteBlock" target="_blank" rel="external">Github源码下载</a></p>
]]></content>
<summary type="html">
<p>这篇文章通过自定义ViewGroup实现前段时间挺火的一个游戏——别踩白块。好了先看一下效果图:</p>
<p><img src="http://img.blog.csdn.net/20170503141750007?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
</summary>
<category term="Android" scheme="https://luweicheng24.github.io/categories/Android/"/>
<category term="自定义ViewGroup" scheme="https://luweicheng24.github.io/tags/%E8%87%AA%E5%AE%9A%E4%B9%89ViewGroup/"/>
</entry>
<entry>
<title>自定义具有拉伸阻尼效果的ScrollerView</title>
<link href="https://luweicheng24.github.io/2017/08/21/first/"/>
<id>https://luweicheng24.github.io/2017/08/21/first/</id>
<published>2017-08-21T02:54:19.000Z</published>
<updated>2017-08-21T04:01:55.585Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>引言<br>一切的自定义都是来自于需求,而在项目开发中由于界面条目太多,所以自然而然的使用到了ScrollerView,当把效果给产品经理的时候呢,ios和Android的效果完全不一样,ios自带的上下拉伸回弹的效果,而Android没有,所以自定义一个具有拉伸效果的ScrollerView迫在眉睫啊.</p>
</blockquote>
<a id="more"></a>
<p>首先来看一下效果图,妹子很漂亮,但是注意重点!!!</p>
<p><img src="http://img.blog.csdn.net/20170722211027420?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHV3ZWljaGVuZzI0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描述"></p>
<p>好了,下面进入正题,通过继承ScrollerView来进行相关滑动回弹的效果实现,先来定义几个变量:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">private View childView;// 子View(ScrollerView的唯一子类)</div><div class="line">private int y;// 点击时y坐标</div><div class="line">private Rect rect = new Rect();// 矩形(用来保存inner的初始状态,判断是够需要动画回弹效果)</div></pre></td></tr></table></figure>
<p>注释打的也很清楚,然后我们先在该ScrollerView的xml布局加载完成后获取ScrollerView的唯一子布局赋值给上面定义的childView:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 在xml布局绘制为界面完成时调用,</div><div class="line"> * 获取ScrollerView中唯一的直系子布局(ScrollerView中不许包含一层ViewGroup,有且只有一个)</div><div class="line"> */</div><div class="line"> @Override</div><div class="line"> protected void onFinishInflate() {</div><div class="line"> if (getChildCount() > 0) {</div><div class="line"> childView = getChildAt(0);</div><div class="line"> }</div><div class="line"> super.onFinishInflate();</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>下面就是处理Touch事件了:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * touch 事件处理</div><div class="line"> **/</div><div class="line"> @Override</div><div class="line"> public boolean onTouchEvent(MotionEvent ev) {</div><div class="line"> if (childView != null) {</div><div class="line"> handleTouchEvent(ev);</div><div class="line"> }</div><div class="line"> return super.onTouchEvent(ev);</div><div class="line"> }</div><div class="line"></div><div class="line"> /***</div><div class="line"> * 触摸事件</div><div class="line"> *</div><div class="line"> * @param ev</div><div class="line"> */</div><div class="line"> public void handleTouchEvent(MotionEvent ev) {</div><div class="line"> int action = ev.getAction();</div><div class="line"> switch (action) {</div><div class="line"> case MotionEvent.ACTION_DOWN:</div><div class="line"> y = (int) ev.getY();//按下的时候获取到y坐标</div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_MOVE:</div><div class="line"> int nowY = (int) ev.getY(); // 移动时的实时y坐标</div><div class="line"> int delayY = y - nowY; // 移动时的间隔</div><div class="line"> y = nowY; // 将本次移动结束时的y坐标赋值给下次移动的起始坐标(也就是nowY)</div><div class="line"> if (isNeedMove()) {</div><div class="line"> if (rect.isEmpty()) {</div><div class="line"> //rect保存childView的初始位置信息</div><div class="line"> rect.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());</div><div class="line"> }</div><div class="line"> //移动布局(屏幕移动的距离等于手指滑动距离的一般)</div><div class="line"> childView.layout(childView.getLeft(), childView.getTop() - delayY / 2, childView.getRight(), childView.getBottom() - delayY / 2);</div><div class="line"> }</div><div class="line"></div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_UP:</div><div class="line"> if (isNeedAnimation()) {// 判断rect是否为空,也就是是否被重置了</div><div class="line"> startAnim();//开始回弹动画</div><div class="line"> }</div><div class="line"> break;</div><div class="line"> default:</div><div class="line"> break;</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>对于Touch事件的处理,我注释说的应该很清楚,但是里面有需要调用的四个方法:</p>
<ul>
<li>判断布局是否需要移动</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">/**</div><div class="line"> * 判断布局是否需要移动</div><div class="line"> * @return</div><div class="line"> */</div><div class="line"> private boolean isNeedMove() {</div><div class="line"> int offset = childView.getMeasuredHeight() - getHeight();</div><div class="line"> int scrollY = getScrollY();</div><div class="line"> // 0是顶部,后面那个是底部(需要仔细想一下这个过程)</div><div class="line"> if (scrollY == 0 || scrollY == offset) {</div><div class="line"> return true;</div><div class="line"> }</div><div class="line"> return false;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>其中childView.getMeasuredHeight()为获取到该布局的实际高度,getHeight是该布局在屏幕中显示的高度,getScrollY()是滑动的时候相对于起始位置的距离。</p>
<ul>
<li>判断rect是否为空</li>
</ul>
<p>在加载布局的时候rect进行了初始化,当确定需要滑动时,再判断一下rect是否为空,因为该rect在布局执行动画回弹之后就会被置空,如果当Scroller顶部对其或者底部对其,未在回弹过程就会将该时刻Scroller的位置信息传入到rect,方便回弹的时候根据rect保存的scrollerview的位置信息完成回弹作用。</p>
<ul>
<li>判断是否需要动画</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">public boolean isNeedAnimation() {</div><div class="line"> return !rect.isEmpty();</div><div class="line"> }</div></pre></td></tr></table></figure>
<ul>
<li>执行动画回弹</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">private void startAnim() {</div><div class="line"> TranslateAnimation anim = new TranslateAnimation(0, 0, childView.getTop(), rect.top);</div><div class="line"> anim.setDuration(200);</div><div class="line"> anim.setInterpolator(new OvershootInterpolator());//加速器</div><div class="line"> childView.startAnimation(anim);</div><div class="line"> // 将inner布局重新回到起始位置</div><div class="line"> childView.layout(rect.left, rect.top, rect.right, rect.bottom);</div><div class="line"> rect.setEmpty();</div><div class="line"></div><div class="line"> }</div></pre></td></tr></table></figure>
<p>在执行完动画回弹后即ScrollerView回归了原始状态,于是rect也就置空,方便下一次继续记录,好了,下面直接贴一份完整代码吧:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div></pre></td><td class="code"><pre><div class="line">import android.content.Context;</div><div class="line">import android.graphics.Rect;</div><div class="line">import android.util.AttributeSet;</div><div class="line">import android.view.MotionEvent;</div><div class="line">import android.view.View;</div><div class="line">import android.view.animation.OvershootInterpolator;</div><div class="line">import android.view.animation.TranslateAnimation;</div><div class="line">import android.widget.ScrollView;</div><div class="line"></div><div class="line">/**</div><div class="line"> * Author : luweicheng on 2017/7/20 0020 15:15</div><div class="line"> * E-mail :1769005961@qq.com</div><div class="line"> * GitHub : https://github.com/luweicheng24</div><div class="line"> * funcation: 具有拉伸效果的ScrollerView</div><div class="line"> */</div><div class="line"></div><div class="line">public class CustomScroller extends ScrollView {</div><div class="line"> private View childView;// 子View(ScrollerView的唯一子类)</div><div class="line"> private int y;// 点击时y坐标</div><div class="line"> private Rect rect = new Rect();// 矩形(用来保存inner的初始状态,判断是够需要动画回弹效果)</div><div class="line"> public CustomScroller(Context context, AttributeSet attrs) {</div><div class="line"> super(context, attrs);</div><div class="line"> }</div><div class="line"> /**</div><div class="line"> * 在xml布局绘制为界面完成时调用,</div><div class="line"> * 获取ScrollerView中唯一的直系子布局(ScrollerView中不许包含一层ViewGroup,有且只有一个)</div><div class="line"> */</div><div class="line"> @Override</div><div class="line"> protected void onFinishInflate() {</div><div class="line"> if (getChildCount() > 0) {</div><div class="line"> childView = getChildAt(0);</div><div class="line"> }</div><div class="line"> super.onFinishInflate();</div><div class="line"> }</div><div class="line"> /**</div><div class="line"> * touch 事件处理</div><div class="line"> **/</div><div class="line"> @Override</div><div class="line"> public boolean onTouchEvent(MotionEvent ev) {</div><div class="line"> if (childView != null) {</div><div class="line"> handleTouchEvent(ev);</div><div class="line"> }</div><div class="line"> return super.onTouchEvent(ev);</div><div class="line"> }</div><div class="line"></div><div class="line"> /***</div><div class="line"> * 触摸事件</div><div class="line"> *</div><div class="line"> * @param ev</div><div class="line"> */</div><div class="line"> public void handleTouchEvent(MotionEvent ev) {</div><div class="line"> int action = ev.getAction();</div><div class="line"> switch (action) {</div><div class="line"> case MotionEvent.ACTION_DOWN:</div><div class="line"> y = (int) ev.getY();//按下的时候获取到y坐标</div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_MOVE:</div><div class="line"> int nowY = (int) ev.getY(); // 移动时的实时y坐标</div><div class="line"> int delayY = y - nowY; // 移动时的间隔</div><div class="line"> y = nowY; // 将本次移动结束时的y坐标赋值给下次移动的起始坐标(也就是nowY)</div><div class="line"> if (isNeedMove()) {</div><div class="line"> if (rect.isEmpty()) {</div><div class="line"> //rect保存childView的初始位置信息</div><div class="line"> rect.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());</div><div class="line"> }</div><div class="line"> //移动布局(屏幕移动的距离等于手指滑动距离的一般)</div><div class="line"> childView.layout(childView.getLeft(), childView.getTop() - delayY / 2, childView.getRight(), childView.getBottom() - delayY / 2);</div><div class="line"> }</div><div class="line"></div><div class="line"> break;</div><div class="line"> case MotionEvent.ACTION_UP:</div><div class="line"> if (isNeedAnimation()) {// 判断rect是否为空,也就是是否被重置了</div><div class="line"> startAnim();//开始回弹动画</div><div class="line"> }</div><div class="line"> break;</div><div class="line"> default:</div><div class="line"> break;</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"> private void startAnim() {</div><div class="line"> TranslateAnimation anim = new TranslateAnimation(0, 0, childView.getTop(), rect.top);</div><div class="line"> anim.setDuration(200);</div><div class="line"> anim.setInterpolator(new OvershootInterpolator());//加速器</div><div class="line"> childView.startAnimation(anim);</div><div class="line"> // 将inner布局重新回到起始位置</div><div class="line"> childView.layout(rect.left, rect.top, rect.right, rect.bottom);</div><div class="line"> rect.setEmpty();</div><div class="line"></div><div class="line"> }</div><div class="line"> /**</div><div class="line"> * 判断布局是否需要移动</div><div class="line"> * @return</div><div class="line"> */</div><div class="line"> private boolean isNeedMove() {</div><div class="line"> int offset = childView.getMeasuredHeight() - getHeight();</div><div class="line"> int scrollY = getScrollY();</div><div class="line"> // 0是顶部,后面那个是底部(需要仔细想一下这个过程)</div><div class="line"> if (scrollY == 0 || scrollY == offset) {</div><div class="line"> return true;</div><div class="line"> }</div><div class="line"> return false;</div><div class="line"> }</div><div class="line"> public boolean isNeedAnimation() {</div><div class="line"> return !rect.isEmpty();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>如果有问题,在下面留言,共同探讨。</p>
]]></content>
<summary type="html">
<blockquote>
<p>引言<br>一切的自定义都是来自于需求,而在项目开发中由于界面条目太多,所以自然而然的使用到了ScrollerView,当把效果给产品经理的时候呢,ios和Android的效果完全不一样,ios自带的上下拉伸回弹的效果,而Android没有,所以自定义一个具有拉伸效果的ScrollerView迫在眉睫啊.</p>
</blockquote>
</summary>
<category term="Android" scheme="https://luweicheng24.github.io/categories/Android/"/>
<category term="自定义View" scheme="https://luweicheng24.github.io/tags/%E8%87%AA%E5%AE%9A%E4%B9%89View/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="https://luweicheng24.github.io/2017/08/12/hello-world/"/>
<id>https://luweicheng24.github.io/2017/08/12/hello-world/</id>
<published>2017-08-12T04:26:39.145Z</published>
<updated>2017-08-12T04:26:39.145Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
]]></content>
<summary type="html">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.
</summary>
</entry>
</feed>