-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgraphics.html
More file actions
697 lines (655 loc) · 72.2 KB
/
graphics.html
File metadata and controls
697 lines (655 loc) · 72.2 KB
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
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Android Development: Lecture Notes</title>
<meta name="description" content="Lecture Notes for INFO 448: Android Development.">
<meta name="generator" content="bookdown 0.5 and GitBook 2.6.7">
<meta property="og:title" content="Android Development: Lecture Notes" />
<meta property="og:type" content="book" />
<meta property="og:url" content="https://info448.github.io/" />
<meta property="og:image" content="https://info448.github.io/img/android_icon_transparent.png" />
<meta property="og:description" content="Lecture Notes for INFO 448: Android Development." />
<meta name="github-repo" content="info448/book" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Android Development: Lecture Notes" />
<meta name="twitter:description" content="Lecture Notes for INFO 448: Android Development." />
<meta name="twitter:image" content="https://info448.github.io/img/android_icon_transparent.png" />
<meta name="author" content="Joel Ross">
<meta name="date" content="2018-11-19">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="shortcut icon" href="img/android_icon_transparent.png" type="image/x-icon">
<link rel="prev" href="sensors.html">
<link rel="next" href="styles-themes.html">
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-bookdown.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-highlight.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-search.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-fontsettings.css" rel="stylesheet" />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-98444716-1', 'auto');
ga('send', 'pageview');
</script>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
<link rel="stylesheet" href="css/style.css" type="text/css" />
</head>
<body>
<div class="book without-animation with-summary font-size-2 font-family-1" data-basepath=".">
<div class="book-summary">
<nav role="navigation">
<ul class="summary">
<li><a href="./" class="title">Android Development</a></li>
<li class="divider"></li>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html"><i class="fa fa-check"></i>About this Book</a></li>
<li class="part"><span><b>I Lectures</b></span></li>
<li class="chapter" data-level="1" data-path="introduction.html"><a href="introduction.html"><i class="fa fa-check"></i><b>1</b> Introduction</a><ul>
<li class="chapter" data-level="1.1" data-path="introduction.html"><a href="introduction.html#android-history"><i class="fa fa-check"></i><b>1.1</b> Android History</a><ul>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#android-versions"><i class="fa fa-check"></i>Android Versions</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#legal-battles"><i class="fa fa-check"></i>Legal Battles</a></li>
</ul></li>
<li class="chapter" data-level="1.2" data-path="introduction.html"><a href="introduction.html#building-apps"><i class="fa fa-check"></i><b>1.2</b> Building Apps</a><ul>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#creating-a-project"><i class="fa fa-check"></i>Creating a Project</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#running-the-app"><i class="fa fa-check"></i>Running the App</a></li>
</ul></li>
<li class="chapter" data-level="1.3" data-path="introduction.html"><a href="introduction.html#app-source-code"><i class="fa fa-check"></i><b>1.3</b> App Source Code</a><ul>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#xml-resources"><i class="fa fa-check"></i>XML Resources</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#the-manifest"><i class="fa fa-check"></i>The Manifest</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#java-activities"><i class="fa fa-check"></i>Java Activities</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#gradle-scripts"><i class="fa fa-check"></i>Gradle Scripts</a></li>
</ul></li>
<li class="chapter" data-level="1.4" data-path="introduction.html"><a href="introduction.html#logging-adb"><i class="fa fa-check"></i><b>1.4</b> Logging & ADB</a><ul>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#log-methods"><i class="fa fa-check"></i>Log Methods</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#logcat"><i class="fa fa-check"></i>Logcat</a></li>
<li class="chapter" data-level="" data-path="introduction.html"><a href="introduction.html#toast"><i class="fa fa-check"></i>Toast</a></li>
</ul></li>
<li class="chapter" data-level="1.5" data-path="introduction.html"><a href="introduction.html#adding-interaction"><i class="fa fa-check"></i><b>1.5</b> Adding Interaction</a></li>
<li class="chapter" data-level="1.6" data-path="introduction.html"><a href="introduction.html#kotlin-setup"><i class="fa fa-check"></i><b>1.6</b> Kotlin</a></li>
</ul></li>
<li class="chapter" data-level="2" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html"><i class="fa fa-check"></i><b>2</b> Resources and Layouts</a><ul>
<li class="chapter" data-level="2.1" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#resources"><i class="fa fa-check"></i><b>2.1</b> Resources</a><ul>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#r"><i class="fa fa-check"></i>R</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#alternative-resources"><i class="fa fa-check"></i>Alternative Resources</a></li>
</ul></li>
<li class="chapter" data-level="2.2" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#views"><i class="fa fa-check"></i><b>2.2</b> Views</a><ul>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#view-properties"><i class="fa fa-check"></i>View Properties</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#views-and-java"><i class="fa fa-check"></i>Views and Java</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#practice"><i class="fa fa-check"></i>Practice</a></li>
</ul></li>
<li class="chapter" data-level="2.3" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#layouts"><i class="fa fa-check"></i><b>2.3</b> Layouts</a><ul>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#linearlayout"><i class="fa fa-check"></i>LinearLayout</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#relativelayout"><i class="fa fa-check"></i>RelativeLayout</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#constraintlayout"><i class="fa fa-check"></i>ConstraintLayout</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#other-layouts"><i class="fa fa-check"></i>Other Layouts</a></li>
<li class="chapter" data-level="" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#combining-and-inflating-layouts"><i class="fa fa-check"></i>Combining and Inflating Layouts</a></li>
</ul></li>
<li class="chapter" data-level="2.4" data-path="resources-and-layouts.html"><a href="resources-and-layouts.html#inputs"><i class="fa fa-check"></i><b>2.4</b> Inputs</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="activities.html"><a href="activities.html"><i class="fa fa-check"></i><b>3</b> Activities</a><ul>
<li class="chapter" data-level="3.1" data-path="activities.html"><a href="activities.html#making-activities"><i class="fa fa-check"></i><b>3.1</b> Making Activities</a></li>
<li class="chapter" data-level="3.2" data-path="activities.html"><a href="activities.html#the-activity-lifecycle"><i class="fa fa-check"></i><b>3.2</b> The Activity Lifecycle</a><ul>
<li class="chapter" data-level="" data-path="activities.html"><a href="activities.html#overriding-the-callback-methods"><i class="fa fa-check"></i>Overriding the Callback Methods</a></li>
<li class="chapter" data-level="" data-path="activities.html"><a href="activities.html#saving-and-restoring-activity-state"><i class="fa fa-check"></i>Saving and Restoring Activity State</a></li>
</ul></li>
<li class="chapter" data-level="3.3" data-path="activities.html"><a href="activities.html#context"><i class="fa fa-check"></i><b>3.3</b> Context</a></li>
<li class="chapter" data-level="3.4" data-path="activities.html"><a href="activities.html#multiple-activities"><i class="fa fa-check"></i><b>3.4</b> Multiple Activities</a><ul>
<li class="chapter" data-level="" data-path="activities.html"><a href="activities.html#activity-intents"><i class="fa fa-check"></i>Intents</a></li>
<li class="chapter" data-level="" data-path="activities.html"><a href="activities.html#back-tasks"><i class="fa fa-check"></i>Back & Tasks</a></li>
<li class="chapter" data-level="" data-path="activities.html"><a href="activities.html#up-navigation"><i class="fa fa-check"></i>Up Navigation</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="4" data-path="data-views.html"><a href="data-views.html"><i class="fa fa-check"></i><b>4</b> Data-Driven Views</a><ul>
<li class="chapter" data-level="4.1" data-path="data-views.html"><a href="data-views.html#listviews-and-adapters"><i class="fa fa-check"></i><b>4.1</b> ListViews and Adapters</a></li>
<li class="chapter" data-level="4.2" data-path="data-views.html"><a href="data-views.html#networking-with-volley"><i class="fa fa-check"></i><b>4.2</b> Networking with Volley</a><ul>
<li class="chapter" data-level="" data-path="data-views.html"><a href="data-views.html#using-volley"><i class="fa fa-check"></i>Using Volley</a></li>
<li class="chapter" data-level="" data-path="data-views.html"><a href="data-views.html#requestqueue-singletons"><i class="fa fa-check"></i>RequestQueue Singletons</a></li>
<li class="chapter" data-level="" data-path="data-views.html"><a href="data-views.html#downloading-images"><i class="fa fa-check"></i>Downloading Images</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="5" data-path="material-design.html"><a href="material-design.html"><i class="fa fa-check"></i><b>5</b> Material Design</a><ul>
<li class="chapter" data-level="5.1" data-path="material-design.html"><a href="material-design.html#the-material-design-language"><i class="fa fa-check"></i><b>5.1</b> The Material Design Language</a></li>
<li class="chapter" data-level="5.2" data-path="material-design.html"><a href="material-design.html#material-styles-icons"><i class="fa fa-check"></i><b>5.2</b> Material Styles & Icons</a></li>
<li class="chapter" data-level="5.3" data-path="material-design.html"><a href="material-design.html#design-support-libraries"><i class="fa fa-check"></i><b>5.3</b> Design Support Libraries</a><ul>
<li class="chapter" data-level="" data-path="material-design.html"><a href="material-design.html#widgets"><i class="fa fa-check"></i>Widgets</a></li>
<li class="chapter" data-level="" data-path="material-design.html"><a href="material-design.html#coordinator-layout"><i class="fa fa-check"></i>Coordinator Layout</a></li>
</ul></li>
<li class="chapter" data-level="5.4" data-path="material-design.html"><a href="material-design.html#animations"><i class="fa fa-check"></i><b>5.4</b> Animations</a></li>
<li class="chapter" data-level="" data-path="material-design.html"><a href="material-design.html#resources-1"><i class="fa fa-check"></i>Resources</a></li>
</ul></li>
<li class="chapter" data-level="6" data-path="fragments.html"><a href="fragments.html"><i class="fa fa-check"></i><b>6</b> Fragments</a><ul>
<li class="chapter" data-level="6.1" data-path="fragments.html"><a href="fragments.html#creating-a-fragment"><i class="fa fa-check"></i><b>6.1</b> Creating a Fragment</a><ul>
<li class="chapter" data-level="" data-path="fragments.html"><a href="fragments.html#activity-to-fragment-communication"><i class="fa fa-check"></i>Activity-to-Fragment Communication</a></li>
</ul></li>
<li class="chapter" data-level="6.2" data-path="fragments.html"><a href="fragments.html#dynamic-fragments"><i class="fa fa-check"></i><b>6.2</b> Dynamic Fragments</a><ul>
<li class="chapter" data-level="" data-path="fragments.html"><a href="fragments.html#instantiating-fragments"><i class="fa fa-check"></i>Instantiating Fragments</a></li>
<li class="chapter" data-level="" data-path="fragments.html"><a href="fragments.html#transactions"><i class="fa fa-check"></i>Transactions</a></li>
<li class="chapter" data-level="" data-path="fragments.html"><a href="fragments.html#inter-fragment-communication"><i class="fa fa-check"></i>Inter-Fragment Communication</a></li>
<li class="chapter" data-level="" data-path="fragments.html"><a href="fragments.html#the-back-stack"><i class="fa fa-check"></i>The Back Stack</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="7" data-path="intents.html"><a href="intents.html"><i class="fa fa-check"></i><b>7</b> Intents</a><ul>
<li class="chapter" data-level="7.1" data-path="intents.html"><a href="intents.html#intents-for-another-activity-explicit"><i class="fa fa-check"></i><b>7.1</b> Intents for Another Activity (Explicit)</a><ul>
<li class="chapter" data-level="" data-path="intents.html"><a href="intents.html#extras"><i class="fa fa-check"></i>Extras</a></li>
</ul></li>
<li class="chapter" data-level="7.2" data-path="intents.html"><a href="intents.html#intents-for-another-app-implicit"><i class="fa fa-check"></i><b>7.2</b> Intents for Another App (Implicit)</a></li>
<li class="chapter" data-level="7.3" data-path="intents.html"><a href="intents.html#intents-for-a-response"><i class="fa fa-check"></i><b>7.3</b> Intents for a Response</a></li>
<li class="chapter" data-level="7.4" data-path="intents.html"><a href="intents.html#listening-for-intents"><i class="fa fa-check"></i><b>7.4</b> Listening for Intents</a></li>
<li class="chapter" data-level="7.5" data-path="intents.html"><a href="intents.html#broadcasts-and-receivers"><i class="fa fa-check"></i><b>7.5</b> Broadcasts and Receivers</a></li>
<li class="chapter" data-level="7.6" data-path="intents.html"><a href="intents.html#menus"><i class="fa fa-check"></i><b>7.6</b> Menus</a><ul>
<li class="chapter" data-level="" data-path="intents.html"><a href="intents.html#action-views"><i class="fa fa-check"></i>Action Views</a></li>
<li class="chapter" data-level="" data-path="intents.html"><a href="intents.html#context-menus"><i class="fa fa-check"></i>Context Menus</a></li>
</ul></li>
<li class="chapter" data-level="7.7" data-path="intents.html"><a href="intents.html#an-intent-example-sms"><i class="fa fa-check"></i><b>7.7</b> An Intent Example: SMS</a></li>
</ul></li>
<li class="chapter" data-level="8" data-path="notifications-settings.html"><a href="notifications-settings.html"><i class="fa fa-check"></i><b>8</b> Notifications & Settings</a><ul>
<li class="chapter" data-level="8.1" data-path="notifications-settings.html"><a href="notifications-settings.html#dialogs"><i class="fa fa-check"></i><b>8.1</b> Dialogs</a><ul>
<li class="chapter" data-level="" data-path="notifications-settings.html"><a href="notifications-settings.html#dialogfragments"><i class="fa fa-check"></i>DialogFragments</a></li>
</ul></li>
<li class="chapter" data-level="8.2" data-path="notifications-settings.html"><a href="notifications-settings.html#notifications"><i class="fa fa-check"></i><b>8.2</b> Notifications</a><ul>
<li class="chapter" data-level="8.2.1" data-path="notifications-settings.html"><a href="notifications-settings.html#tap-actions"><i class="fa fa-check"></i><b>8.2.1</b> Tap Actions</a></li>
</ul></li>
<li class="chapter" data-level="8.3" data-path="notifications-settings.html"><a href="notifications-settings.html#settings"><i class="fa fa-check"></i><b>8.3</b> Settings</a><ul>
<li class="chapter" data-level="" data-path="notifications-settings.html"><a href="notifications-settings.html#sharedpreferences"><i class="fa fa-check"></i>SharedPreferences</a></li>
<li class="chapter" data-level="" data-path="notifications-settings.html"><a href="notifications-settings.html#preference-settings"><i class="fa fa-check"></i>Preference Settings</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="9" data-path="loaders.html"><a href="loaders.html"><i class="fa fa-check"></i><b>9</b> Providers and Loaders</a><ul>
<li class="chapter" data-level="9.1" data-path="loaders.html"><a href="loaders.html#content-providers-intro"><i class="fa fa-check"></i><b>9.1</b> Content Providers</a></li>
<li class="chapter" data-level="9.2" data-path="loaders.html"><a href="loaders.html#cursors"><i class="fa fa-check"></i><b>9.2</b> Cursors</a></li>
<li class="chapter" data-level="9.3" data-path="loaders.html"><a href="loaders.html#loaders"><i class="fa fa-check"></i><b>9.3</b> Loaders</a></li>
<li class="chapter" data-level="9.4" data-path="loaders.html"><a href="loaders.html#other-provider-actions"><i class="fa fa-check"></i><b>9.4</b> Other Provider Actions</a></li>
</ul></li>
<li class="chapter" data-level="10" data-path="files-and-permissions.html"><a href="files-and-permissions.html"><i class="fa fa-check"></i><b>10</b> Files and Permissions</a><ul>
<li class="chapter" data-level="10.1" data-path="files-and-permissions.html"><a href="files-and-permissions.html#file-storage-locations"><i class="fa fa-check"></i><b>10.1</b> File Storage Locations</a></li>
<li class="chapter" data-level="10.2" data-path="files-and-permissions.html"><a href="files-and-permissions.html#permissions"><i class="fa fa-check"></i><b>10.2</b> Permissions</a></li>
<li class="chapter" data-level="10.3" data-path="files-and-permissions.html"><a href="files-and-permissions.html#external-storage"><i class="fa fa-check"></i><b>10.3</b> External Storage</a></li>
<li class="chapter" data-level="10.4" data-path="files-and-permissions.html"><a href="files-and-permissions.html#internal-storage-cache"><i class="fa fa-check"></i><b>10.4</b> Internal Storage & Cache</a></li>
<li class="chapter" data-level="10.5" data-path="files-and-permissions.html"><a href="files-and-permissions.html#example-saving-pictures"><i class="fa fa-check"></i><b>10.5</b> Example: Saving Pictures</a><ul>
<li class="chapter" data-level="10.5.1" data-path="files-and-permissions.html"><a href="files-and-permissions.html#fileproviders"><i class="fa fa-check"></i><b>10.5.1</b> FileProviders</a></li>
</ul></li>
<li class="chapter" data-level="10.6" data-path="files-and-permissions.html"><a href="files-and-permissions.html#sharing-files"><i class="fa fa-check"></i><b>10.6</b> Sharing Files</a></li>
</ul></li>
<li class="chapter" data-level="11" data-path="databases.html"><a href="databases.html"><i class="fa fa-check"></i><b>11</b> Providers and Databases</a><ul>
<li class="chapter" data-level="11.1" data-path="databases.html"><a href="databases.html#review-providers-and-loaders"><i class="fa fa-check"></i><b>11.1</b> Review: Providers and Loaders</a></li>
<li class="chapter" data-level="11.2" data-path="databases.html"><a href="databases.html#sqlite-databases"><i class="fa fa-check"></i><b>11.2</b> SQLite Databases</a></li>
<li class="chapter" data-level="11.3" data-path="databases.html"><a href="databases.html#implementing-a-contentprovider"><i class="fa fa-check"></i><b>11.3</b> Implementing a ContentProvider</a><ul>
<li class="chapter" data-level="" data-path="databases.html"><a href="databases.html#uris-and-types"><i class="fa fa-check"></i>URIs and Types</a></li>
<li class="chapter" data-level="" data-path="databases.html"><a href="databases.html#query-methods"><i class="fa fa-check"></i>Query Methods</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="12" data-path="location.html"><a href="location.html"><i class="fa fa-check"></i><b>12</b> Location</a><ul>
<li class="chapter" data-level="12.1" data-path="location.html"><a href="location.html#localization-techniques"><i class="fa fa-check"></i><b>12.1</b> Localization Techniques</a><ul>
<li class="chapter" data-level="" data-path="location.html"><a href="location.html#gps"><i class="fa fa-check"></i>GPS</a></li>
<li class="chapter" data-level="" data-path="location.html"><a href="location.html#cell-tower-localization"><i class="fa fa-check"></i>Cell Tower Localization</a></li>
<li class="chapter" data-level="" data-path="location.html"><a href="location.html#wifi-localization"><i class="fa fa-check"></i>WiFi Localization</a></li>
<li class="chapter" data-level="" data-path="location.html"><a href="location.html#representing-location"><i class="fa fa-check"></i>Representing Location</a></li>
</ul></li>
<li class="chapter" data-level="12.2" data-path="location.html"><a href="location.html#android-location"><i class="fa fa-check"></i><b>12.2</b> Android Location</a><ul>
<li class="chapter" data-level="" data-path="location.html"><a href="location.html#google-play-services"><i class="fa fa-check"></i>Google Play Services</a></li>
<li class="chapter" data-level="" data-path="location.html"><a href="location.html#accessing-location"><i class="fa fa-check"></i>Accessing Location</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="13" data-path="services.html"><a href="services.html"><i class="fa fa-check"></i><b>13</b> Threads and Services</a><ul>
<li class="chapter" data-level="13.1" data-path="services.html"><a href="services.html#threads-and-processes"><i class="fa fa-check"></i><b>13.1</b> Threads and Processes</a><ul>
<li class="chapter" data-level="" data-path="services.html"><a href="services.html#java-threads"><i class="fa fa-check"></i>Java Threads</a></li>
<li class="chapter" data-level="" data-path="services.html"><a href="services.html#android-threads"><i class="fa fa-check"></i>Android Threads</a></li>
</ul></li>
<li class="chapter" data-level="13.2" data-path="services.html"><a href="services.html#intentservices"><i class="fa fa-check"></i><b>13.2</b> IntentServices</a><ul>
<li class="chapter" data-level="" data-path="services.html"><a href="services.html#the-service-lifecycle"><i class="fa fa-check"></i>The Service Lifecycle</a></li>
</ul></li>
<li class="chapter" data-level="13.3" data-path="services.html"><a href="services.html#example-a-music-service"><i class="fa fa-check"></i><b>13.3</b> Example: A Music Service</a><ul>
<li class="chapter" data-level="" data-path="services.html"><a href="services.html#mediaplayer"><i class="fa fa-check"></i>MediaPlayer</a></li>
<li class="chapter" data-level="" data-path="services.html"><a href="services.html#creating-a-service"><i class="fa fa-check"></i>Creating a Service</a></li>
</ul></li>
<li class="chapter" data-level="13.4" data-path="services.html"><a href="services.html#foreground-services"><i class="fa fa-check"></i><b>13.4</b> Foreground Services</a></li>
<li class="chapter" data-level="13.5" data-path="services.html"><a href="services.html#bound-services"><i class="fa fa-check"></i><b>13.5</b> Bound Services</a></li>
</ul></li>
<li class="chapter" data-level="14" data-path="sensors.html"><a href="sensors.html"><i class="fa fa-check"></i><b>14</b> Sensors</a><ul>
<li class="chapter" data-level="14.1" data-path="sensors.html"><a href="sensors.html#motion-sensors"><i class="fa fa-check"></i><b>14.1</b> Motion Sensors</a><ul>
<li class="chapter" data-level="" data-path="sensors.html"><a href="sensors.html#accessing-sensors"><i class="fa fa-check"></i>Accessing Sensors</a></li>
<li class="chapter" data-level="" data-path="sensors.html"><a href="sensors.html#composite-sensors"><i class="fa fa-check"></i>Composite Sensors</a></li>
</ul></li>
<li class="chapter" data-level="14.2" data-path="sensors.html"><a href="sensors.html#rotation"><i class="fa fa-check"></i><b>14.2</b> Rotation</a><ul>
<li class="chapter" data-level="" data-path="sensors.html"><a href="sensors.html#coordinates"><i class="fa fa-check"></i>Coordinates</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="15" data-path="graphics.html"><a href="graphics.html"><i class="fa fa-check"></i><b>15</b> Graphics and Touch</a><ul>
<li class="chapter" data-level="15.1" data-path="graphics.html"><a href="graphics.html#drawing-graphics"><i class="fa fa-check"></i><b>15.1</b> Drawing Graphics</a><ul>
<li class="chapter" data-level="" data-path="graphics.html"><a href="graphics.html#custom-views"><i class="fa fa-check"></i>Custom Views</a></li>
<li class="chapter" data-level="" data-path="graphics.html"><a href="graphics.html#surfaceviews"><i class="fa fa-check"></i>SurfaceViews</a></li>
</ul></li>
<li class="chapter" data-level="15.2" data-path="graphics.html"><a href="graphics.html#touch-and-gestures"><i class="fa fa-check"></i><b>15.2</b> Touch and Gestures</a><ul>
<li class="chapter" data-level="" data-path="graphics.html"><a href="graphics.html#advanced-gestures"><i class="fa fa-check"></i>Advanced Gestures</a></li>
</ul></li>
<li class="chapter" data-level="15.3" data-path="graphics.html"><a href="graphics.html#property-animation"><i class="fa fa-check"></i><b>15.3</b> Property Animation</a></li>
</ul></li>
<li class="part"><span><b>II Additional Topics (Labs)</b></span></li>
<li class="chapter" data-level="16" data-path="styles-themes.html"><a href="styles-themes.html"><i class="fa fa-check"></i><b>16</b> Styles & Themes</a><ul>
<li class="chapter" data-level="16.1" data-path="styles-themes.html"><a href="styles-themes.html#defining-styles"><i class="fa fa-check"></i><b>16.1</b> Defining Styles</a><ul>
<li class="chapter" data-level="" data-path="styles-themes.html"><a href="styles-themes.html#style-inheritance"><i class="fa fa-check"></i>Style Inheritance</a></li>
<li class="chapter" data-level="" data-path="styles-themes.html"><a href="styles-themes.html#built-in-styles"><i class="fa fa-check"></i>Built-in Styles</a></li>
<li class="chapter" data-level="" data-path="styles-themes.html"><a href="styles-themes.html#styles-for-text-views"><i class="fa fa-check"></i>Styles for Text Views</a></li>
</ul></li>
<li class="chapter" data-level="16.2" data-path="styles-themes.html"><a href="styles-themes.html#themes"><i class="fa fa-check"></i><b>16.2</b> Themes</a><ul>
<li class="chapter" data-level="" data-path="styles-themes.html"><a href="styles-themes.html#material-themes"><i class="fa fa-check"></i>Material Themes</a></li>
<li class="chapter" data-level="" data-path="styles-themes.html"><a href="styles-themes.html#theme-attributes"><i class="fa fa-check"></i>Theme Attributes</a></li>
</ul></li>
<li class="chapter" data-level="" data-path="styles-themes.html"><a href="styles-themes.html#resources-2"><i class="fa fa-check"></i>Resources</a></li>
</ul></li>
<li class="chapter" data-level="17" data-path="fragment-viewpager.html"><a href="fragment-viewpager.html"><i class="fa fa-check"></i><b>17</b> Fragments: ViewPager</a><ul>
<li class="chapter" data-level="17.1" data-path="fragment-viewpager.html"><a href="fragment-viewpager.html#define-a-searchfragment"><i class="fa fa-check"></i><b>17.1</b> Define a SearchFragment</a></li>
<li class="chapter" data-level="17.2" data-path="fragment-viewpager.html"><a href="fragment-viewpager.html#add-the-viewpager-and-adapter"><i class="fa fa-check"></i><b>17.2</b> Add the ViewPager and Adapter</a></li>
<li class="chapter" data-level="17.3" data-path="fragment-viewpager.html"><a href="fragment-viewpager.html#add-user-interaction"><i class="fa fa-check"></i><b>17.3</b> Add User Interaction</a></li>
</ul></li>
<li class="chapter" data-level="18" data-path="bluetooth.html"><a href="bluetooth.html"><i class="fa fa-check"></i><b>18</b> Bluetooth</a></li>
<li class="chapter" data-level="19" data-path="maps.html"><a href="maps.html"><i class="fa fa-check"></i><b>19</b> Maps</a><ul>
<li class="chapter" data-level="19.1" data-path="maps.html"><a href="maps.html#create-a-map-activity"><i class="fa fa-check"></i><b>19.1</b> Create a Map Activity</a><ul>
<li class="chapter" data-level="" data-path="maps.html"><a href="maps.html#getting-an-api-key"><i class="fa fa-check"></i>Getting an API Key</a></li>
<li><a href="maps.html#the-supportmapfragment">The <code>SupportMapFragment</code></a></li>
</ul></li>
<li class="chapter" data-level="19.2" data-path="maps.html"><a href="maps.html#specifying-the-user-interface"><i class="fa fa-check"></i><b>19.2</b> Specifying the User Interface</a></li>
<li class="chapter" data-level="19.3" data-path="maps.html"><a href="maps.html#markers-and-drawings"><i class="fa fa-check"></i><b>19.3</b> Markers and Drawings</a><ul>
<li class="chapter" data-level="" data-path="maps.html"><a href="maps.html#drawing-shapes"><i class="fa fa-check"></i>Drawing Shapes</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="20" data-path="memory.html"><a href="memory.html"><i class="fa fa-check"></i><b>20</b> Memory Management</a><ul>
<li class="chapter" data-level="20.1" data-path="memory.html"><a href="memory.html#memory-allocation"><i class="fa fa-check"></i><b>20.1</b> Memory Allocation</a></li>
<li class="chapter" data-level="20.2" data-path="memory.html"><a href="memory.html#the-memory-monitor"><i class="fa fa-check"></i><b>20.2</b> The Memory Monitor</a><ul>
<li class="chapter" data-level="" data-path="memory.html"><a href="memory.html#garbage-collection"><i class="fa fa-check"></i>Garbage Collection</a></li>
</ul></li>
<li class="chapter" data-level="20.3" data-path="memory.html"><a href="memory.html#memory-leaks"><i class="fa fa-check"></i><b>20.3</b> Memory Leaks</a></li>
</ul></li>
<li class="chapter" data-level="21" data-path="multi-touch.html"><a href="multi-touch.html"><i class="fa fa-check"></i><b>21</b> Multi-Touch</a><ul>
<li class="chapter" data-level="21.1" data-path="multi-touch.html"><a href="multi-touch.html#identifying-fingers"><i class="fa fa-check"></i><b>21.1</b> Identifying Fingers</a></li>
<li class="chapter" data-level="21.2" data-path="multi-touch.html"><a href="multi-touch.html#drawing-touches"><i class="fa fa-check"></i><b>21.2</b> Drawing Touches</a></li>
<li class="chapter" data-level="21.3" data-path="multi-touch.html"><a href="multi-touch.html#moving-fingers"><i class="fa fa-check"></i><b>21.3</b> Moving Fingers</a></li>
<li class="chapter" data-level="21.4" data-path="multi-touch.html"><a href="multi-touch.html#other-multi-touch-gestures"><i class="fa fa-check"></i><b>21.4</b> Other Multi-Touch Gestures</a></li>
</ul></li>
<li class="appendix"><span><b>Appendix</b></span></li>
<li class="chapter" data-level="A" data-path="java-review.html"><a href="java-review.html"><i class="fa fa-check"></i><b>A</b> Java Review</a><ul>
<li class="chapter" data-level="A.1" data-path="java-review.html"><a href="java-review.html#building-apps-with-gradle"><i class="fa fa-check"></i><b>A.1</b> Building Apps with Gradle</a></li>
<li class="chapter" data-level="A.2" data-path="java-review.html"><a href="java-review.html#class-basics"><i class="fa fa-check"></i><b>A.2</b> Class Basics</a></li>
<li class="chapter" data-level="A.3" data-path="java-review.html"><a href="java-review.html#inheritance"><i class="fa fa-check"></i><b>A.3</b> Inheritance</a></li>
<li class="chapter" data-level="A.4" data-path="java-review.html"><a href="java-review.html#interfaces"><i class="fa fa-check"></i><b>A.4</b> Interfaces</a></li>
<li class="chapter" data-level="A.5" data-path="java-review.html"><a href="java-review.html#polymorphism"><i class="fa fa-check"></i><b>A.5</b> Polymorphism</a></li>
<li class="chapter" data-level="A.6" data-path="java-review.html"><a href="java-review.html#abstract-methods-and-classes"><i class="fa fa-check"></i><b>A.6</b> Abstract Methods and Classes</a></li>
<li class="chapter" data-level="A.7" data-path="java-review.html"><a href="java-review.html#generics"><i class="fa fa-check"></i><b>A.7</b> Generics</a></li>
<li class="chapter" data-level="A.8" data-path="java-review.html"><a href="java-review.html#nested-classes"><i class="fa fa-check"></i><b>A.8</b> Nested Classes</a></li>
</ul></li>
<li class="chapter" data-level="B" data-path="java-swing.html"><a href="java-swing.html"><i class="fa fa-check"></i><b>B</b> Java Swing Framework</a><ul>
<li class="chapter" data-level="B.1" data-path="java-swing.html"><a href="java-swing.html#events"><i class="fa fa-check"></i><b>B.1</b> Events</a></li>
<li class="chapter" data-level="B.2" data-path="java-swing.html"><a href="java-swing.html#layouts-and-composites"><i class="fa fa-check"></i><b>B.2</b> Layouts and Composites</a></li>
</ul></li>
<li class="chapter" data-level="C" data-path="publishing.html"><a href="publishing.html"><i class="fa fa-check"></i><b>C</b> Publishing</a><ul>
<li class="chapter" data-level="C.1" data-path="publishing.html"><a href="publishing.html#signing-an-app"><i class="fa fa-check"></i><b>C.1</b> Signing an App</a><ul>
<li><a href="publishing.html#release-.apk">Release <code>.apk</code></a></li>
</ul></li>
</ul></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i><a href="./">Android Development: Lecture Notes</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<section class="normal" id="section-">
<div id="graphics" class="section level1">
<h1><span class="header-section-number">Lecture 15</span> Graphics and Touch</h1>
<p>This lecture discusses some different ways to add “visual motion” (graphical animation) to Android applications. It covers <a href="https://developer.android.com/guide/topics/graphics/2d-graphics.html">2D drawing</a> with custom Views, <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html">Property Animations</a> (also used in Material effects), and how to handle <a href="https://developer.android.com/training/gestures/index.html">touch-based gestures</a>.</p>
<p class="alert alert-info">
This lecture references code found at <a href="https://github.com/info448/lecture15-graphics" class="uri">https://github.com/info448/lecture15-graphics</a>.
</p>
<div id="drawing-graphics" class="section level2">
<h2><span class="header-section-number">15.1</span> Drawing Graphics</h2>
<!-- //graphics, mostly looking at what is provided, maybe a _minor_ demo -->
<p>Android provides a <a href="https://developer.android.com/guide/topics/graphics/2d-graphics.html">2D Graphics API</a> similar in both spirit and usage to the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">HTML5 Canvas API</a>: it provides an <em>interface</em> by which the developer can <em>programmatically</em> generate 2D, raster-based images. This API can be used for drawing graphs, showing manipulated images, and even performing animations!</p>
<p>As in HTML5, in Android this API is available via the <a href="https://developer.android.com/reference/android/graphics/Canvas.html"><code>Canvas</code></a><a href="#fn50" class="footnoteRef" id="fnref50"><sup>50</sup></a> class. Similar to the HTML5 <code><canvas></code> element or the Java SE <a href="https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics2D.html"><code>Graphics2D</code></a> class, the Android <code>Canvas</code> provides a graphical “context” upon which the developer can “draw” rectangles, circles, and even images (<code>Bitmaps</code>) to be shown on the screen.</p>
<div id="custom-views" class="section level3 unnumbered">
<h3>Custom Views</h3>
<p>In order to draw pictures, we need to have a View to draw on (which will provide the <code>Canvas</code> context). The easiest way to get this View is to create it ourselves: define a <strong>custom View</strong> which we can specify as having a “drawn” appearance. We can make our own special <code>View</code> by subclassing it (remember: <code>Buttons</code> and <code>EditTexts</code> are just subclasses of <code>View</code>!), and then filling in a callback function (<code>onDraw()</code>) that specifies how that <code>View</code> is rendered on the screen.</p>
<p class="alert alert-info">
The word <em>render</em> in this case means to “bring into being”, meaning to generate a graphical image and putting it on the screen.
</p>
<p>Customizing a <code>View</code> isn’t too hard, but to save time a complete example is provided in the lecture code in the form of the <code>DrawingView</code> class. Notes about this classes implementation are below:</p>
<ul>
<li><p>The class <code>extends View</code> to subclass the base <code>View</code> class.</p>
<ul>
<li>Also notice how we specify a custom view as a <code><view></code> element in the Layout XML, indicating the <code>class</code> attribute.</li>
</ul></li>
<li><p><code>View</code> has a number of different of constructors. We override them all, since each one is used by a different piece of the Android system (and thus we need to provide custom implementations for each). However, we’ll have each call the “last” one in order to actually do any setup.</p>
<ul>
<li>In the constructor we set up a <a href="http://developer.android.com/reference/android/graphics/Paint.html"><code>Paint</code></a>, which represents <em>how</em> we want to draw: color, stroke width, font-size, anti-aliasing options, etc. We’ll mostly use <code>Paint</code> objects for color.</li>
</ul></li>
<li><p>We override the <strong><code>onSizeChanged()</code></strong> callback, which will get executed when the <code>View</code> changes size. This occurs on inflation (which happens as part of an Activity’s <code>onCreate</code>, meaning the callback will be called on rotation). This callback can act a little bit like a Fragment’s <code>onCreateView()</code>, in that we can do work that is based on the created View at this point.</p></li>
<li><p>We should also override the <strong><code>onMeasure()</code></strong> callback, as <a href="https://developer.android.com/guide/topics/ui/custom-components.html#custom">recommend</a> by the Android guides. This callback is used to specify how the View should be sized in response to its width or height being set as <code>wrap_content</code>. This is particularly important for making things like custom Buttons. However, our example will skip this for time and space, since the <code>DrawingView</code> is intended to always take up the entire screen.</p></li>
<li><p>Finally, we override <strong><code>onDraw()</code></strong>, which is where the magic happens. This method gets called whenever the <code>View</code> needs to be displayed (like <code>paintComponent()</code> in the Swing framework). This callback is passed a <code>Canvas</code> object as a parameter, providing the context we can draw on!</p>
<ul>
<li>Like all other lifecycle callbacks: <strong>we never call <code>onDraw()</code>!!</strong> The Android UI system calls it for us!</li>
</ul></li>
</ul>
<p>The provided <code>Canvas</code> can be drawn on in a couple of ways:</p>
<ul>
<li><p>We can call methods like <code>drawColor()</code> (to fill the background), <code>drawCircle()</code>, or <code>drawText()</code> to draw specific shapes or entities on it. These methods are similar in usage to the HTML5 Canvas.</p></li>
<li><p>We can also draw a <a href="https://developer.android.com/reference/android/graphics/Bitmap.html"><code>Bitmap</code></a>, which represents a graphics raster (e.g., a 2D array of pixels). If we have a <code>Bitmap</code>, we can set the colors of individual pixels (using <code>setPixel(x,y,color)</code>), and then draw the <code>Bitmap</code> onto the Canvas (thereby double-buffering!). This is useful for pixel-level drawing, or when you want to make more complex graphics or artwork.</p>
<ul>
<li>If you’ve used MS Paint, it’s the difference between the shape drawing options and the “zoomed in” pixel coloring.</li>
</ul></li>
</ul>
<p>Note that we cause the <code>Canvas</code> to be “redrawn” (so our <code>onDraw()</code> method to be called) by calling <code>invalidate()</code> on the <code>View</code>: this causes Android to need to recreate it, thereby redrawing it. By repeatedly calling <code>invalidate()</code> we can do something approximating animation!</p>
<ul>
<li><p>We can do this via a recursive loop by calling <code>invalidate()</code> at the end of <code>onDraw()</code>. This lets us “request” that Android cause <code>onDraw()</code> to be called again once it is finished, but <strong>we don’t call it</strong>.</p></li>
<li><p>As a demo, we can make the <code>Ball</code> slide off the screen by changing it’s position slightly:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java">ball.<span class="fu">cx</span> += ball.<span class="fu">dx</span>;
ball.<span class="fu">cy</span> += ball.<span class="fu">dy</span>;</code></pre></div>
<p>We can also add in wall collisions:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="kw">if</span>(ball.<span class="fu">cx</span> + ball.<span class="fu">radius</span> > viewWidth) { <span class="co">//left bound</span>
ball.<span class="fu">cx</span> = viewWidth - ball.<span class="fu">radius</span>;
ball.<span class="fu">dx</span> *= -<span class="dv">1</span>;
}
<span class="kw">else</span> <span class="kw">if</span>(ball.<span class="fu">cx</span> - ball.<span class="fu">radius</span> < <span class="dv">0</span>) { <span class="co">//right bound</span>
ball.<span class="fu">cx</span> = ball.<span class="fu">radius</span>;
ball.<span class="fu">dx</span> *= -<span class="dv">1</span>;
}
<span class="kw">else</span> <span class="kw">if</span>(ball.<span class="fu">cy</span> + ball.<span class="fu">radius</span> > viewHeight) { <span class="co">//bottom bound</span>
ball.<span class="fu">cy</span> = viewHeight - ball.<span class="fu">radius</span>;
ball.<span class="fu">dy</span> *= -<span class="dv">1</span>;
}
<span class="kw">else</span> <span class="kw">if</span>(ball.<span class="fu">cy</span> - ball.<span class="fu">radius</span> < <span class="dv">0</span>) { <span class="co">//top bound</span>
ball.<span class="fu">cy</span> = ball.<span class="fu">radius</span>;
ball.<span class="fu">dy</span> *= -<span class="dv">1</span>;
}</code></pre></div></li>
</ul>
<div class="alert alert-info">
<p>
<em>Animation</em> is the process of “imparting life” (from the Latin <strong><em>“anima”</em></strong>). We tend to mean giving something <strong>motion</strong>—making an object appear to move over time. Consider what that means for how people understand “life”.
</p>
<p>
Video animation involves showing a sequences of images over time. If the images go fast enough, then the human brain interprets them as being part of the same successive motion, and any objects in those images will be considered to be “moving”. Each image in this sequence is called a “frame”. Film tends to be 24 frames per second (<strong>fps</strong>), video is 29.97fps, and video games aim at 60fps. Any video running at at least 16fps will be perceived as mostly smooth motion.
</p>
<p>
Hitting that 16fps can actually be pretty difficult, since determining <em>what</em> to draw is computationally expensive! If we’re calculating every pixel on a 600x800 display, that’s half a million pixels we have to calculate! At 60fps, that’s 28 million pixels per second. For scale, a 1Ghz processor can do 1 billion operations per second—so if each pixel requires 5 operations, we’re at 15% of our processor. This is part of why most graphical systems utilize a dedicated GPU (graphical processing unit)—it provides massive parallelization to speed up this process.
</p>
</div>
</div>
<div id="surfaceviews" class="section level3 unnumbered">
<h3>SurfaceViews</h3>
<p>Since all this calculation (at pixel-level detail) can take some time, we want to be careful it doesn’t block the UI thread! We’d like to instead do the drawing in the background. The rendering itself needs to occur on the UI Thread, but we want all of the <em>drawing logic</em> to occur on the background thread, so that the UI work is as fast as possible (think: hanging up a pre-printed poster rather than needing to print it entirely).</p>
<ul>
<li>However, an <code>AsyncTask</code> isn’t appropriate, because we want to do this repeatedly. Similarly, an <code>IntentService</code> may not be able to respond fast enough if we need to wait for the system to deliver Intents.</li>
</ul>
<p>Android provides a class that is specially designed for being “drawn” on a background thread: the <a href="https://developer.android.com/reference/android/view/SurfaceView.html"><strong><code>SurfaceView</code></strong></a>. Unlike basic <code>Views</code> that are somewhat ephemeral, a <code>SurfaceView</code> includes a dedicated drawing surface that we can interact with in a separate thread. It is designed to support this threading work without requiring <em>too</em> much synchronization code.</p>
<p>These take even more work to setup, so a complete example (<code>DrawingSurfaceView</code>) is again provided in the lecture code:</p>
<ul>
<li><p>This class <code>extends SurfaceView</code> and <em>implements</em> <code>SurfaceHolder.Callback</code>. A <code>SurfaceHolder</code> is an object that “holds” (contains) the underlying drawable surface; somewhat similar to the <code>ViewHolder</code> pattern utilized with an Adapter. We interact with the <code>SurfaceView</code> through the holder to make sure that we’re <em>thread-safe</em>: that only one thread is interacting with the surface at a time.</p>
<ul>
<li>In general there will be two threads trading off use of the holder: our background thread that is drawing on the surface (“printing the poster”), and then UI thread that is showing the surface to the user (“hanging the printed poster”). You can think of the holder <em>as</em> the poster in this metaphor!</li>
</ul></li>
<li><p>We register the holder in the constructor with the provided <code>getHolder()</code> method, and register ourselves for callbacks when the holder changes. We also instantiate a new <code>Runnable</code>, which will represent the callback executed in a separate (background) thread to do the drawing.</p></li>
<li><p>The <code>SurfaceHolder.Callback</code> interface requires methods about when the surface changes, and so we fill those in:</p>
<ul>
<li><code>onSurfaceCreated()</code> starts our background thread (because the surface has now been created)</li>
<li><code>onSurfaceChanged()</code> ends up acting a lot like <code>onSizeChanged()</code> from the basic <code>DrawingView</code></li>
<li><code>onSurfaceDestroyed()</code> stops the background thread in a “safe” way (code adapted from Google)</li>
</ul></li>
<li><p>If we look at the <code>Runnable</code>, it’s basically an infinite loop:</p>
<ol style="list-style-type: decimal">
<li>Grab the Surface’s <code>Canvas</code>, “locking” it so only used in this (background) thread.</li>
<li>Draw on it.</li>
<li>Then “push” the Canvas back out to the rest of the world, basically saying “we’re done drawing, you can show it to the user now”.</li>
</ol></li>
</ul>
<p>Overall, this process will cause the Surface to “redraw” as fast as possible, all without blocking the UI thread! This is great for animation, which can be controlled and timed (e.g., in the <code>update()</code> helper method by only updating variables at a particular rate). Moreover, it provides a drawable surface that can be interacted with!</p>
<p>And that gives us a drawable surface that we can interact with in the same way, using the same kind of movement/interaction logic.</p>
<ul>
<li>This demonstrates one way to create low-level game and animation logic using basic Java work; no specific game engines are required (though those exist as well).</li>
</ul>
</div>
</div>
<div id="touch-and-gestures" class="section level2">
<h2><span class="header-section-number">15.2</span> Touch and Gestures</h2>
<p>As this point we have some simple animation and movement, but we would like to make it more interactive. Our <code>View</code> takes up the entire screen so we don’t want to add buttons, but there are other options available.</p>
<p>In particular, we can add <a href="http://developer.android.com/training/gestures/index.html">Touch Gestures</a>. Touch screens are a huge part of Android devices (and mobile devices in general, especially since the first iPhone) that are familiar to most users. We’ve already indirectly used the touch interface, with how we’ve had users click on buttons (theoretically using the touch screen). But here we’re interested in more than just button clicks, which really could come from anywhere. Instead, we’re interested in how we can react to <em>where</em> the user might touch the screen, and even the different ways the user might <em>caress</em> the screen: flings, drags, multi-touch, etc.</p>
<p>Android devices automatically detect various touching interactions (that’s how buttons work); we can respond to these <strong>touch events</strong> by overriding the <code>onTouchEvent()</code> callback, which is executed whenever there something happens that involves the touch screen.</p>
<ul>
<li>For example, we can log out the event to see the kind of details it includes.</li>
</ul>
<p>There are <em>lots</em> of things that can cause <code>TouchEvents</code>, so much of our work involves trying to determine what <em>semantic</em> “gesture” the user made. Luckily, Android provides a number of utility methods and classes to help with this.</p>
<p>The most basic is <code>MotionEvent#getActionMasked()</code>, which extracts the “action type” of the event from the motion that was recorded:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="dt">int</span> action = motionEvent.<span class="fu">getActionMasked</span>(); <span class="co">//get action constant</span>
<span class="dt">float</span> x = event.<span class="fu">getX</span>(); <span class="co">//get location of event</span>
<span class="dt">float</span> y = event.<span class="fu">getY</span>() - <span class="fu">getSupportActionBar</span>().<span class="fu">getHeight</span>(); <span class="co">//closer to center...</span>
<span class="kw">switch</span>(action) {
<span class="kw">case</span> (MotionEvent.<span class="fu">ACTION_DOWN</span>) : <span class="co">//put finger down</span>
<span class="co">//e.g., move ball</span>
view.<span class="fu">ball</span>.<span class="fu">cx</span> = x;
view.<span class="fu">ball</span>.<span class="fu">cy</span> = y;
<span class="kw">return</span> <span class="kw">true</span>;
<span class="kw">case</span> (MotionEvent.<span class="fu">ACTION_MOVE</span>) : <span class="co">//move finger</span>
<span class="co">//e.g., move ball</span>
view.<span class="fu">ball</span>.<span class="fu">cx</span> = x;
view.<span class="fu">ball</span>.<span class="fu">cy</span> = y;
<span class="kw">return</span> <span class="kw">true</span>;
<span class="kw">case</span> (MotionEvent.<span class="fu">ACTION_UP</span>) : <span class="co">//lift finger up</span>
<span class="kw">case</span> (MotionEvent.<span class="fu">ACTION_CANCEL</span>) : <span class="co">//aborted gesture</span>
<span class="kw">case</span> (MotionEvent.<span class="fu">ACTION_OUTSIDE</span>) : <span class="co">//outside bounds</span>
<span class="kw">default</span> :
<span class="kw">return</span> <span class="kw">super</span>.<span class="fu">onTouchEvent</span>(event);
}</code></pre></div>
<p>This lets us react to basic touching. For example, we can make it so that taps (<code>ACTION_DOWN</code>) will “teleport” the ball to where we click! We can also use the <code>ACTION_MOVE</code> events to let us drag the ball around.</p>
<div id="advanced-gestures" class="section level3 unnumbered">
<h3>Advanced Gestures</h3>
<p>We can also detect and react to more complex gestures: long presses, double-taps, or “flings” (a flick or swipe on the screen). As with basic gestures, the Material Design specification details some <a href="https://www.google.com/design/spec/patterns/gestures.html#gestures-drag-swipe-or-fling-details">specific patterns</a> that you should consider when utilizing these interactions.</p>
<p>Android provides a <a href="https://developer.android.com/training/gestures/detector.html#detect"><code>GestureDetector</code></a> class that can be used to identify these actions. The easiest way to use this class—particularly when we’re interested in a particular gesture (like fling)—is to <em>extend</em> <code>GestureDetector.SimpleOnGestureListener</code> to make our own “listener” for gestures. We can then override the callbacks for the gestures we’re interested in responding to: e.g., <code>onFling()</code>.</p>
<ul>
<li>Note that the official documentation says we should also override the <code>onDown()</code> method and have it return <code>true</code> to indicate that we’ve “consumed” (handled) the event—similar to what we’ve done with OptionsMenus. If we return false from this method, then <em>“the system assumes that you want to ignore the rest of the gesture, and the other methods of GestureDetector.OnGestureListener never get called.”</em> However, in my testing the gesture detection works either way, but we’ll follow the spec for now.</li>
</ul>
<p>We can instantiate a <code>GestureDetector</code> by passing in our listener into a <code>GestureDetectorCompat</code> constructor:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java">mDetector = <span class="kw">new</span> <span class="fu">GestureDetectorCompat</span>(<span class="kw">this</span>, <span class="kw">new</span> <span class="fu">MyGestureListener</span>());</code></pre></div>
<p>Then in the Activity’s <code>onTouchEvent()</code> callback, we can pass the event into the Gesture Detector to process:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="dt">boolean</span> gesture = <span class="kw">this</span>.<span class="fu">mDetector</span>.<span class="fu">onTouchEvent</span>(event); <span class="co">//check gestures first!</span>
<span class="kw">if</span>(gesture){
<span class="kw">return</span> <span class="kw">true</span>;
}</code></pre></div>
<ul>
<li>Since the detector’s <code>onTouchEvent()</code> returns a <code>boolean</code> for whether or not a gesture was detected, we can check for whether we should otherwise handle the gesture ourselves.</li>
</ul>
<p>This gives us the ability to “fling” the Ball by taking the detected fling <em>velocity</em> and assigning that as the Ball’s velocity. Note that we need to negate the velocities since they are registered as “backwards” from the coordinates our drawing system is utilizing (though this doesn’t match the documented examples). Scaling down the velocity to 3% produce a reasonable Ball movement speed for me. We can also have the Ball slow down by 1% on each update so it drifts to a stop!</p>
<!-- **** -->
</div>
</div>
<div id="property-animation" class="section level2">
<h2><span class="header-section-number">15.3</span> Property Animation</h2>
<p>We’ve seen how we can create animations simply by adjusting the drawing we do on each frame. This is great for games or other complex animations if we want to have <em>a lot</em> of control over our graphical layout… but sometimes we want to have some simpler, platform-specific effects (that run smoother!) Android actually involves a number of different animation systems that can be used within and <em>across</em> Views:</p>
<ul>
<li><p>We’ve previously talked about some <a href="https://developer.android.com/training/material/animations.html">Material Animations</a> built into the Material Design support library; in particular we discussed creating Activity transition. Android also includes a robust framework for <a href="https://developer.android.com/training/transitions/index.html">Scene Transitions</a> even outside of Material; see <a href="https://developer.android.com/training/animation/index.html">Adding Animations</a> for more details.</p></li>
<li><p>Android also supports <a href="https://developer.android.com/guide/topics/graphics/opengl.html">OpenGL Animations</a> for doing 3D animated systems. This requires knowing the OpenGL API.</p></li>
</ul>
<p>In this section, we will discuss how to use <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html"><strong>Property Animation</strong></a>. This is a general animation framework in which you specify a start state for an Object <em>property</em> (attribute), an end state for that property, and a duration for the animation; the Android systems then changes the property from the start state to the end over that length of time—thereby producing animation!</p>
<ul>
<li><p>The change in property state over time (that is, at any given “frame”) is calculated using <a href="https://en.wikipedia.org/wiki/Interpolation"><strong>interpolation</strong></a>. This is basically a “weighted average” between the the start and end states, where the weight is determined by how close you are to the “start” or “end”. While we often use <em>linear interpolation</em> (so that being 70% across means the end gets 70% of the weight), it is also possible to use <em>non-linear interpolation</em>) (e.g., you need to get 70% across in for the end to have 50% of the weight).</p>
<div class="figure">
<img src="img/animation/interpolation.png" alt="Linearly interpolating colors" />
<p class="caption">Linearly interpolating colors</p>
</div></li>
</ul>
<p>The main engine for doing this kind of interpolated animation in Android is the <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html#value-animator"><code>ValueAnimator</code></a><a href="#fn51" class="footnoteRef" id="fnref51"><sup>51</sup></a> class. This class lets you specify the start state, end state, and animation duration. It will then be able to run through and calculate all of the “intermediate” values throughout the interpolated animation. The <code>ValueAnimator</code> class provides a number of static methods (e.g., <code>.ofInt()</code>, <code>.ofFloat()</code>, <code>.ofArgb()</code>) which creates “animators” for interpolating different <em>value types</em>. For example:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java">ValueAnimator animation = ValueAnimator.<span class="fu">ofFloat</span>(0f, 1f); <span class="co">//interpolate between 0 and 1</span>
animation.<span class="fu">setDuration</span>(<span class="dv">1000</span>); <span class="co">//over 1000ms (1 second)</span>
animation.<span class="fu">start</span>(); <span class="co">//run the animation</span></code></pre></div>
<p>Of course, just performing this interpolation over time doesn’t produce any visible result—it’s changing the numbers, but those numbers don’t correspond to anything.</p>
<p>We can access the interpolated values by registering a <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html#listeners">listener</a> and overriding the callback we’re interested in observing (e.g., <code>onAnimationUpdate()</code> from <code>ValueAnimator.AnimatorUpdateListener</code>). But more commonly, we want to have our interpolated animation change the <em>property</em> of some object—for example, the color of a View, the position of an Button, or the instance variables of an object such as a <code>Ball</code>.</p>
<p>We can do this easily using the <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html#object-animator"><code>ObjectAnimator</code></a><a href="#fn52" class="footnoteRef" id="fnref52"><sup>52</sup></a> subclass. This subclass runs an animation just like the <code>ValueAnimator</code>, but has the built-in functionality to change a property of an object on each interpolated step. It does this by calling a <strong>setter</strong> for that property—thus the object needs to have a <a href="http://docs.oracle.com/javaee/6/tutorial/doc/gjbbp.html">setter method</a> for the property we want to animate:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="co">//change the "alpha" property of foo: will call `foo.setAlpha(float)`</span>
ObjectAnimator anim = ObjectAnimator.<span class="fu">ofFloat</span>(foo, <span class="st">"alpha"</span>, 0f, 1f);
anim.<span class="fu">setDuration</span>(<span class="dv">1000</span>);
anim.<span class="fu">start</span>();</code></pre></div>
<ul>
<li><p>This example will mutate the object by calling the <code>setAlpha()</code> method (the name of the method is generated from the property name following normal CamelCasing style).</p></li>
<li><p>If the object lacks such a setter, such as because we are using a class provided by someone else, we can either make a “wrapper” which will call the appropriate mutating function, or just utilize a <code>ValueAnimator</code> with an appropriate listener.</p></li>
</ul>
<p>For example, we can use this approach to change the circle’s size or position using an interpolated animation (make it “pulse”).</p>
<ul>
<li>Note that we’re just changing the object property; the only reason we see the changed drawing is because Android is constantly refreshing our SurfaceView.</li>
</ul>
<p>The <code>ObjectAnimator</code> interpolator methods support a number of variations as well:</p>
<ul>
<li><p>As long as the object has an appropriate <strong>getter</strong>, it is possible to only pass the Animator an ending value (indicating that the animation should interpolate “from current state to specified end state”)</p></li>
<li><p>We can use <code>.setRepeatCount(ObjectAnimator.INFINITE)</code> and <code>.setRepeatMode(ObjectAnimator.REVERSE)</code> to cause it to repeat back and forth.</p></li>
</ul>
<p>If we want to include multiple animations in sequence, we can use an <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html#choreography"><code>AnimatorSet</code></a>, which gives us methods used to specify the ordering:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="co">//example from docs</span>
ObjectAnimator animX = ObjectAnimator.<span class="fu">ofFloat</span>(obj, <span class="st">"x"</span>, 50f);
ObjectAnimator animY = ObjectAnimator.<span class="fu">ofFloat</span>(obj, <span class="st">"y"</span>, 100f);
AnimatorSet animSetXY = <span class="kw">new</span> <span class="fu">AnimatorSet</span>();
animSetXY.<span class="fu">playTogether</span>(animX, animY);
animSetXY.<span class="fu">start</span>();</code></pre></div>
<p>AnimatorSet animations can get complicated, and we may want to reuse them. Thus best practice is to instead define them in XML as <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html#declaring-xml">resources</a>. Animation resources are put inside the <code>/res/animator</code> directory (<strong>not</strong> the <code>/res/anim/</code> folder, which is for <a href="https://developer.android.com/guide/topics/graphics/view-animation.html">View Animations</a>).</p>
<div class="sourceCode"><pre class="sourceCode xml"><code class="sourceCode xml"><span class="kw"><set</span><span class="ot"> android:ordering=</span><span class="st">"together"</span><span class="kw">></span> <span class="co"><!-- together is default --></span>
<span class="kw"><objectAnimator</span>
<span class="ot"> android:propertyName=</span><span class="st">"x"</span>
<span class="ot"> android:duration=</span><span class="st">"500"</span>
<span class="ot"> android:valueTo=</span><span class="st">"400"</span>
<span class="ot"> android:valueType=</span><span class="st">"intType"</span><span class="kw">/></span>
<span class="co"><!-- ... --></span>
<span class="kw"></set></span></code></pre></div>
<ul>
<li><p>See <a href="https://developer.android.com/guide/topics/resources/animation-resource.html#Property">Property Animation Resources</a><a href="#fn53" class="footnoteRef" id="fnref53"><sup>53</sup></a> for the full XML schema.</p></li>
<li><p>Note that by defining animations as resources, it also means that we can easily have different device configurations use different animations (e.g., perhaps objects move faster on larger displays).</p></li>
</ul>
<p>In order to utilize the XML, we will need to <strong>inflate</strong> the Animator resource, just as we have done with Layouts:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java">ObjectAnimator anim = (ObjectAnimator)AnimatorInflater.<span class="fu">loadAnimator</span>(context, R.<span class="fu">anim</span>.<span class="fu">my_animation</span>);
anim.<span class="fu">setTarget</span>(myObject);
anim.<span class="fu">start</span>();</code></pre></div>
<p>Note that we can also use this same framework to animate changes to <code>Views</code>: Buttons, Images, etc. Views are objects and have properties (along with appropriate <em>getter</em> and <em>setter</em> methods), so we can use just an <code>ObjectAnimator</code>! See <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html#views">Animating Views</a> for a list of properties we can change (a list that includes <code>x, y, rotation, alpha, scaleX, scaleY</code>, and others)</p>
<p>To make this process even simpler, Android also provides a <code>ViewPropertyAnimator</code> class. This Animator is able to easily animate multiple properties together (at the same time), and does so in a much more efficient way. We can access this Animator via the <code>View#animate()</code> method. We then call relevant shortcut methods on this Animator to “add in” addition property animations to the animation set:</p>
<div class="sourceCode"><pre class="sourceCode java"><code class="sourceCode java"><span class="co">//animate x (to 100) and y (to 300) together!</span>
myView.<span class="fu">animate</span>().<span class="fu">x</span>(<span class="dv">100</span>).<span class="fu">y</span>(<span class="dv">300</span>);</code></pre></div>
<p>This allows you to easily specify moderately complex property animations for <code>View</code> objects.</p>
<ul>
<li>But really, if you want to animate layout changes on a modern device, you should use <a href="http://developer.android.com/training/transitions/index.html">transitions</a>, such as the ones we used with Material design.</li>
</ul>
<p>There are <a href="https://developer.android.com/guide/topics/graphics/prop-animation.html">many more ways</a> to customize exactly what you want your animation to be. You can also look at <a href="https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/animation">official demos</a> for more examples of different styles of animation.</p>
</div>
</div>
<!-- Check AppCompat stuff
Clarify inheritance example (i.e., with "alert")
Implement solution
-->
</div>
<div class="footnotes">
<hr />
<ol start="50">
<li id="fn50"><p><a href="https://developer.android.com/reference/android/graphics/Canvas.html" class="uri">https://developer.android.com/reference/android/graphics/Canvas.html</a><a href="graphics.html#fnref50">↩</a></p></li>
<li id="fn51"><p><a href="http://developer.android.com/guide/topics/graphics/prop-animation.html#value-animator" class="uri">http://developer.android.com/guide/topics/graphics/prop-animation.html#value-animator</a><a href="graphics.html#fnref51">↩</a></p></li>
<li id="fn52"><p><a href="http://developer.android.com/guide/topics/graphics/prop-animation.html#object-animator" class="uri">http://developer.android.com/guide/topics/graphics/prop-animation.html#object-animator</a><a href="graphics.html#fnref52">↩</a></p></li>
<li id="fn53"><p><a href="http://developer.android.com/guide/topics/resources/animation-resource.html#Property" class="uri">http://developer.android.com/guide/topics/resources/animation-resource.html#Property</a><a href="graphics.html#fnref53">↩</a></p></li>
</ol>
</div>
</section>
</div>
</div>
</div>
<a href="sensors.html" class="navigation navigation-prev " aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
<a href="styles-themes.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>
<script src="libs/gitbook-2.6.7/js/lunr.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-search.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-sharing.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-fontsettings.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-bookdown.js"></script>
<script src="libs/gitbook-2.6.7/js/jquery.highlight.js"></script>
<script>
gitbook.require(["gitbook"], function(gitbook) {
gitbook.start({
"sharing": {
"github": true,
"facebook": false,
"twitter": false,
"google": false,
"weibo": false,
"instapper": false,
"vk": false,
"all": ["github", "facebook", "twitter", "google"]
},
"fontsettings": {
"theme": "white",
"family": "sans",
"size": 2
},
"edit": {
"link": "https://github.com/info448/book/edit/master/animation.Rmd",
"text": "Edit"
},
"download": ["android-development.pdf", "android-development.epub"],
"toc": {
"collapse": "section",
"scroll_highlight": true
}
});
});
</script>
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://cdn.bootcss.com/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML";
if (location.protocol !== "file:" && /^https?:/.test(script.src))
script.src = script.src.replace(/^https?:/, '');
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>