{"id":37134,"date":"2018-06-07T16:43:39","date_gmt":"2018-06-07T23:43:39","guid":{"rendered":"https:\/\/blog.xamarin.com\/?p=37134"},"modified":"2019-04-04T07:45:47","modified_gmt":"2019-04-04T14:45:47","slug":"build-2018-conference-vision-demo-app","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/build-2018-conference-vision-demo-app\/","title":{"rendered":"Build 2018: Conference Vision Demo App"},"content":{"rendered":"<p>\t\t\t\tAt Build 2018 we shipped Xamarin.Forms 3.0. Did you miss the announcement? No worries, you can <a href=\"https:\/\/www.youtube.com\/watch?v=gNU8-IXjyaI\">watch it here<\/a> to catch up on many of the great new things that will help make you more productive building cross-platform mobile applications with C# and Visual Studio.<\/p>\n<p>In the few weeks leading up to the release, <a href=\"https:\/\/twitter.com\/davidortinau\">David Ortinau<\/a> built <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\">Conference Vision<\/a>, a mobile app for taking photos during the conference and retrieving tags and text about the images. For added fun, he also included a scavenger hunt of sorts where you could help train vision models and identify mobile related products such as Xamarin and our awesome new monkey.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-medium\" src=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/raw\/master\/Design\/Screenshots\/FaceUp.png?raw=true\" width=\"896\" height=\"874\" \/><\/p>\n<p>The goals were to:<\/p>\n<ul>\n<li>Showcase new capabilities of Xamarin.Forms including FlexLayout, CSS, and Visual State Manager.<\/li>\n<li>Produce an aesthetically beautiful app to use at Build.<\/li>\n<li>Show how easy it is to incorporate Cognitive Services for Custom Vision and the Vision API.<\/li>\n<li>Leverage AppCenter for builds, analytics, and distribution.<\/li>\n<li>Use the latest preview of <a href=\"https:\/\/github.com\/xamarin\/Essentials\">Xamarin.Essentials<\/a> for common cross-platform needs.<\/li>\n<\/ul>\n<blockquote style=\"background-color: #f1f1f1;text-align: left;font-size: medium;padding: 10px 20px;border-left: 3px solid #39e\">\n<p style=\"font-size: 15px\">For a patterns and practices approach to mobile app development, read through the <a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/xamarin-forms\/enterprise-application-patterns\/\">Enterprise Application Patterns using Xamarin.Forms<\/a>. The Conference Vision app is not that kind of app and more represents the &#8220;get it done&#8221; style of development.<\/p>\n<\/blockquote>\n<h2>Xamarin.Forms 3.0<\/h2>\n<p>FlexLayout, CSS, and Visual State Manager were covered in a <a href=\"https:\/\/blog.xamarin.com\/xamarin-forms-3-0-released\/\">previous blog with lots of additional resources<\/a>, so we won\u2019t go into those details here. Instead, the following points out where and how they were used.<\/p>\n<h3>FlexLayout<\/h3>\n<p>FlexLayout was used largely for the grid of possible achievements one could unlock when taking photos of product logos. However, while reviewing the code you may not realize that this is a <code>FlexLayout<\/code>.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-37136\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/Screenshot-2018-05-03-19.35.47.png\" alt=\"\" width=\"363\" height=\"642\" \/><\/p>\n<pre class=\"lang:xhtml decode:true\">&lt;local:RepeaterView x:Name=\"AchievementsContainer\" \n                    class=\"container\"\n                    ItemsSource=\"{Binding Achievements}\"&gt;\n    &lt;local:RepeaterView.ItemTemplate&gt;\n        &lt;DataTemplate&gt;\n            &lt;local:AchievementView class=\"item\" \/&gt;\n        &lt;\/DataTemplate&gt;\n    &lt;\/local:RepeaterView.ItemTemplate&gt;\n&lt;\/local:RepeaterView&gt;\n<\/pre>\n<p>In order to leverage data binding and keep the XAML tidy, a custom repeater control was implemented that one of our engineers, Shane Neuville, put together and shared via <a href=\"https:\/\/github.com\/xamarin\/\">gist<\/a>. There are also other repeater implementations you can find online, but this one was super easy and fit the needs of this project. Since the original is based on <code>StackLayout<\/code>, this was updated to use <code>FlexLayout<\/code>. Simple. Yay open source!<\/p>\n<h3>CSS<\/h3>\n<p>CSS is another way to express styles in Xamarin.Forms, and can be used alongside existing XAML styles. XAML styling was used in a few places such as some <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/58e45873d3c1da1198aa5b2cd0b6ee586c95c3af\/ConferenceVision\/ConferenceVision\/Styles\/Global.xaml#L72\">global styles a custom font<\/a> (icon fonts are a great way to add vector images to your app). To add more styling, create individual CSS files for each page. Visual Studio has support for pre-processors, and you can use something like Dan Siegel&#8217;s <a href=\"https:\/\/github.com\/dansiegel\/Mobile.BuildTools\">Mobile Build Tools<\/a> NuGet to add this everywhere.<\/p>\n<p>In the previous XAML snippet you\u2019ll see the <code>class<\/code> names declared. Here is a look at the corresponding CSS for those:<\/p>\n<pre class=\"lang:css decode:true\">.container {\n    flex-direction: row;\n    flex-wrap: wrap;\n    justify-content: space-between;\n}\n\n.item {\n    padding: 0;\n    margin: 5,5;\n    height: 110;\n    width: 90;\n}\n<\/pre>\n<h3>Visual State Manager<\/h3>\n<p>When the phone rotates, the camera interface needs to adjust accordingly. For this, use <code>VisualStateManager<\/code> and trigger a new state based on the view resize. In the page\u2019s resources decalire styles for each orientation, in the code add an override of <code>OnSizeAllocated<\/code>, and depending on the orientation tell the controls which state to represent:<\/p>\n<pre class=\"lang:c# decode:true\">VisualStateManager.GoToState(Container, (width &gt; height) ? \"Horizontal\" : \"Portrait\");\nVisualStateManager.GoToState(LastImage, (width &gt; height) ? \"Horizontal\" : \"Portrait\");\n<\/pre>\n<h2>Extending Xamarin.Forms<\/h2>\n<p>We\u2019ve already noted one way in which to extend Xamarin.Forms by implementing the custom <code>RepeaterView<\/code> control. This requires no platform code at all.<\/p>\n<h3>Effects<\/h3>\n<p>Effects provide a minimal way to tweak a control or layout. Take for example the search entry implemented for filtering the photos taken.<\/p>\n<p><img decoding=\"async\" class=\"alignright size-full wp-image-37139\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/cf_search_entry.png\" alt=\"\" width=\"1090\" height=\"437\" \/><\/p>\n<p>You\u2019ll notice the Entry field doesn\u2019t look like the default <code>Entry<\/code>, and that\u2019s because two handy effects were added from the <a href=\"https:\/\/github.com\/xamarin\/XamarinCommunityToolkit\">XamarinCommunityToolkit<\/a> to remove the border (on iOS) and remove the bottom line (on Android).<\/p>\n<pre class=\"lang:xhtml decode:true\">&lt;Entry \n    Placeholder=\"search by tag\"\n    HeightRequest=\"40\"\n    FlexLayout.Grow=\"1\" \n    FlexLayout.Order=\"1\"&gt;\n    &lt;Entry.Effects&gt;\n        &lt;effects:EntryRemoveBorder \/&gt;\n        &lt;effects:EntryRemoveLine \/&gt;\n    &lt;\/Entry.Effects&gt;\n    &lt;Entry.Margin&gt;\n        &lt;OnPlatform x:TypeArguments=\"Thickness\" Default=\"0\"&gt;\n            &lt;On Platform=\"iOS\" Value=\"10,0\"\/&gt;\n        &lt;\/OnPlatform&gt;\n    &lt;\/Entry.Margin&gt;\n&lt;\/Entry&gt;\n<\/pre>\n<p>To those effects for free, browse through the <a href=\"https:\/\/github.com\/xamarin\/XamarinCommunityToolkit\">XamarinCommunityToolkit<\/a>!<\/p>\n<p>There was another area with specific customization, which needed a separate effect. Such as the content not scrolling behind the navigation bar area but underneath it.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-37138\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/IMG_0881.TRIM_4.gif\" alt=\"\" width=\"266\" height=\"575\" \/><\/p>\n<pre class=\"lang:xhtml decode:true \">&lt;ListView x:Name=\"MediaList\" \n              AbsoluteLayout.LayoutBounds=\"0, 0, 1, 1\"\n              AbsoluteLayout.LayoutFlags=\"SizeProportional\"\n              SeparatorVisibility=\"None\"\n              BackgroundColor=\"Transparent\"\n              RowHeight=\"340\"\n              HasUnevenRows=\"false\"\n              CachingStrategy=\"RecycleElement\"\n              ItemTapped=\"Handle_ItemTappedAsync\"\n              myeffects:ContentInsetAdjustmentBehavior.ContentInset=\"0,100,0,0\"\n              ItemsSource=\"{Binding Memories, Mode=OneWay}\"&gt;\n            &lt;ListView.Effects&gt;\n                &lt;myeffects:ContentInsetAdjustmentBehaviorEffect \/&gt;\n            &lt;\/ListView.Effects&gt;\n<\/pre>\n<p>In the shared code, a <code>BindableProperty<\/code> and <a>effect<\/a> was added to set the inset on the controls (ListView and ScrollView), and then an <a>effect on iOS<\/a> was created to take that value and apply it to the native iOS control. Just that simple!<\/p>\n<h3>Custom Renderer<\/h3>\n<p>You can customize a bit of the navigation bar in Xamarin.Forms, though depending on your design goals you may hit a limitation. <a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/xamarin-forms\/app-fundamentals\/custom-renderer\/\" target=\"_blank\" rel=\"noopener\">Custom renderers<\/a> to the rescue!<\/p>\n<p>Renderers on both <a>iOS<\/a> and <a>Android<\/a> were implemented because they both have very different controls for handling the navigation UI. This begins to explain why limitations are present in Xamarin.Forms for customizing the bar and the best next step is to work on the platform controls. To create a renderer and register it with Xamarin.Forms to be used instead of the default renderer, I created a\u00a0<span class=\"lang:c# decode:true crayon-inline \">CustomNavigationPage<\/span>\u00a0 and then in my platform classes exported them as renderers by adding this to each custom platform renderer class (<a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/master\/ConferenceVision\/ConferenceVision.iOS\/Renderers\/CustomNavigationRenderer.cs\" target=\"_blank\" rel=\"noopener\">iOS<\/a> | <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/master\/ConferenceVision\/ConferenceVision.Android\/Renderers\/CustomNavigationRenderer.cs\" target=\"_blank\" rel=\"noopener\">Android<\/a>):<\/p>\n<pre class=\"lang:c# decode:true \">[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))]\n<\/pre>\n<p>A few other custom renderers are in this project. Check out the camera view (<a>iOS<\/a> | <a>Android<\/a>) and the master detail page renderer (<a>Android<\/a>).<\/p>\n<h2>Cognitive Services<\/h2>\n<p>In the app we use Vision in two ways, <a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/cognitive-services\/custom-vision-service\/\">Custom Vision<\/a> and the <a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/cognitive-services\/computer-vision\/?v=18.05\">Computer Vision API<\/a>.<\/p>\n<h3>Custom Vision<\/h3>\n<p>Custom Vision allows us to train a model to recognize products, generally those files and embed them in our mobile application so we can do the analysis offline. The pieces that come together to make this work are the Custom Vision service, uploading training sets of images with tags, generating models, adding those models to the iOS and Android projects, and using those models to identify achievements (or tags). Check out the great guides and documentation on the <a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/cognitive-services\/custom-vision-service\/\">Custom Vision website<\/a>, and how we use it within the <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/master\/ConferenceVision\/ConferenceVision\/Services\/VisionService.cs\">VisionService.cs<\/a> class.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-37145\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/custom_vision.png\" alt=\"\" width=\"2018\" height=\"800\" \/><\/p>\n<p>During Build 2018 the app was really good at recognizing monkeys and Xamarin, which makes sense as that was the most complete training set. Other achievements were near impossible to obtain until the app is properly trained. So, we added an API call to allow users to upload their images and provide more training. Check out the <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/master\/ConferenceVision\/ConferenceVision\/Views\/ImageTrainingView.xaml\">ImageTrainingView<\/a> and <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/master\/ConferenceVision\/ConferenceVision\/ViewModels\/ImageTrainingViewModel.cs#L30\">ImageTrainingViewModel<\/a>.<\/p>\n<p>More information and examples about Custom Vision can be found on <a href=\"https:\/\/channel9.msdn.com\/Shows\/XamarinShow\/Custom-Vision--Machine-Learning-Made-Easy-with-Jim-Bennett\">Jim Bennett&#8217;s Xamarin Show episode<\/a> and <a href=\"https:\/\/www.jimbobbennett.io\/identifying-my-daughters-toys-using-ai\/\">his blog<\/a>.<\/p>\n<h3>Computer Vision API<\/h3>\n<p>Computer Vision allows us to upload images and get back tags and text that can be identified in the image. Take a look back at the <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\/blob\/master\/ConferenceVision\/ConferenceVision\/Services\/VisionService.cs#L139\">VisionService<\/a> class and how we&#8217;re using the <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Azure.CognitiveServices.Vision.ComputerVision\/\">Computer Vision NuGet<\/a>.<\/p>\n<h2>Explore Today<\/h2>\n<p>The Conference Vision GitHub repositories are linked above with even more interesting things to examine. Grab a copy and explore it yourself, or just install the app on iOS or Android straight off App Center!<\/p>\n<p><strong>Repository:<\/strong> <a href=\"https:\/\/github.com\/Microsoft\/ConferenceVision\">https:\/\/github.com\/Microsoft\/ConferenceVision<\/a><\/p>\n<p><strong>App Center:<\/strong><\/p>\n<ul>\n<li>Android: <a href=\"https:\/\/aka.ms\/androidmovai\">https:\/\/aka.ms\/androidmovai<\/a><\/li>\n<li>iOS: <a href=\"https:\/\/aka.ms\/iosmovai\">https:\/\/aka.ms\/iosmovai<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>At Build 2018 we shipped Xamarin.Forms 3.0. Did you miss the announcement? No worries, you can watch it here to catch up on many of the great new things that will help make you more productive building cross-platform mobile applications with C# and Visual Studio. In the few weeks leading up to the release, David [&hellip;]<\/p>\n","protected":false},"author":553,"featured_media":39167,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[16],"class_list":["post-37134","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-xamarin-forms"],"acf":[],"blog_post_summary":"<p>At Build 2018 we shipped Xamarin.Forms 3.0. Did you miss the announcement? No worries, you can watch it here to catch up on many of the great new things that will help make you more productive building cross-platform mobile applications with C# and Visual Studio. In the few weeks leading up to the release, David [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/37134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/553"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=37134"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/37134\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/39167"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=37134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=37134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=37134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}