-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxamarin-feed.xml
More file actions
2212 lines (1509 loc) · 344 KB
/
xamarin-feed.xml
File metadata and controls
2212 lines (1509 loc) · 344 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
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>That CS guy</title>
<description>Blog about computer science, mainly focused on application programming, emphasizing C# development, my favourite language. Sometimes I write about technology in general too.
</description>
<link>http://thatcsharpguy.com/</link>
<atom:link href="http://thatcsharpguy.com/xamarin-feed.xml" rel="self" type="application/rss+xml"/>
<pubDate>Thu, 21 Jun 2018 07:55:15 +0100</pubDate>
<lastBuildDate>Thu, 21 Jun 2018 07:55:15 +0100</lastBuildDate>
<generator>Jekyll v3.8.2</generator>
<item>
<title>Xamarin.Forms & PaintCode</title>
<description><![CDATA[<p>Last week, <a href="https://www.paintcodeapp.com/" target="_blank">PaintCode 3</a> was 20% off. And that gave me an idea for a post. In this post, I’ll explain how to create a custom control using PaintCode and Xamarin.Forms’ <em>custom renderers</em>, starting from the drawing itself, this post may be a little bit too long but I’m sure it is worth it.</p>
<h2 id="paintcode-drawing">PaintCode drawing</h2>
<p>If you have previously created and exported graphics using PaintCode, you probably want to skip this section. But if you haven’t you must start by adding a new canvas, in this case I’ll name it <em>SharpCanvas</em> and its dimensions are 100 by 100, or a 1:1 ratio, which is the same as the drawing I’ll be creating:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/1sharpCanvas.png" alt="&quot;Blank SharpCanvaso&quot; images_set" /></figure>
<p>Then, add a <em>Frame</em>, I’ll be calling it <em>SharpFrame</em>:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/2frame.png" alt="&quot;Blank SharpFrame&quot; images_set" /></figure>
<p>On the left panel, we need to add a color called <em>FillColor</em>, and have it set as a <em>Parameter</em>:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/3fillColor.png" alt="&quot;SharpFrame en blanco&quot; images_set" /></figure>
<p>Now lets add a couple of variables: <em>Width</em> y <em>Height</em> and make their values the same as our <em>frame</em> size, add them also as <em>Parameters</em>:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/4variables.png" alt="&quot;Agregar variables&quot; images_set" /></figure>
<p>Then, with the <em>frame</em> selected, we’re going to drag from the variable panel up to the <em>frame</em>’s properties. So that the Frame’s <em>Width</em> is bound to the <em>Width</em> value from the variables panel, then do the same for <em>Height</em>:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/5setProperties.png" alt="&quot;Linking variables&quot; images_set" /></figure>
<p>And now we’re ready to create our drawing:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/6drawing.png" alt="&quot;Drawing&quot; images_set" /></figure>
<p>Our next task is to link the color we created before (<em>FillColor</em>) with the fill color of our recently created drawing. If you made it right, the color of our drawing will change to the one we set before:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/7linkColor.png" alt="&quot;Drawing&quot; images_set" /></figure>
<p>Pay attention to this next step as it is very important if we want our drawing to adjust whenever the <em>frame</em> changes its size. If the drawing you made is a bézier curve (as it is in this case), double click it until some dots appear its path:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/8waypoints.png" alt="&quot;Waypoints&quot; images_set" /></figure>
<p>Once they show up, select them all and on the right panel, just below the <em>Transforms</em> menu click on the small “I” on the square, so that the four lines that join the central dot with the square become zigzagging lines:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/9selectWaypoints.png" alt="&quot;Select waypoints&quot; images_set" /></figure>
<figure><img src="/postimages//xamarin-forms/paintcode/10shrinkBehavior.png" alt="&quot;Zigzag&quot; images_set" /></figure>
<p>By this point you’ll be able to verify that everything is working properly if you change the values of the variables <em>Height</em> y <em>Width</em> on the left panel.</p>
<p>Before we’re done for a minute with PaintCode, select the tab at the top that has <em>“StyleKit”</em> as its name, and then on the right panel modify the properties so they somewhat match your project:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/11styleKit.png" alt="&quot;Zigzag&quot; images_set" /></figure>
<h2 id="xamarinforms-code">Xamarin.Forms code</h2>
<p>First thing we’re going to do with the code, is create a class that will be the reference for our control. In this case, I called it <code>SharpView</code> but no matter what name you chose, it must inherit from <code>View</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">SharpView</span> <span class="p">:</span> <span class="n">View</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>To it you need to add all the properties you wish, in this case we’ll be adding just one (<code>FillColor</code>) as it’ll be a reference to the fill color of our drawing.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">BindableProperty</span> <span class="n">FillColorProperty</span> <span class="p">=</span>
<span class="n">BindableProperty</span><span class="p">.</span><span class="n">Create</span><span class="p">(</span><span class="n">nameof</span><span class="p">(</span><span class="n">FillColor</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Color</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">SharpView</span><span class="p">),</span> <span class="k">default</span><span class="p">(</span><span class="n">Color</span><span class="p">));</span>
<span class="k">public</span> <span class="n">Color</span> <span class="n">FillColor</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span><span class="n">Color</span><span class="p">)</span><span class="n">GetValue</span><span class="p">(</span><span class="n">FillColorProperty</span><span class="p">);</span> <span class="p">}</span>
<span class="k">set</span> <span class="p">{</span> <span class="n">SetValue</span><span class="p">(</span><span class="n">FillColorProperty</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Lastly, we must set a few default properties, these will improve our control appearance and they can always be overridden if we want to:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="nf">SharpView</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">BackgroundColor</span> <span class="p">=</span> <span class="n">Color</span><span class="p">.</span><span class="n">Transparent</span><span class="p">;</span>
<span class="n">HorizontalOptions</span> <span class="p">=</span> <span class="n">LayoutOptions</span><span class="p">.</span><span class="n">Center</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>And we’re don with the Forms project.</p>
<h2 id="xamarinios-code">Xamarin.iOS code</h2>
<p>In the iOS project, we’ll be creating two new classes: the “native” control and a <em>custom renderer</em>:</p>
<h3 id="native-control">Native control</h3>
<p>Lets start with the native control. Create a new class that inherits from <code>UIView</code>, we’re going to call it <code>UISharpView</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">UISharpView</span> <span class="p">:</span> <span class="n">UIView</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>We need to add at least one constructor that takes a <code>CGRect</code> as an argument, this argument will be passed on to the base class and our control will take its size from it:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="nf">UISharpView</span><span class="p">(</span><span class="n">CGRect</span> <span class="n">rect</span><span class="p">)</span>
<span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">rect</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span></code></pre></figure>
<p>We must add a property that corresponds to the <code>FillColor</code> property in our Forms control, the name can be different, but to keep some consistency, lets name it <code>FillColor</code> too. If you see, inside this property there is a call to the <code>SetNeedsDisplay</code> method, it will force the control to be redrawn every time the property’s value changes:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="n">UIColor</span> <span class="n">_fillColor</span> <span class="p">=</span> <span class="n">UIColor</span><span class="p">.</span><span class="n">FromRGB</span><span class="p">(</span><span class="m">60</span><span class="p">,</span> <span class="m">138</span><span class="p">,</span> <span class="m">63</span><span class="p">);</span>
<span class="k">public</span> <span class="n">UIColor</span> <span class="n">FillColor</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_fillColor</span><span class="p">;</span> <span class="p">}</span>
<span class="k">set</span> <span class="p">{</span> <span class="n">_fillColor</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span> <span class="n">SetNeedsDisplay</span><span class="p">();</span> <span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Now, lets go back to PaintCode for a second, we need to retrieve the drawing’s code. In the export panel make sure that “iOS &gt; C# Xamarin” is selected:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/12codeSelection.png" alt="&quot;Selección de código C# Xamarin&quot; images_set" /></figure>
<p>Once selected, copy all lines of code to this newly created class. You may need to add a couple of <code>using</code> sentences for it to compile. To finish, override the <code>OnDraw</code> method, in it call the method you’ve just copied from PaintCode (in this case it is called <code>DrawSharpCanvas</code>), and pass the fill color and the frame dimensions to it as parameters:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Draw</span><span class="p">(</span><span class="n">CGRect</span> <span class="n">rect</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">DrawSharpCanvas</span><span class="p">(</span><span class="n">FillColor</span><span class="p">,</span> <span class="n">rect</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span> <span class="n">rect</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h3 id="custom-renderer"><em>Custom renderer</em></h3>
<p>Now it’s the time to implement the <em>custom renderer</em>. First off, lets create a new class that inherits from <code>ViewRenderer&lt;TAbstraction, TNative&gt;</code>, I’ll be calling it <code>SharpViewRenderer</code> and it’ll have the Forms class as <code>TAbstraction</code> and <code>UISharpView</code> as <code>TNative</code>. Don’t forget the <code>ExportRenderer</code> attribute:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="na">[assembly: ExportRenderer(typeof(SharpView), typeof(SharpViewRenderer))]</span>
<span class="k">namespace</span> <span class="nn">SharpPaintCode.iOS.Controls</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SharpViewRenderer</span> <span class="p">:</span> <span class="n">ViewRenderer</span><span class="p">&lt;</span><span class="n">SharpView</span><span class="p">,</span> <span class="n">UISharpView</span><span class="p">&gt;</span>
<span class="p">{</span></code></pre></figure>
<p>Inside it, lets create an instance of <code>UISharpView</code> and set it as the element that is to be shown on screen, this is done by overriding the <code>OnElementChanged</code> method. We’ll take the size from the <code>WidthRequest</code> and <code>HeightRequest</code> <code>Element</code>s properties. For the fill color, we’ll also use the <code>FillColor</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnElementChanged</span><span class="p">(</span><span class="n">ElementChangedEventArgs</span><span class="p">&lt;</span><span class="n">SharpView</span><span class="p">&gt;</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="n">OnElementChanged</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">NewElement</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Control</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">sharpFrame</span> <span class="p">=</span> <span class="k">new</span> <span class="n">CGRect</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">Element</span><span class="p">.</span><span class="n">WidthRequest</span><span class="p">,</span> <span class="n">Element</span><span class="p">.</span><span class="n">HeightRequest</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">native</span> <span class="p">=</span> <span class="k">new</span> <span class="n">UISharpView</span><span class="p">(</span><span class="n">sharpFrame</span><span class="p">);</span>
<span class="n">native</span><span class="p">.</span><span class="n">FillColor</span> <span class="p">=</span> <span class="n">Element</span><span class="p">.</span><span class="n">FillColor</span><span class="p">.</span><span class="n">ToUIColor</span><span class="p">();</span>
<span class="n">SetNativeControl</span><span class="p">(</span><span class="n">native</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Finally, we need to add a way to modify the <code>FillColor</code> of the native control when we modify it from the Forms project. To do that, inside the <em>renderer</em> we must override the <code>OnElementPropertyChanged</code> and inside it we we’ll change the native fill color property:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnElementPropertyChanged</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">PropertyChangedEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">PropertyName</span><span class="p">.</span><span class="n">Equals</span><span class="p">(</span><span class="n">nameof</span><span class="p">(</span><span class="n">SharpView</span><span class="p">.</span><span class="n">FillColor</span><span class="p">)))</span>
<span class="n">Control</span><span class="p">.</span><span class="n">FillColor</span> <span class="p">=</span> <span class="n">Element</span><span class="p">.</span><span class="n">FillColor</span><span class="p">.</span><span class="n">ToUIColor</span><span class="p">();</span>
<span class="k">else</span>
<span class="k">base</span><span class="p">.</span><span class="n">OnElementPropertyChanged</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>And that’s all about the iOS project.</p>
<h2 id="xamarinandroid-code">Xamarin.Android code</h2>
<p>Similarly, in this project we’ll have to create a “native” view and a *renderer. We’re going to start with the native control:</p>
<h3 id="native-control-1">Native control</h3>
<p>In Android we’ll create our native control class, following the good practices of the Android platform, we’ll call it <code>SharpView</code>, in this case it has to inherit from <code>View</code>, just make sure it inherits from <code>Android.Views.View</code> and not from <code>Xamarin.Forms.View</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">SharpView</span> <span class="p">:</span> <span class="n">View</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>This class must have at least one constructor that takes a <code>Context</code> instance, this instance will be passed on to the base class:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="nf">SharpView</span><span class="p">(</span><span class="n">Context</span> <span class="n">context</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>Now, in this case we need to add a new property, <code>FillColor</code> so that we can set the drawing’s fill color, you should note that inside this property the method <code>Invalidate</code> gets called, this method will force our control to be redrawn:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="n">Color</span> <span class="n">_fillColor</span> <span class="p">=</span> <span class="n">Color</span><span class="p">.</span><span class="n">Argb</span><span class="p">(</span><span class="m">255</span><span class="p">,</span> <span class="m">60</span><span class="p">,</span> <span class="m">138</span><span class="p">,</span> <span class="m">63</span><span class="p">);</span>
<span class="k">public</span> <span class="n">Color</span> <span class="n">FillColor</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_fillColor</span><span class="p">;</span> <span class="p">}</span>
<span class="k">set</span>
<span class="p">{</span>
<span class="n">_fillColor</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
<span class="n">Invalidate</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Now, again, pay attention to this following step: PaintCode doesn’t support Xamarin.Android yet, but for us it makes no difference as Java and Xamarin’s C# are similar enough to translate it ourselves. To star, open again PaintCode and make sure “Android &gt; Java” is selected in the export code panel:</p>
<figure><img src="/postimages//xamarin-forms/paintcode/13androidJava.png" alt="&quot;Selección de código C# Xamarin&quot; images_set" /></figure>
<p>Now, inside the Android project, create a new class called <code>SharpKit</code>, wipe all the boilerplate code and paste in it the code from PaintCode, there should be a ton of errors, but don’t worry, all you have to do is remove the <code>package</code> declaration, erase all the <code>import</code> lines and, if you feel like, put the remaining clas into a C# <em>namespace</em>.</p>
<p>Then, add the following <code>using</code> statements at the top of the file:</p>
<pre>
using System;
using Android.Graphics;
</pre>
<p>The following step is to convert <em>all</em> the Java methods to C#. In Java it is normal for methods and properties to start with a lowercase letter, so, for most of the code it should be enough to make all the methods and properties start with an uppercase letter to save you some time, search and replace the following strings: <code>.save(</code> for <code>.Save(</code>, <code>.set(</code> for <code>.Set(</code>, <code>.reset(</code> for <code>.Reset(</code>, <code>.moveTo(</code> for <code>.MoveTo(</code>, <code>.cubicTo(</code> for <code>.CubicTo(</code>, <code>.width(</code> for <code>.Width(</code>, <code>.height(</code> for <code>.Height(</code>, <code>.top</code> for <code>.Top</code>, <code>.left</code> for <code>.Left</code>.</p>
<p>There are some difficult translations, most of them related to <code>enum</code> datatypes. But don’t worry, take into consideration the following table:</p>
<pre>
paint.setFlags(Paint.ANTI_ALIAS_FLAG); → paint.Flags = PaintFlags.AntiAlias;
paint.setStyle(Paint.Style.FILL); → paint.SetStyle(Paint.Style.Fill);
paint.setColor(fillColor); → paint.Color = new Color(fillColor);
canvas.drawPath(sharpSymbolPath, paint); → canvas.DrawPath(sharpSymbolPath, paint);
</pre>
<p>Once the code compiles again, inside the native control, we need to override the <code>OnDraw</code> method to set it to use the <code>DrawSharpCanvas</code> we added inside the <code>SharpKit</code> class, pass the color and dimensions of your control to it:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnDraw</span><span class="p">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">SharpKit</span><span class="p">.</span><span class="n">DrawSharpCanvas</span><span class="p">(</span><span class="n">canvas</span><span class="p">,</span> <span class="n">_fillColor</span><span class="p">.</span><span class="n">ToArgb</span><span class="p">(),</span> <span class="n">Width</span><span class="p">,</span> <span class="n">Height</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Now, lets add the <em>custom renderer</em>.</p>
<h3 id="custom-renderer-1"><em>Custom renderer</em></h3>
<p>Again, inside the Android project we need to add a new class that inherits from <code>ViewRenderer&lt;TAbstraction, TNative&gt;</code>, lets get creative and name it <code>SharpViewRenderer</code>, it’ll have <code>SharpView</code> (from the central project) as <code>TAbstraction</code> and <code>SharpView</code> (from the Android project) as <code>TNative</code>, for this singular case, we’ll use aliases to not confuse the controls:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">using</span> <span class="nn">FormsSharpView</span> <span class="p">=</span> <span class="n">SharpPaintCode</span><span class="p">.</span><span class="n">Controls</span><span class="p">.</span><span class="n">SharpView</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">NativeSharpView</span> <span class="p">=</span> <span class="n">SharpPaintCode</span><span class="p">.</span><span class="n">Droid</span><span class="p">.</span><span class="n">Controls</span><span class="p">.</span><span class="n">Native</span><span class="p">.</span><span class="n">SharpView</span><span class="p">;</span>
<span class="na">[assembly: ExportRenderer(typeof(FormsSharpView), typeof(SharpViewRenderer))]</span>
<span class="k">namespace</span> <span class="nn">SharpPaintCode.Droid.Controls</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SharpViewRenderer</span> <span class="p">:</span> <span class="n">ViewRenderer</span><span class="p">&lt;</span><span class="n">FormsSharpView</span><span class="p">,</span> <span class="n">NativeSharpView</span><span class="p">&gt;</span>
<span class="p">{</span></code></pre></figure>
<p>The next step is to create an instance of <code>NativeSharpView</code> and set it as the on-screen control for our custom control. For it to happen, override the <code>OnElementChanged</code> and create such instance, pass to it the <code>Context</code> property and set the <code>FillColor</code> from the beginning:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnElementChanged</span><span class="p">(</span><span class="n">ElementChangedEventArgs</span><span class="p">&lt;</span><span class="n">FormsSharpView</span><span class="p">&gt;</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="n">OnElementChanged</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">NewElement</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Control</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">native</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NativeSharpView</span><span class="p">(</span><span class="n">Context</span><span class="p">);</span>
<span class="n">native</span><span class="p">.</span><span class="n">FillColor</span> <span class="p">=</span> <span class="n">Element</span><span class="p">.</span><span class="n">FillColor</span><span class="p">.</span><span class="n">ToAndroid</span><span class="p">();</span>
<span class="n">SetNativeControl</span><span class="p">(</span><span class="n">native</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>We need also a way to modify the native’s <code>FillColor</code> from our Forms control, and to do it, override the <code>OnElementPropertyChanged</code>, inside it, change the property if the property being changed is called <code>FillColor</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnElementPropertyChanged</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">PropertyChangedEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">PropertyName</span><span class="p">.</span><span class="n">Equals</span><span class="p">(</span><span class="n">nameof</span><span class="p">(</span><span class="n">FormsSharpView</span><span class="p">.</span><span class="n">FillColor</span><span class="p">)))</span>
<span class="p">{</span>
<span class="n">Control</span><span class="p">.</span><span class="n">FillColor</span> <span class="p">=</span> <span class="n">Element</span><span class="p">.</span><span class="n">FillColor</span><span class="p">.</span><span class="n">ToAndroid</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="n">OnElementPropertyChanged</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>And, that’s it for our custom control.</p>
<h2 id="demo">Demo</h2>
<p><strong><a href="https://github.com/ThatCSharpGuy/sharp-paintcode" target="_blank">Remember: you can download a full version of this project</a></strong> in GitHub so you can play and learn with it.</p>
<p>In order to test the control, I created a simple app that lets you change the color of two <code>SharpViews</code>, it looks like this while running on iOS (it looks the same in Android):</p>
<p><img src="https://media.giphy.com/media/3oKIPrccIwjWhlrBNS/giphy.gif" /></p>
<p>And with a little more imagination and patience, you can make even more interactive controls:</p>
<p><img src="https://media.giphy.com/media/3oKIPifbi3CJj1g2Dm/giphy.gif" /></p>
]]></description>
<pubDate>Tue, 06 Jun 2017 20:00:01 +0100</pubDate>
<link>http://thatcsharpguy.com/post/custom-renderer-paint-code-en/</link>
<guid isPermaLink="true">http://thatcsharpguy.com/post/custom-renderer-paint-code-en/</guid>
<category>Xamarin</category>
<category>XamarinForms</category>
<category>en</category>
</item>
<item>
<title>More familiar tabs for your users in Xamarin.Forms</title>
<description><![CDATA[<p>Amongst the great variety of out-of-the-box pages that Xamarin.Forms has to offer, we can choose a <code>TabbedPage</code> wich is nothing else than a container to other pages, making them accesible trough tabs. You probable have used them and, as me, you think they are awesome, what it is not so awesome is the fact that they are somewhat limited as they do not allow so much customization.</p>
<p>That is why I decided to create a <a href="https://developer.xamarin.com/guides/xamarin-forms/custom-renderer/" target="_blank">custom renderer</a> that allows to further stylize the tabs, making them more <em>native</em> for your users.</p>
<h2 id="usage">Usage</h2>
<p>To start using this tabs you have two options: install the <a href="https://www.nuget.org/packages/PlatformTabbedPage/" target="_blank">NuGet package</a> in your three projects, or download the <a href="https://github.com/messier16/PlatformTabbedPage" target="_blank">source code</a> and paste in your code directly.</p>
<figure class="console"><pre><code>PM&gt; Install-Package PlatformTabbedPage</code></pre></figure>
<p>After that, you need to create a page that inherits from <code>PlatformTabbedPage</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">HomeTabbedPage</span> <span class="p">:</span> <span class="n">PlatformTabbedPage</span></code></pre></figure>
<p>And as you usually do with a normal <code>TabbedPage</code>, add the child pages in the constructor. It is <strong>very important</strong> that you note that the names do not end with “.png”, because otherwise your tabs will not work properly on iOS.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="k">public</span> <span class="nf">HomeTabbedPage</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">BarBackgroundColor</span> <span class="p">=</span> <span class="n">App</span><span class="p">.</span><span class="n">BarBackgroundColors</span><span class="p">[</span><span class="m">3</span><span class="p">];</span>
<span class="n">SelectedColor</span> <span class="p">=</span> <span class="n">App</span><span class="p">.</span><span class="n">SelectedColors</span><span class="p">[</span><span class="m">0</span><span class="p">];</span>
<span class="n">BarBackgroundApplyTo</span> <span class="p">=</span> <span class="n">BarBackgroundApplyTo</span><span class="p">.</span><span class="n">None</span><span class="p">;</span>
<span class="n">Children</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">ConfigurationPage</span> <span class="p">{</span> <span class="n">Icon</span> <span class="p">=</span> <span class="s">&quot;feed&quot;</span> <span class="p">});</span>
<span class="n">Children</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">BasicContentPage</span><span class="p">(</span><span class="s">&quot;YouTube&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">Icon</span> <span class="p">=</span> <span class="s">&quot;youtube&quot;</span> <span class="p">});</span>
<span class="n">Children</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">BasicContentPage</span><span class="p">(</span><span class="s">&quot;Twitter&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">Icon</span> <span class="p">=</span> <span class="s">&quot;twitter&quot;</span> <span class="p">});</span>
<span class="n">Children</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">BasicContentPage</span><span class="p">(</span><span class="s">&quot;Info&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">Icon</span> <span class="p">=</span> <span class="s">&quot;info&quot;</span> <span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The we would get something like this (on the left is the same page but created with a common <code>TabbedPage</code>:</p>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<figure><img src="/postimages//xamarin-forms/tabbed-page/android-no-small.gif" alt="&quot;iOS no normal&quot; images_set" /></figure>
</div>
<div class="pure-u-1 pure-u-md-1-2">
<figure><img src="/postimages//xamarin-forms/tabbed-page/android-small.gif" alt="&quot;iOS no normal&quot; images_set" /></figure>
</div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<figure><img src="/postimages//xamarin-forms/tabbed-page/ios-no-small.gif" alt="&quot;iOS no normal&quot; images_set" /></figure>
</div>
<div class="pure-u-1 pure-u-md-1-2">
<figure><img src="/postimages//xamarin-forms/tabbed-page/ios-small.gif" alt="&quot;iOS no normal&quot; images_set" /></figure>
</div>
</div>
<p>Dowload the <a href=" https://github.com/messier16/PlatformTabbedPage" target="_blank">source code</a> so you can see the run and play with the sample app for this post.</p>
<p>And that’s all… now, if you want to know how I managed to deliver this customization, keep on reading.</p>
<h2 id="platformtabbedpage">PlatformTabbedPage</h2>
<p>Among the things that I wanted to customize are the color of the selected item, the color of the unselected item, and when in iOS the icon of the selected element becuase as you may have seen in the previous gifs when using Android it is hard to tell at first sight in which page are we on, while in iOS it is a bit weird that the icon of the selected stays the same as the others.</p>
<h3 id="render-creation">Render creation</h3>
<p>Start by defining a class that inherits from the type of page that we are going to customize.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">PlatformTabbedPage</span> <span class="p">:</span> <span class="n">TabbedPage</span></code></pre></figure>
<p>Then we define the properties, along with its correspondent <code>BindableProperty</code> that will allow these properties to be bindable.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">BindableProperty</span> <span class="n">SelectedColorProperty</span> <span class="p">=</span>
<span class="n">BindableProperty</span><span class="p">.</span><span class="n">Create</span><span class="p">(</span><span class="n">nameof</span><span class="p">(</span><span class="n">SelectedColor</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Color</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">PlatformTabbedPage</span><span class="p">),</span> <span class="k">default</span><span class="p">(</span><span class="n">Color</span><span class="p">));</span>
<span class="k">public</span> <span class="n">Color</span> <span class="n">SelectedColor</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span><span class="n">Color</span><span class="p">)</span><span class="n">GetValue</span><span class="p">(</span><span class="n">SelectedColorProperty</span><span class="p">);</span> <span class="p">}</span>
<span class="k">set</span> <span class="p">{</span> <span class="n">SetValue</span><span class="p">(</span><span class="n">SelectedColorProperty</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">readonly</span> <span class="k">new</span> <span class="n">BindableProperty</span> <span class="n">BarBackgroundColorProperty</span> <span class="p">=</span>
<span class="n">BindableProperty</span><span class="p">.</span><span class="n">Create</span><span class="p">(</span><span class="n">nameof</span><span class="p">(</span><span class="n">BarBackgroundColor</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Color</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">PlatformTabbedPage</span><span class="p">),</span> <span class="k">default</span><span class="p">(</span><span class="n">Color</span><span class="p">));</span>
<span class="k">public</span> <span class="k">new</span> <span class="n">Color</span> <span class="n">BarBackgroundColor</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span><span class="n">Color</span><span class="p">)</span><span class="n">GetValue</span><span class="p">(</span><span class="n">BarBackgroundColorProperty</span><span class="p">);</span> <span class="p">}</span>
<span class="k">set</span> <span class="p">{</span> <span class="n">SetValue</span><span class="p">(</span><span class="n">BarBackgroundColorProperty</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">BindableProperty</span> <span class="n">BarBackgroundApplyToProperty</span> <span class="p">=</span>
<span class="n">BindableProperty</span><span class="p">.</span><span class="n">Create</span><span class="p">(</span><span class="n">nameof</span><span class="p">(</span><span class="n">BarBackgroundApplyTo</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">BarBackgroundApplyTo</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">PlatformTabbedPage</span><span class="p">),</span> <span class="n">BarBackgroundApplyTo</span><span class="p">.</span><span class="n">Android</span><span class="p">);</span>
<span class="k">public</span> <span class="n">BarBackgroundApplyTo</span> <span class="n">BarBackgroundApplyTo</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span><span class="n">BarBackgroundApplyTo</span><span class="p">)</span><span class="n">GetValue</span><span class="p">(</span><span class="n">BarBackgroundApplyToProperty</span><span class="p">);</span> <span class="p">}</span>
<span class="k">set</span> <span class="p">{</span> <span class="n">SetValue</span><span class="p">(</span><span class="n">BarBackgroundApplyToProperty</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The property descriptions are the following:</p>
<ul>
<li><code>SelectedColor</code>: The color of the selected item</li>
<li><code>BarBackgroundColor</code>: The background color of the bar, I decided to hide with <code>new</code> the default implementation, as I’m going to control the behavior of it inside the custom renderer.</li>
<li><code>BarBackgroundApplyTo</code>: An enum that indicates in which platforms the backround color of the bar needs to be modified, the default is Android, as I consider that in iOS it seems a bit weird setting the background color of the bar.</li>
</ul>
<p>Apart from that, I created some extension methods that are useful to work with colors, making them darker or lighter, or help deciding whether one color is light or dark.</p>
<p>Now, we are ready to see each platform implementation:</p>
<h2 id="ios">iOS</h2>
<p>(this renderer is completely based on the <a href="https://github.com/xamarinhq/app-evolve/blob/master/src/XamarinEvolve.iOS/Renderers/SelectedTabPageRenderer.cs" target="_blank">implementation</a> of James Montemagno in the Xamarin’s Evolve App)</p>
<p>In iOS we need to create a renderer that inherits from <code>TabbedRenderer</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">PlatformTabbedPageRenderer</span> <span class="p">:</span> <span class="n">TabbedRenderer</span></code></pre></figure>
<p>After that I defined a property to access to the forms instance of <code>PlatformTabbedPage</code> and another couple to store the default colors of the <code>UITabBar</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">PlatformTabbedPage</span> <span class="n">FormsTabbedPage</span> <span class="p">=&gt;</span> <span class="n">Element</span> <span class="k">as</span> <span class="n">PlatformTabbedPage</span><span class="p">;</span>
<span class="n">UIColor</span> <span class="n">DefaultTintColor</span><span class="p">;</span>
<span class="n">UIColor</span> <span class="n">DefaultBarBackgroundColor</span><span class="p">;</span></code></pre></figure>
<p>If you have previously written a custom renderer you should know of the importance of the <code>OnElementChanged</code> method, because it is called every time your control is going to be rendered on screen. That is why we assign and unassign an event that will allow us to know whent the properties of the bar in the forms project change.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">OldElement</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">e</span><span class="p">.</span><span class="n">OldElement</span><span class="p">.</span><span class="n">PropertyChanged</span> <span class="p">-=</span> <span class="n">OnElementPropertyChanged</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">NewElement</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">e</span><span class="p">.</span><span class="n">NewElement</span><span class="p">.</span><span class="n">PropertyChanged</span> <span class="p">+=</span> <span class="n">OnElementPropertyChanged</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>Then we get and store the default colors of the <code>UITabBar</code> just in case we need them in the future.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">DefaultTintColor</span> <span class="p">=</span> <span class="n">TabBar</span><span class="p">.</span><span class="n">TintColor</span><span class="p">;</span>
<span class="n">DefaultBarBackgroundColor</span> <span class="p">=</span> <span class="n">TabBar</span><span class="p">.</span><span class="n">BackgroundColor</span><span class="p">;</span></code></pre></figure>
<p>Once the original colors are stored, we call a couple of methods that will assign the desired colors.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">SetTintedColor</span><span class="p">();</span>
<span class="n">SetBarBackgroundColor</span><span class="p">();</span></code></pre></figure>
<p>Now it is time to “fill” the icons, and I say “fill” because in reality you need to provide a “filled” version of your icons, one is going to be shown by default while the oter is going to be displayed when the tab is active.</p>
<p>The trick here relies in the fact that the iOS API exposes a property to set an image for each state of a given tab, and that is precisely what this renderer does: takes the original icon, appends the suffix “_active” and sets it aas the image that should be used when the tab is selected:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">if</span> <span class="p">(</span><span class="n">FormsTabbedPage</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">TabBar</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">item</span> <span class="p">=</span> <span class="n">TabBar</span><span class="p">.</span><span class="n">Items</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="kt">var</span> <span class="n">icon</span> <span class="p">=</span> <span class="n">FormsTabbedPage</span><span class="p">.</span><span class="n">Children</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Icon</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">item</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="n">icon</span> <span class="p">=</span> <span class="n">icon</span> <span class="p">+</span> <span class="s">&quot;_active&quot;</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">item</span><span class="p">?.</span><span class="n">SelectedImage</span><span class="p">?.</span><span class="n">AccessibilityIdentifier</span> <span class="p">==</span> <span class="n">icon</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="n">item</span><span class="p">.</span><span class="n">SelectedImage</span> <span class="p">=</span> <span class="n">UIImage</span><span class="p">.</span><span class="n">FromBundle</span><span class="p">(</span><span class="n">icon</span><span class="p">);</span>
<span class="n">item</span><span class="p">.</span><span class="n">SelectedImage</span><span class="p">.</span><span class="n">AccessibilityIdentifier</span> <span class="p">=</span> <span class="n">icon</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">&quot;Unable to set selected icon: &quot;</span> <span class="p">+</span> <span class="n">ex</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>And basically that’s all, we do not require of anything else thanks to the iOS API.</p>
<h2 id="android">Android</h2>
<p>For the Android renderer we must derive from the <code>TabbedPageRenderer</code> class, yes, we need a different renderer for Android.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">PlatformTabbedPageRenderer</span> <span class="p">:</span> <span class="n">TabbedPageRenderer</span></code></pre></figure>
<p>Again, we need some properties to store the default colors:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">PlatformTabbedPage</span> <span class="n">FormsTabbedPage</span> <span class="p">=&gt;</span> <span class="n">Element</span> <span class="k">as</span> <span class="n">PlatformTabbedPage</span><span class="p">;</span>
<span class="n">AndroidColor</span> <span class="n">_selectedColor</span> <span class="p">=</span> <span class="n">AndroidColor</span><span class="p">.</span><span class="n">Black</span><span class="p">;</span>
<span class="n">AndroidColor</span> <span class="n">DefaultUnselectedColor</span> <span class="p">=</span> <span class="n">FormsColor</span><span class="p">.</span><span class="n">Gray</span><span class="p">.</span><span class="n">Darken</span><span class="p">().</span><span class="n">ToAndroid</span><span class="p">();</span>
<span class="k">static</span> <span class="n">AndroidColor</span> <span class="n">BarBackgroundDefault</span><span class="p">;</span>
<span class="n">AndroidColor</span> <span class="n">_unselectedColor</span> <span class="p">=</span> <span class="n">DefaultUnselectedColor</span><span class="p">;</span></code></pre></figure>
<p>In Android, a tabbed page is comprised by two elements: A <code>ViewPager</code> and a <code>TabLayout</code> that work together to act as a single control, given the importance for this renderer, we also need to store a class level reference to both elements:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">ViewPager</span> <span class="n">_viewPager</span><span class="p">;</span>
<span class="n">TabLayout</span> <span class="n">_tabLayout</span><span class="p">;</span></code></pre></figure>
<p>Now, inside the <code>OnElementChanged</code> method we are going to get the references to the Views declared before. The renderer contains both, but they’re “hidden” as <code>View</code> types, that is why the <code>is</code> operator is used to know which cast to use:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">ChildCount</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">v</span> <span class="p">=</span> <span class="n">GetChildAt</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="k">is</span> <span class="n">ViewPager</span><span class="p">)</span>
<span class="n">_viewPager</span> <span class="p">=</span> <span class="p">(</span><span class="n">ViewPager</span><span class="p">)</span><span class="n">v</span><span class="p">;</span>
<span class="k">else</span> <span class="nf">if</span> <span class="p">(</span><span class="n">v</span> <span class="k">is</span> <span class="n">TabLayout</span><span class="p">)</span>
<span class="n">_tabLayout</span> <span class="p">=</span> <span class="p">(</span><span class="n">TabLayout</span><span class="p">)</span><span class="n">v</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>We get the default colors for the bar background and then we set our own colors:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">BarBackgroundDefault</span> <span class="p">=</span> <span class="p">(</span><span class="n">_tabLayout</span><span class="p">.</span><span class="n">Background</span> <span class="k">as</span> <span class="n">ColorDrawable</span><span class="p">)?.</span><span class="n">Color</span> <span class="p">??</span> <span class="n">Android</span><span class="p">.</span><span class="n">Graphics</span><span class="p">.</span><span class="n">Color</span><span class="p">.</span><span class="n">Green</span><span class="p">;</span>
<span class="n">SetSelectedColor</span><span class="p">();</span>
<span class="n">SetBarBackgroundColor</span><span class="p">();</span></code></pre></figure>
<p>Unlike iOS, Android makes use of a couple of methods that are called everytime a tab is selected/unselected, that is why we need to assign them inside our aforementioned method:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">_tabLayout</span><span class="p">.</span><span class="n">TabSelected</span> <span class="p">+=</span> <span class="n">TabLayout_TabSelected</span><span class="p">;</span>
<span class="n">_tabLayout</span><span class="p">.</span><span class="n">TabUnselected</span> <span class="p">+=</span> <span class="n">TabLayout_TabUnselected</span><span class="p">;</span></code></pre></figure>
<p>To finish overriding of this method, we need to set the color of all icons as unselected, and then mark the firs one as selected:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">SetupTabColors</span><span class="p">();</span>
<span class="n">SelectTab</span><span class="p">(</span><span class="m">0</span><span class="p">);</span></code></pre></figure>
<p>And to finish this masterpiece, here is the “magic”. In the methods that handle each selection/unselection of tabs we need to apply a color filter to each image, as you can see the color varies depending on the tab being selected or not:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">private</span> <span class="k">void</span> <span class="nf">TabLayout_TabUnselected</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">TabLayout</span><span class="p">.</span><span class="n">TabUnselectedEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">tab</span> <span class="p">=</span> <span class="n">e</span><span class="p">.</span><span class="n">Tab</span><span class="p">;</span>
<span class="n">tab</span><span class="p">.</span><span class="n">Icon</span><span class="p">?.</span><span class="n">SetColorFilter</span><span class="p">(</span><span class="n">_unselectedColor</span><span class="p">,</span> <span class="n">PorterDuff</span><span class="p">.</span><span class="n">Mode</span><span class="p">.</span><span class="n">SrcIn</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">TabLayout_TabSelected</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">TabLayout</span><span class="p">.</span><span class="n">TabSelectedEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">tab</span> <span class="p">=</span> <span class="n">e</span><span class="p">.</span><span class="n">Tab</span><span class="p">;</span>
<span class="n">tab</span><span class="p">.</span><span class="n">Icon</span><span class="p">?.</span><span class="n">SetColorFilter</span><span class="p">(</span><span class="n">_selectedColor</span><span class="p">,</span> <span class="n">PorterDuff</span><span class="p">.</span><span class="n">Mode</span><span class="p">.</span><span class="n">SrcIn</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>And that’s it, the renderer for Android is slightly more complicated than the iOS one, but it isn’t hard to understand.</p>
]]></description>
<pubDate>Thu, 02 Feb 2017 19:00:01 +0000</pubDate>
<link>http://thatcsharpguy.com/post/platformtabbedpage-xamarin-forms-en/</link>
<guid isPermaLink="true">http://thatcsharpguy.com/post/platformtabbedpage-xamarin-forms-en/</guid>
<category>Xamarin</category>
<category>XamarinForms</category>
<category>NuGetRecomendado</category>
<category>en</category>
</item>
<item>
<title>Learning Xamarin.iOS at Stanford</title>
<description><![CDATA[<p>To finish the year in a good manner I decided to ramp up my Xamarin.iOS development skills. So far I had only worked on iOS apps using Xamarin.Forms and I have only made small apps following Apple tutorials <a href="https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/" target="_blank">like this</a>, but for me that is not enough, I wanted to take a course like I did a few years ago when I took one on Android dev, with that in mind <a href="https://twitter.com/io_exception/status/807047846063177728" target="_blank">I asked on Twitter</a> whether NSScreencasts was a good choice for novices.</p>
<p>Luckily I got a several answers of all kind, generally the answers where a big yes, but not for beginners (which I consider myself), a couple of them suggested some books, but three suggested I should took a free Stanford Course with the nuance that it was given using Swift 2, to me it isn’t a huge deal as my main focus is to learn the workflow and essentials of iOS dev, and then transfer that knowledge to Xamarin.iOS.</p>
<p>I’m about 3 lectures away from finishing the course, but in this post I’ll share my experience so far:</p>
<h2 id="syntax-differences">Syntax differences</h2>
<p>This may be because I am a .NET developer since 2008 but, mate: Swift syntax is so weird! and my guess is that is in great part thanks to Obj-C… but anyway, the differences for basic properties, methods, base classes, aren’t that big. You can get around them thanks to the great intellisense offered by Xamarin/Visual studio since they are mostly only casing (<code>tableView</code> vs <code>TableView</code>) distinctions, if you want, you can read my post on basic <a href="../xamarin-ios-vs-traditional" target="_blank">Xamarin.iOS vs Swift differences</a>.</p>
<p>In other cases you’ll have to look for the arguments and return type of a given method to be 90% that you are calling the right method (the other 10% comes from executing and see if it works as expected).</p>
<h2 id="enums-whith-associated-values">Enums whith associated values</h2>
<p>WAIT WHAT? really? wow, there are no such things when using C#… you’ll have to work around this issue, C# do have enums but they’re <em>masked</em> integer types and no other info can be associated with them.</p>
<p>What I ended up doing to overcome this issue for the <em>Calculator assignment</em> was to create <a href="https://github.com/fferegrino/cs193/blob/master/Calculator/CalculatorBrainDictionaries.cs" target="_blank">a few dictionaries</a>. It got a bit messy, but in the end it worked pretty good.</p>
<h2 id="closures">Closures</h2>
<p>Closures in Swift are our good (not so) old Func and Action types in C#. You don’t get the nice $1, $2 syntax, but who needs that? A thing to note is that in Swift you the possibility to specify how a local variable will be referenced inside a closure, in order to avoid memory leaks.</p>
<h2 id="of-vars-and-properties">Of vars and properties</h2>
<p>In Swift exist properties which are almost, almost like properties in C#, you can see this when using the “stored properties”:</p>
<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span></span><span class="kd">class</span> <span class="nc">AxesDrawer</span>
<span class="p">{</span>
<span class="kd">var</span> <span class="nv">color</span> <span class="p">=</span> <span class="bp">UIColor</span><span class="p">.</span><span class="n">blueColor</span><span class="p">()</span>
<span class="kd">var</span> <span class="nv">minimumPointsPerHashmark</span><span class="p">:</span> <span class="n">CGFloat</span> <span class="p">=</span> <span class="mi">40</span></code></pre></figure>
<p>Which are somewhat like the “automplmemented properties” in C#</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">class</span> <span class="nc">AxesDrawer</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">UIColor</span> <span class="n">Color</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="n">CGFloat</span> <span class="n">MinimumPointsPerHashmark</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></code></pre></figure>
<p>In both languages you can have computed properties:</p>
<figure class="highlight"><pre><code class="language-swift" data-lang="swift"><span></span><span class="c1">// Swift</span>
<span class="kd">class</span> <span class="nc">AxesDrawer</span>
<span class="p">{</span>
<span class="kd">private</span> <span class="kd">var</span> <span class="nv">_color</span> <span class="p">:</span> <span class="bp">UIColor</span> <span class="p">=</span> <span class="bp">UIColor</span><span class="p">.</span><span class="n">blueColor</span><span class="p">()</span>
<span class="kd">var</span> <span class="nv">color</span> <span class="p">:</span> <span class="bp">UIColor</span> <span class="p">{</span>
<span class="kr">get</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">_color</span>
<span class="p">}</span>
<span class="kr">set</span> <span class="p">{</span>
<span class="n">_color</span> <span class="p">=</span> <span class="n">newValue</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="c1">// C#</span>
<span class="k">class</span> <span class="nc">AxesDrawer</span>
<span class="p">{</span>
<span class="n">UIColor</span> <span class="n">_color</span> <span class="p">=</span> <span class="n">UIColor</span><span class="p">.</span><span class="n">Blue</span><span class="p">;</span>
<span class="k">public</span> <span class="n">UIColor</span> <span class="n">Color</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_color</span><span class="p">;</span> <span class="p">}</span>
<span class="k">set</span> <span class="p">{</span> <span class="n">_color</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Another cool feature that I would enjoy in C# are the property observers (<code>willSet</code> and <code>didSet</code>) which behavior we can mimic in C# using computed properties but the code does not look as clean as with Apple’s language:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="kt">double</span> <span class="n">_scale</span> <span class="p">=</span> <span class="m">0.9</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">double</span> <span class="n">Scale</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_scale</span><span class="p">;</span> <span class="p">}</span>
<span class="k">set</span>
<span class="p">{</span>
<span class="c1">// willSet code</span>
<span class="n">_scale</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
<span class="c1">// didSet code </span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="implementing-protocols">Implementing protocols</h2>
<p>When implementing protocols, there is a weird thing that happens: At first I thought that Protocols in Swift where like Interfaces in C#… turns out they are not! When using protocols there are some methods or properties that you are not obligated to implement whereas when using an interface you are required to implement all the members defined within it, so the guys at Xamarin came up with this weird solution where you need to implement an <em>EMPTY</em> interface that has nothing but metadata that you can use to mimic the protocols behavior (<a href="https://developer.xamarin.com/api/type/MonoTouch.UIKit.IUITextViewDelegate/" target="_blank">see here</a>). For example, take a look at the approach to create a delegate for the UITextField and respond to a protocol’s member call:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">TweetTableViewController</span> <span class="p">:</span> <span class="n">UITableViewController</span><span class="p">,</span> <span class="n">IUITextFieldDelegate</span>
<span class="p">{</span>
<span class="c1">// ...</span>
<span class="na"> [Export(&quot;textFieldShouldReturn:&quot;)]</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="nf">ShouldReturn</span><span class="p">(</span><span class="n">UITextField</span> <span class="n">textField</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// Delegate code</span></code></pre></figure>
<h2 id="swifts-extensions-to-types">Swift’s extensions to types</h2>
<p>When it comes to extend the capabilities of classes, Swift offers a more range of movement than C# since you can add properties, constructors and make a class adopt a protocol. C# only allows to “extend” vía static methods, no other members can be added to a given type.</p>
<h2 id="using-the-ios-interface-designer">Using the iOS interface designer</h2>
<p>Neither the Android designer nor the iOS designer are perfect in their current form, and as such I think it is awesome that you can use Xcode to create your UI and then have it sync and map every outlet and action in your C# project within Xamarin Studio. What you need to do is to <em>right click</em> on your storyboard file and select <code>Open with Xcode interface builder</code>.</p>
<p>Every time you save your interface in Xcode it’ll be synced to Xamarin Studio without issues.</p>
<p>The Xamarin approach will create a WhateverViewController.designer.cs containing a partial definition of your <code>UIViewController</code> derivate class, in it all the outlets and actions of your view controller will be stored, each of them with a certain attribute (for outlets the attribute is <code>[Outlet]</code>) that tells the designer what they are used for. You are not supposed to mess with this file, however, if you need to take an outlet out of there you can do so… as long as you place it somewhere else without the designer attribute, as I did when I had to perform an action as soon as a view was assigned:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">FaceView</span> <span class="n">_faceView</span><span class="p">;</span>
<span class="na">[Outlet]</span>
<span class="k">protected</span> <span class="n">FaceView</span> <span class="n">FaceView</span>
<span class="p">{</span>
<span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_faceView</span><span class="p">;</span> <span class="p">}</span>
<span class="k">set</span>
<span class="p">{</span>
<span class="n">_faceView</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
<span class="c1">// didSet:</span>
<span class="kt">var</span> <span class="n">gesture</span> <span class="p">=</span> <span class="k">new</span> <span class="n">UIPinchGestureRecognizer</span><span class="p">();</span>
<span class="n">gesture</span><span class="p">.</span><span class="n">AddTarget</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">_faceView</span><span class="p">.</span><span class="n">ChangeScale</span><span class="p">(</span><span class="n">gesture</span><span class="p">));</span>
<span class="c1">// Ommited for brevity ...</span>
<span class="n">UpdateUI</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Despite the fact of that you must be switching between the Xcode designer and Xamarin’s IDE you should worry no more, you are in good hands when it comes to design the interface of your app.</p>
<p>I do have a complaint about the integration and that is because at the moment I was taking the course it was impossible to open a .storyboard file modified with Xcode 8 in Xamarin Studio, but I think they’re addressing this problem.</p>
<h2 id="custom-views">Custom views</h2>
<p>Just as you can create custom controls using Swift or Obj-C you can create custom views using C#, there are a few things to take into consideration, though:</p>
<p>Make sure that your custom view implements a public constructor that takes an <code>IntPtr</code> instance as a parameter:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="nf">FaceView</span> <span class="p">(</span><span class="n">IntPtr</span> <span class="n">handle</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span> <span class="p">(</span><span class="n">handle</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>Also, make sure to register your custom views to be visible at design time in the editor, using the appropiate attributes <code>Register</code> and <code>DesignTimeVisible</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="na">[Register(&quot;FaceView&quot;), DesignTimeVisible(true)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">FaceView</span> <span class="p">:</span> <span class="n">UIView</span>
<span class="p">{</span></code></pre></figure>
<p>If you want your properties to be available for modification at design time you will need to mark them with yet another couple of attributes (<code>Export</code> and <code>Browsable</code>):</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="na">[Export(&quot;Color&quot;), Browsable(true)]</span>
<span class="k">public</span> <span class="n">UIColor</span> <span class="n">Color</span>
<span class="p">{</span> <span class="c1">// ...</span></code></pre></figure>
<h2 id="coredata">CoreData</h2>
<p>Uh, for what I’ve been reading CoreData isn’t that easy to use with Xamarin… yet it is possible. I didn’t try to do the assignments, mainly because I find it too specific for my purposes at the moment. If you want to try, maybe this links points to a sample that uses this feature in Xamarin: <a href="https://developer.xamarin.com/samples/monotouch/ThreadedCoreData/" target="_blank">ThreadedCoreData sample</a>.</p>
<h2 id="my-code">My code</h2>
<p>In case you are interested, you can see the code I created &amp; “translated” from some of the on class demos and assignments for this course in this <a href="https://github.com/fferegrino/cs193" target="_blank">GitHub repo</a> feel free to reach to me in case of doubts.</p>
<h2 id="so-where">So… where?</h2>
<p>You can see the lectures from <a href="https://itunes.apple.com/mx/course/developing-ios-9-apps-swift/id1104579961?l=en" target="_blank">iTunes U</a> or <a href="https://www.youtube.com/watch?v=_lRx1zoriPo&amp;list=PLsJq-VuSo2k26duIWzNjXztkZ7VrbppkT" target="_blank">YouTube</a>.</p>
<h2 id="to-paul-hegarty">To Paul Hegarty</h2>
<p>I’m 99.9999% sure that you won’t read this, but just in case you do: I want to thank you for this lecture, you cannot imagine the knowledge I have gained by simply sitting in front of a PC listening to you, following your code demos and doing the assignments, even using Xamarin. Also thanks to Stanford University for providing this course for free (even though I’d pay for it, seriously!)</p>
]]></description>
<pubDate>Tue, 27 Dec 2016 08:00:00 +0000</pubDate>
<link>http://thatcsharpguy.com/post/learning-xamarin-ios-stanford-cs193p/</link>
<guid isPermaLink="true">http://thatcsharpguy.com/post/learning-xamarin-ios-stanford-cs193p/</guid>
<category>Xamarin</category>
<category>XamariniOS</category>
<category>en</category>
</item>
<item>
<title>Full page camera in Xamarin.Forms</title>
<description><![CDATA[<p>It has been a while since I coded <a href="..\Aharphat-Android" target="_blank">CharpHat</a>, which is an app that lets you snap a picture of anything and then put a nice C# graduation cap on it. That app was far from perfect, but it helped me to practice the usage of custom page renderers.</p>
<p>Today I decided to retake that project, but this time trying to isolate the code needed to build the interface and funcionality of the page, so that anyone looking forward to implement a full camera page in their apps could reuse the code for their own projects. So be sure to <strong><a href="https://github.com/messier16/FullCameraPage" target="_blank">grab the source code</a></strong> for this post.</p>
<h2 id="forms-abstractions">Forms abstractions</h2>
<p><small><a href="https://github.com/messier16/FullCameraPage/blob/master/FullCameraApp/CameraPage.cs" target="_blank">Here is the source code for this section.</a></small></p>
<p>Let’s start by creating the Xamarin.Forms page that will serve as our point of interaction with the custom code:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">class</span> <span class="nc">CameraPage</span> <span class="p">:</span> <span class="n">ContentPage</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">delegate</span> <span class="k">void</span> <span class="nf">PhotoResultEventHandler</span><span class="p">(</span><span class="n">PhotoResultEventArgs</span> <span class="n">result</span><span class="p">);</span>
<span class="k">public</span> <span class="k">event</span> <span class="n">PhotoResultEventHandler</span> <span class="n">OnPhotoResult</span><span class="p">;</span></code></pre></figure>
<p>Business as usual, create a class deriving from <code>ContentPage</code>. I have added an event handler as I want to access the picture taken by the user. Now let’s throw in some methods to call whenever an user performs an action in our camera page (in this case, the user will be allowed to take a photo or cancel the action):</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">void</span> <span class="nf">SetPhotoResult</span><span class="p">(</span><span class="kt">byte</span><span class="p">[]</span> <span class="n">image</span><span class="p">,</span> <span class="kt">int</span> <span class="n">width</span> <span class="p">=</span> <span class="p">-</span><span class="m">1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">height</span> <span class="p">=</span> <span class="p">-</span><span class="m">1</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">OnPhotoResult</span><span class="p">?.</span><span class="n">Invoke</span><span class="p">(</span><span class="k">new</span> <span class="n">PhotoResultEventArgs</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Cancel</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">OnPhotoResult</span><span class="p">?.</span><span class="n">Invoke</span><span class="p">(</span><span class="k">new</span> <span class="n">PhotoResultEventArgs</span><span class="p">());</span>
<span class="p">}</span> </code></pre></figure>
<p>For reference, see the properties inside the <code>PhotoResultEventArgs</code> class:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="kt">bool</span> <span class="n">Success</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">Width</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">Height</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">Image</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span></code></pre></figure>
<p>Now, time to move on to the platform specifics.</p>
<h2 id="in-xamarinios">In Xamarin.iOS</h2>
<p><small><a href="https://github.com/messier16/FullCameraPage/blob/master/FullCameraApp.iOS/CameraPageRenderer.cs" target="_blank">Here is the source code for this section.</a></small></p>
<p>To be honest, this implementation is the easiest by far. Start off by creating a class that inherits from <code>PageRenderer</code>, and to add the <code>ExportRenderer</code> attribute:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="na">[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]</span>
<span class="k">namespace</span> <span class="nn">FullCameraPage.iOS</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CameraPageRenderer</span> <span class="p">:</span> <span class="n">PageRenderer</span></code></pre></figure>
<p>Now, an this is very important, you need to override the <code>ViewDidLoad</code> method, since it gets called as soon as our page is loaded by the iOS mechanisms. For the sake of organisation let’s split the code in several other methods:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="k">void</span> <span class="nf">ViewDidLoad</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="n">ViewDidLoad</span><span class="p">();</span>
<span class="n">SetupUserInterface</span><span class="p">();</span>
<span class="n">SetupEventHandlers</span><span class="p">();</span>
<span class="n">AuthorizeCameraUse</span><span class="p">();</span>
<span class="n">SetupLiveCameraStream</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>
<h3 id="setupuserinterface">SetupUserInterface</h3>
<p>As the name states, here is where you need to build the UI. As you may have guessed, it is all done by code, but don’t worry, it is very easy… as long as your UI isn’t so complex, but you can do whatever you need here.</p>
<p>For this sample the UI will consist of a couple of buttons and a surface where the live preview from the camera is going to be shown, so you need to declare them on a class-level scope:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">VectorButton</span> <span class="n">takePhotoButton</span><span class="p">;</span>
<span class="n">VectorButton</span> <span class="n">cancelPhotoButton</span><span class="p">;</span>
<span class="n">UIView</span> <span class="n">liveCameraStream</span><span class="p">;</span></code></pre></figure>
<p>To set the items in place you need to think as if you were working with a relative layout, meaning that you need to set the position of each item within the screen. For example, look at how the live camera preview view is positioned:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">private</span> <span class="k">void</span> <span class="nf">SetupUserInterface</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Code ommited ...</span>
<span class="n">liveCameraStream</span> <span class="p">=</span> <span class="k">new</span> <span class="n">UIView</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Frame</span> <span class="p">=</span> <span class="k">new</span> <span class="n">CGRect</span><span class="p">(</span><span class="m">0f</span><span class="p">,</span> <span class="m">0f</span><span class="p">,</span> <span class="n">View</span><span class="p">.</span><span class="n">Bounds</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span> <span class="n">View</span><span class="p">.</span><span class="n">Bounds</span><span class="p">.</span><span class="n">Height</span><span class="p">)</span>
<span class="p">};</span>
<span class="c1">// Code ommited ...</span>
<span class="n">View</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">liveCameraStream</span><span class="p">);</span>
<span class="c1">// Code ommited ...</span>
<span class="p">}</span></code></pre></figure>
<h3 id="setupeventhandlers">SetupEventHandlers</h3>
<p>Now that the UI has been built, let’s hook up the event handlers to each control, luckly for this sample there are only two buttons on screen: one to take the picture and the other to cancel the whole thing.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">cancelPhotoButton</span><span class="p">.</span><span class="n">TouchUpInside</span> <span class="p">+=</span> <span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="p">(</span><span class="n">Element</span> <span class="k">as</span> <span class="n">CameraPage</span><span class="p">).</span><span class="n">Cancel</span><span class="p">();</span>
<span class="p">};</span>
<span class="n">takePhotoButton</span><span class="p">.</span><span class="n">TouchUpInside</span> <span class="p">+=</span> <span class="k">async</span> <span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">data</span> <span class="p">=</span> <span class="k">await</span> <span class="n">CapturePhoto</span><span class="p">();</span>
<span class="n">UIImage</span> <span class="n">imageInfo</span> <span class="p">=</span> <span class="k">new</span> <span class="n">UIImage</span><span class="p">(</span><span class="n">data</span><span class="p">);</span>
<span class="p">(</span><span class="n">Element</span> <span class="k">as</span> <span class="n">CameraPage</span><span class="p">).</span><span class="n">SetPhotoResult</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">ToArray</span><span class="p">(),</span>
<span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">imageInfo</span><span class="p">.</span><span class="n">Size</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span>
<span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">imageInfo</span><span class="p">.</span><span class="n">Size</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span>
<span class="p">};</span></code></pre></figure>
<p>The property <code>Element</code> contains a reference to the page associated to the renderer, and is our way to interact with our Forms project. As for the method <code>CapturePhoto</code>… we’ll see it later.</p>
<h2 id="authorizecamerause">AuthorizeCameraUse</h2>
<p>Now it’s time to ask the user for its permission to access the camera:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="kt">var</span> <span class="n">authorizationStatus</span> <span class="p">=</span> <span class="n">AVCaptureDevice</span><span class="p">.</span><span class="n">GetAuthorizationStatus</span><span class="p">(</span><span class="n">AVMediaType</span><span class="p">.</span><span class="n">Video</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">authorizationStatus</span> <span class="p">!=</span> <span class="n">AVAuthorizationStatus</span><span class="p">.</span><span class="n">Authorized</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">await</span> <span class="n">AVCaptureDevice</span><span class="p">.</span><span class="n">RequestAccessForMediaTypeAsync</span><span class="p">(</span><span class="n">AVMediaType</span><span class="p">.</span><span class="n">Video</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>But wait a minute, before executing the code above, make sure you have added the key <code>Privacy - Camera Usage Description</code> to the Info.plist in your project.</p>
<h3 id="setuplivecamerastream">SetupLiveCameraStream</h3>
<p>Now the “heavy” stuff.</p>
<p>Start by declaring at class-level scope an <code>AVCaptureSession</code>, <code>AVCaptureDeviceInput</code> and <code>AVCaptureStillImageOutput</code>, as they will hel us access the camera, display the live feed and capture the photo.</p>
<p>Then, inside the <code>SetupLiveCameraStream</code> method, initialize the capture session, create a preview layer with the same size as our <code>liveCameraStream</code>, and add it as a sublayer of it:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="n">captureSession</span> <span class="p">=</span> <span class="k">new</span> <span class="n">AVCaptureSession</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">videoPreviewLayer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">AVCaptureVideoPreviewLayer</span><span class="p">(</span><span class="n">captureSession</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Frame</span> <span class="p">=</span> <span class="n">liveCameraStream</span><span class="p">.</span><span class="n">Bounds</span>
<span class="p">};</span>
<span class="n">liveCameraStream</span><span class="p">.</span><span class="n">Layer</span><span class="p">.</span><span class="n">AddSublayer</span><span class="p">(</span><span class="n">videoPreviewLayer</span><span class="p">);</span></code></pre></figure>
<p>Next, “create” a capture device (you can configure it to work according to your needs). And then, from it create the an input source for the capture session:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="kt">var</span> <span class="n">captureDevice</span> <span class="p">=</span> <span class="n">AVCaptureDevice</span><span class="p">.</span><span class="n">DefaultDeviceWithMediaType</span><span class="p">(</span><span class="n">AVMediaType</span><span class="p">.</span><span class="n">Video</span><span class="p">);</span>
<span class="n">ConfigureCameraForDevice</span><span class="p">(</span><span class="n">captureDevice</span><span class="p">);</span>
<span class="n">captureDeviceInput</span> <span class="p">=</span> <span class="n">AVCaptureDeviceInput</span><span class="p">.</span><span class="n">FromDevice</span><span class="p">(</span><span class="n">captureDevice</span><span class="p">);</span></code></pre></figure>
<p>We have an input (the camera of the device), now we need an output which is going to be a jpeg photograph:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="kt">var</span> <span class="n">dictionary</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NSMutableDictionary</span><span class="p">();</span>
<span class="n">dictionary</span><span class="p">[</span><span class="n">AVVideo</span><span class="p">.</span><span class="n">CodecKey</span><span class="p">]</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NSNumber</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">AVVideoCodec</span><span class="p">.</span><span class="n">JPEG</span><span class="p">);</span>
<span class="n">stillImageOutput</span> <span class="p">=</span> <span class="k">new</span> <span class="n">AVCaptureStillImageOutput</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">OutputSettings</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NSDictionary</span><span class="p">()</span>
<span class="p">};</span></code></pre></figure>
<p>Finalize by setting the input and output of the capture session and starting it:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span> <span class="n">captureSession</span><span class="p">.</span><span class="n">AddOutput</span><span class="p">(</span><span class="n">stillImageOutput</span><span class="p">);</span>
<span class="n">captureSession</span><span class="p">.</span><span class="n">AddInput</span><span class="p">(</span><span class="n">captureDeviceInput</span><span class="p">);</span>
<span class="n">captureSession</span><span class="p">.</span><span class="n">StartRunning</span><span class="p">();</span></code></pre></figure>
<h3 id="capturephoto">CapturePhoto</h3>
<p>At last, the icing on the cake, the code to capture the photo. The code is pretty simple: Take the output and capture a still image from it, as we only need the bytes we get an <code>NSData</code> containing the taken photo.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">NSData</span><span class="p">&gt;</span> <span class="n">CapturePhoto</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">videoConnection</span> <span class="p">=</span> <span class="n">stillImageOutput</span><span class="p">.</span><span class="n">ConnectionFromMediaType</span><span class="p">(</span><span class="n">AVMediaType</span><span class="p">.</span><span class="n">Video</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">sampleBuffer</span> <span class="p">=</span> <span class="k">await</span> <span class="n">stillImageOutput</span><span class="p">.</span><span class="n">CaptureStillImageTaskAsync</span><span class="p">(</span><span class="n">videoConnection</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">jpegImageAsNsData</span> <span class="p">=</span> <span class="n">AVCaptureStillImageOutput</span><span class="p">.</span><span class="n">JpegStillToNSData</span><span class="p">(</span><span class="n">sampleBuffer</span><span class="p">);</span>
<span class="k">return</span> <span class="n">jpegImageAsNsData</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<h2 id="in-xamarinandroid">In Xamarin.Android</h2>
<p><small><a href="https://github.com/messier16/FullCameraPage/blob/master/FullCameraApp.Android/CameraPageRenderer.cs" target="_blank">Here is the source code for this section.</a></small> <br />
This implementation isn’t as clean as it is in iOS. Mainly because Android puts a lot of ephasis in the use of listeners, rather than in event handlers. However, that is not a problem for us.</p>
<p>As with the iOS implementation, start by creating a new class and make it derive from <code>PageRenderer</code> and also make it implement the <code>TextureView.ISurfaceTextureListener</code> interface. Don’t forget the <code>ExportRender</code> attribute:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="na">[assembly: Xamarin.Forms.ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]</span>
<span class="k">namespace</span> <span class="nn">FullCameraPage.Droid</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CameraPageRenderer</span> <span class="p">:</span> <span class="n">PageRenderer</span><span class="p">,</span> <span class="n">TextureView</span><span class="p">.</span><span class="n">ISurfaceTextureListener</span></code></pre></figure>
<p>Then, override the <code>OnElementChanged</code> method (if you have creaated custom renderers before this method may be familar to you), this method is going to be called everytime the a <code>CamerPage</code> is shown on screen:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnElementChanged</span><span class="p">(</span><span class="n">ElementChangedEventArgs</span><span class="p">&lt;</span><span class="n">Xamarin</span><span class="p">.</span><span class="n">Forms</span><span class="p">.</span><span class="n">Page</span><span class="p">&gt;</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="n">OnElementChanged</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
<span class="n">SetupUserInterface</span><span class="p">();</span>
<span class="n">SetupEventHandlers</span><span class="p">();</span></code></pre></figure>
<h3 id="setupuserinterface-1">SetupUserInterface</h3>
<p>In this method we are supposed to create the camera page itself, you can do it by creating an <em>axml</em> file and calling all the Android inflating stuff… Or, like in this sample, you can create it by code.</p>
<p>For this sample, we’ll need a <code>RelativeLayout</code> to work as a container, a <code>TextureView</code> to display the live feed from the camera, and a <code>Button</code> (a <code>PaintCodeButton</code> actually) to snap the photograph. Declare all them at class-level scope:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">RelativeLayout</span> <span class="n">mainLayout</span><span class="p">;</span>
<span class="n">TextureView</span> <span class="n">liveView</span><span class="p">;</span>
<span class="n">PaintCodeButton</span> <span class="n">capturePhotoButton</span><span class="p">;</span></code></pre></figure>
<p>Now, proceed to create them and add them to the screen, for example, see how we can create the container layout and add the <code>TextureView</code> to it:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">void</span> <span class="nf">SetupUserInterface</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">mainLayout</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RelativeLayout</span><span class="p">(</span><span class="n">Context</span><span class="p">);</span>
<span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span> <span class="n">mainLayoutParams</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span><span class="p">(</span>
<span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span><span class="p">.</span><span class="n">MatchParent</span><span class="p">,</span>
<span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span><span class="p">.</span><span class="n">MatchParent</span><span class="p">);</span>
<span class="n">mainLayout</span><span class="p">.</span><span class="n">LayoutParameters</span> <span class="p">=</span> <span class="n">mainLayoutParams</span><span class="p">;</span>
<span class="n">liveView</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TextureView</span><span class="p">(</span><span class="n">Context</span><span class="p">);</span>
<span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span> <span class="n">liveViewParams</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span><span class="p">(</span>
<span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span><span class="p">.</span><span class="n">MatchParent</span><span class="p">,</span>
<span class="n">RelativeLayout</span><span class="p">.</span><span class="n">LayoutParams</span><span class="p">.</span><span class="n">MatchParent</span><span class="p">);</span>
<span class="n">liveView</span><span class="p">.</span><span class="n">LayoutParameters</span> <span class="p">=</span> <span class="n">liveViewParams</span><span class="p">;</span>
<span class="n">mainLayout</span><span class="p">.</span><span class="n">AddView</span><span class="p">(</span><span class="n">liveView</span><span class="p">);</span>
<span class="c1">// Code ommited...</span>
<span class="n">AddView</span><span class="p">(</span><span class="n">mainLayout</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Before continuing, there is another method (<code>OnLayout</code>) we need to override to give our main layout it’s size (and acommodate the UI accordingly):</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnLayout</span><span class="p">(</span><span class="kt">bool</span> <span class="n">changed</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">t</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="n">OnLayout</span><span class="p">(</span><span class="n">changed</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">changed</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">msw</span> <span class="p">=</span> <span class="n">MeasureSpec</span><span class="p">.</span><span class="n">MakeMeasureSpec</span><span class="p">(</span><span class="n">r</span> <span class="p">-</span> <span class="n">l</span><span class="p">,</span> <span class="n">MeasureSpecMode</span><span class="p">.</span><span class="n">Exactly</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">msh</span> <span class="p">=</span> <span class="n">MeasureSpec</span><span class="p">.</span><span class="n">MakeMeasureSpec</span><span class="p">(</span><span class="n">b</span> <span class="p">-</span> <span class="n">t</span><span class="p">,</span> <span class="n">MeasureSpecMode</span><span class="p">.</span><span class="n">Exactly</span><span class="p">);</span>
<span class="n">mainLayout</span><span class="p">.</span><span class="n">Measure</span><span class="p">(</span><span class="n">msw</span><span class="p">,</span> <span class="n">msh</span><span class="p">);</span>
<span class="n">mainLayout</span><span class="p">.</span><span class="n">Layout</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">r</span> <span class="p">-</span> <span class="n">l</span><span class="p">,</span> <span class="n">b</span> <span class="p">-</span> <span class="n">t</span><span class="p">);</span>
<span class="n">capturePhotoButton</span><span class="p">.</span><span class="n">SetX</span><span class="p">(</span> <span class="n">mainLayout</span><span class="p">.</span><span class="n">Width</span> <span class="p">/</span> <span class="m">2</span> <span class="p">-</span> <span class="m">60</span><span class="p">);</span>
<span class="n">capturePhotoButton</span><span class="p">.</span><span class="n">SetY</span><span class="p">(</span><span class="n">mainLayout</span><span class="p">.</span><span class="n">Height</span> <span class="p">-</span> <span class="m">200</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h3 id="setupeventhandlers-1">SetupEventHandlers</h3>
<p>As I said, Android relies mostly on event listeners rather than handlers, so the code for this method is pretty simple. We need to set an event handler for the “sutter” button and assign the listener that will be aware of the <code>SurfaceTexture</code> status (remember that our page render implements an interface?):</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">capturePhotoButton</span><span class="p">.</span><span class="n">Click</span> <span class="p">+=</span> <span class="k">async</span> <span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">bytes</span> <span class="p">=</span> <span class="k">await</span> <span class="n">TakePhoto</span><span class="p">();</span>
<span class="p">(</span><span class="n">Element</span> <span class="k">as</span> <span class="n">CameraPage</span><span class="p">).</span><span class="n">SetPhotoResult</span><span class="p">(</span><span class="n">bytes</span><span class="p">,</span> <span class="n">liveView</span><span class="p">.</span><span class="n">Bitmap</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span> <span class="n">liveView</span><span class="p">.</span><span class="n">Bitmap</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">liveView</span><span class="p">.</span><span class="n">SurfaceTextureListener</span> <span class="p">=</span> <span class="k">this</span><span class="p">;</span></code></pre></figure>
<p>And one more thing, let’s to override the default behavior of the “back” button, so that it acts as a cancel button for the camera:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">OnKeyDown</span><span class="p">(</span><span class="n">Keycode</span> <span class="n">keyCode</span><span class="p">,</span> <span class="n">KeyEvent</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">keyCode</span> <span class="p">==</span> <span class="n">Keycode</span><span class="p">.</span><span class="n">Back</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">(</span><span class="n">Element</span> <span class="k">as</span> <span class="n">CameraPage</span><span class="p">).</span><span class="n">Cancel</span><span class="p">();</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">base</span><span class="p">.</span><span class="n">OnKeyDown</span><span class="p">(</span><span class="n">keyCode</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h3 id="textureviewisurfacetexturelistener-implementation">TextureView.ISurfaceTextureListener implementation</h3>
<p>Now is time to implement the core of our page. Start by writing the code for the <code>OnSurfaceTextureAvailable</code> where we will prepare the output for the camera, but first we’ll need a camera, right?</p>
<p>At class-level scope declare a <code>Camera</code>:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">Android</span><span class="p">.</span><span class="n">Hardware</span><span class="p">.</span><span class="n">Camera</span> <span class="n">camera</span><span class="p">;</span></code></pre></figure>
<p>Inside the method, open the camera (by default it’ll try to open the back camera of the device) and get its parameters. We need them to select the right preview size, because we want things to look great in our app:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="n">camera</span> <span class="p">=</span> <span class="n">Android</span><span class="p">.</span><span class="n">Hardware</span><span class="p">.</span><span class="n">Camera</span><span class="p">.</span><span class="n">Open</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">parameters</span> <span class="p">=</span> <span class="n">camera</span><span class="p">.</span><span class="n">GetParameters</span><span class="p">();</span></code></pre></figure>
<p>Once we have the parameters at hand, we can get the avaliable <code>PreviewSizes</code> and get the one that fits our preview surface. In this case I’m using a simple <a href="#">linq expression</a> to get the best preview size based on aspect ratio:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span></span><span class="kt">var</span> <span class="n">aspect</span> <span class="p">=</span> <span class="p">((</span><span class="kt">decimal</span><span class="p">)</span><span class="n">height</span><span class="p">)</span> <span class="p">/</span> <span class="p">((</span><span class="kt">decimal</span><span class="p">)</span><span class="n">width</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">previewSize</span> <span class="p">=</span> <span class="n">parameters</span><span class="p">.</span><span class="n">SupportedPreviewSizes</span>
<span class="p">.</span><span class="n">OrderBy</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">Math</span><span class="p">.</span><span class="n">Abs</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">Width</span> <span class="p">/</span> <span class="p">(</span><span class="kt">decimal</span><span class="p">)</span><span class="n">s</span><span class="p">.</span><span class="n">Height</span> <span class="p">-</span> <span class="n">aspect</span><span class="p">))</span>
<span class="p">.</span><span class="n">First</span><span class="p">();</span>
<span class="n">parameters</span><span class="p">.</span><span class="n">SetPreviewSize</span><span class="p">(</span><span class="n">previewSize</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span> <span class="n">previewSize</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span>
<span class="n">camera</span><span class="p">.</span><span class="n">SetParameters</span><span class="p">(</span><span class="n">parameters</span><span class="p">);</span></code></pre></figure>
<p>Finish by setting our surface as the preview texture, at this point the only thing left to do is to start the camera:</p>