├── .gitignore ├── LICENSE ├── README.md ├── XamUIDemo.Android ├── Assets │ └── AboutAssets.txt ├── MainActivity.cs ├── Properties │ ├── AndroidManifest.xml │ └── AssemblyInfo.cs ├── RenderersAndroid │ ├── BorderlessEntryRenderer.cs │ ├── PancakeDrawable.cs │ ├── PancakeViewRenderer.cs │ ├── RoundedCornerOutlineProvider.cs │ └── ShapeUtils.cs ├── Resources │ ├── AboutResources.txt │ ├── Resource.designer.cs │ ├── drawable │ │ ├── bg1.png │ │ ├── bg9.png │ │ └── logo.png │ ├── layout │ │ ├── Tabbar.xml │ │ └── Toolbar.xml │ ├── mipmap-anydpi-v26 │ │ ├── icon.xml │ │ └── icon_round.xml │ ├── mipmap-hdpi │ │ ├── icon.png │ │ ├── launcher_foreground.png │ │ └── logo.png │ ├── mipmap-mdpi │ │ ├── icon.png │ │ ├── launcher_foreground.png │ │ └── logo.png │ ├── mipmap-xhdpi │ │ ├── icon.png │ │ ├── launcher_foreground.png │ │ └── logo.png │ ├── mipmap-xxhdpi │ │ ├── icon.png │ │ ├── launcher_foreground.png │ │ └── logo.png │ ├── mipmap-xxxhdpi │ │ ├── icon.png │ │ ├── launcher_foreground.png │ │ └── logo.png │ └── values │ │ ├── colors.xml │ │ └── styles.xml └── XamUIDemo.Android.csproj ├── XamUIDemo.iOS ├── AppDelegate.cs ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-1024.png │ │ ├── Icon-120-1.png │ │ ├── Icon-120.png │ │ ├── Icon-152.png │ │ ├── Icon-167.png │ │ ├── Icon-180.png │ │ ├── Icon-20.png │ │ ├── Icon-29.png │ │ ├── Icon-40-1.png │ │ ├── Icon-40-2.png │ │ ├── Icon-40.png │ │ ├── Icon-58-1.png │ │ ├── Icon-58.png │ │ ├── Icon-60.png │ │ ├── Icon-76.png │ │ ├── Icon-80-1.png │ │ ├── Icon-80.png │ │ └── Icon-87.png ├── Entitlements.plist ├── Info.plist ├── Main.cs ├── Properties │ └── AssemblyInfo.cs ├── RenderersiOS │ ├── BorderlessEntryRenderer.cs │ ├── PancakeViewRenderer.cs │ └── ShapeUtils.cs ├── Resources │ ├── Default-568h@2x.png │ ├── Default-Portrait.png │ ├── Default-Portrait@2x.png │ ├── Default.png │ ├── Default@2x.png │ ├── LaunchScreen.storyboard │ ├── bg1.png │ ├── bg9.png │ └── logo.png └── XamUIDemo.iOS.csproj ├── XamUIDemo.sln └── XamUIDemo ├── Animations └── ViewAnimations.cs ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── LoginPages ├── LoginPage10.xaml ├── LoginPage10.xaml.cs ├── LoginPage14.xaml ├── LoginPage14.xaml.cs ├── LoginPage2.xaml └── LoginPage2.xaml.cs ├── MainPage.xaml ├── MainPage.xaml.cs ├── Renderers ├── BlurredImage.cs ├── BorderlessEntry.cs └── PancakeView.cs ├── Styles ├── BorderDrawingStyle.cs ├── GradientStop.cs └── GradientStopCollection.cs └── XamUIDemo.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Coverlet is a free, cross platform Code Coverage Tool 141 | coverage*[.json, .xml, .info] 142 | 143 | # Visual Studio code coverage results 144 | *.coverage 145 | *.coveragexml 146 | 147 | # NCrunch 148 | _NCrunch_* 149 | .*crunch*.local.xml 150 | nCrunchTemp_* 151 | 152 | # MightyMoose 153 | *.mm.* 154 | AutoTest.Net/ 155 | 156 | # Web workbench (sass) 157 | .sass-cache/ 158 | 159 | # Installshield output folder 160 | [Ee]xpress/ 161 | 162 | # DocProject is a documentation generator add-in 163 | DocProject/buildhelp/ 164 | DocProject/Help/*.HxT 165 | DocProject/Help/*.HxC 166 | DocProject/Help/*.hhc 167 | DocProject/Help/*.hhk 168 | DocProject/Help/*.hhp 169 | DocProject/Help/Html2 170 | DocProject/Help/html 171 | 172 | # Click-Once directory 173 | publish/ 174 | 175 | # Publish Web Output 176 | *.[Pp]ublish.xml 177 | *.azurePubxml 178 | # Note: Comment the next line if you want to checkin your web deploy settings, 179 | # but database connection strings (with potential passwords) will be unencrypted 180 | *.pubxml 181 | *.publishproj 182 | 183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 184 | # checkin your Azure Web App publish settings, but sensitive information contained 185 | # in these scripts will be unencrypted 186 | PublishScripts/ 187 | 188 | # NuGet Packages 189 | *.nupkg 190 | # NuGet Symbol Packages 191 | *.snupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | *.appxbundle 217 | *.appxupload 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- [Bb]ackup.rdl 268 | *- [Bb]ackup ([0-9]).rdl 269 | *- [Bb]ackup ([0-9][0-9]).rdl 270 | 271 | # Microsoft Fakes 272 | FakesAssemblies/ 273 | 274 | # GhostDoc plugin setting file 275 | *.GhostDoc.xml 276 | 277 | # Node.js Tools for Visual Studio 278 | .ntvs_analysis.dat 279 | node_modules/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/paket.exe 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # CodeRush personal settings 306 | .cr/personal 307 | 308 | # Python Tools for Visual Studio (PTVS) 309 | __pycache__/ 310 | *.pyc 311 | 312 | # Cake - Uncomment if you are using it 313 | # tools/** 314 | # !tools/packages.config 315 | 316 | # Tabs Studio 317 | *.tss 318 | 319 | # Telerik's JustMock configuration file 320 | *.jmconfig 321 | 322 | # BizTalk build output 323 | *.btp.cs 324 | *.btm.cs 325 | *.odx.cs 326 | *.xsd.cs 327 | 328 | # OpenCover UI analysis results 329 | OpenCover/ 330 | 331 | # Azure Stream Analytics local run output 332 | ASALocalRun/ 333 | 334 | # MSBuild Binary and Structured Log 335 | *.binlog 336 | 337 | # NVidia Nsight GPU debugger configuration file 338 | *.nvuser 339 | 340 | # MFractors (Xamarin productivity tool) working folder 341 | .mfractor/ 342 | 343 | # Local History for Visual Studio 344 | .localhistory/ 345 | 346 | # BeatPulse healthcheck temp database 347 | healthchecksdb 348 | 349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 350 | MigrationBackup/ 351 | 352 | # Ionide (cross platform F# VS Code tools) working folder 353 | .ionide/ 354 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ufuk 4 | 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XamLoginUIDemo 2 |

XamUI Login Page UI Kit v2 !!

3 |

Full Code

4 |

More Xamarin applications and designs

5 |

6 |

7 |

8 |

9 |

10 | 11 | 12 |

XamUI Login Page UI Kit

13 |

XamUI Login Page UI Kit 14 | It is an Android and iOS compatible Login Page design project made with Xamarin Forms. 15 | 16 | Includes 15 unique login screen designs. 17 | You can use these designs seamlessly in your applications, the design is made more functional with beautiful and clean animations. 18 |

19 |

Application Features

20 | 40 | 41 |

Want to use this Application for your business or reuse?

42 |

We think that is fantastic! Already we have several clients that are using a similar template and love the results. If you are looking to use this application for production proposes you will need to purchase an extended license. For development and testing proposes you are able to use a regular license.

43 |

What is Xamarin?

44 |

Xamarin is an open-source platform for building modern and performant applications for iOS, Android, and Windows with .NET. Xamarin is an abstraction layer that manages communication of shared code with underlying platform code. Xamarin runs in a managed environment that provides conveniences such as memory allocation and garbage collection. Xamarin enables developers to share an average of 90% of their application across platforms. This pattern allows developers to write all of their business logic in a single language (or reuse existing application code) but achieve native performance, look, and feel on each platform. Xamarin applications can be written on PC or Mac and compile into native application packages, such as an .apk file on Android , or an .ipa file on iOS. More İnformation for Xamarin

45 | 46 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Assets/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories) and given a Build Action of "AndroidAsset". 3 | 4 | These files will be deployed with your package and will be accessible using Android's 5 | AssetManager, like this: 6 | 7 | public class ReadAsset : Activity 8 | { 9 | protected override void OnCreate (Bundle bundle) 10 | { 11 | base.OnCreate (bundle); 12 | 13 | InputStream input = Assets.Open ("my_asset.txt"); 14 | } 15 | } 16 | 17 | Additionally, some Android functions will automatically load asset files: 18 | 19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); 20 | -------------------------------------------------------------------------------- /XamUIDemo.Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Content.PM; 3 | using Android.Runtime; 4 | using Android.OS; 5 | 6 | namespace XamUIDemo.Droid 7 | { 8 | [Activity(Label = "XamUIDemo", Icon = "@mipmap/logo", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] 9 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity 10 | { 11 | protected override void OnCreate(Bundle savedInstanceState) 12 | { 13 | TabLayoutResource = Resource.Layout.Tabbar; 14 | ToolbarResource = Resource.Layout.Toolbar; 15 | 16 | base.OnCreate(savedInstanceState); 17 | 18 | Xamarin.Essentials.Platform.Init(this, savedInstanceState); 19 | global::Xamarin.Forms.Forms.Init(this, savedInstanceState); 20 | LoadApplication(new App()); 21 | } 22 | public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults) 23 | { 24 | Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults); 25 | 26 | base.OnRequestPermissionsResult(requestCode, permissions, grantResults); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /XamUIDemo.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("XamUIDemo.Android")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("XamUIDemo.Android")] 14 | [assembly: AssemblyCopyright("Copyright © 2014")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | 32 | // Add some common permissions, these can be removed if not needed 33 | [assembly: UsesPermission(Android.Manifest.Permission.Internet)] 34 | [assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)] 35 | -------------------------------------------------------------------------------- /XamUIDemo.Android/RenderersAndroid/BorderlessEntryRenderer.cs: -------------------------------------------------------------------------------- 1 | using Android.Content; 2 | using Xamarin.Forms; 3 | using Xamarin.Forms.Platform.Android; 4 | using XamLoginUIDemo.Droid.RenderersAndroid; 5 | using XamUIDemo.Renderers; 6 | 7 | [assembly: ExportRenderer(typeof(BorderlessEntry), typeof(BorderlessBorderlessEntryRenderer))] 8 | namespace XamLoginUIDemo.Droid.RenderersAndroid 9 | { 10 | public class BorderlessBorderlessEntryRenderer : EntryRenderer 11 | { 12 | public BorderlessBorderlessEntryRenderer(Context context) : base(context) 13 | { 14 | } 15 | 16 | protected override void OnElementChanged(ElementChangedEventArgs e) 17 | { 18 | base.OnElementChanged(e); 19 | if (e.OldElement == null) 20 | { 21 | Control.Background = null; 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /XamUIDemo.Android/RenderersAndroid/PancakeDrawable.cs: -------------------------------------------------------------------------------- 1 | using Android.Graphics; 2 | using Android.Graphics.Drawables; 3 | using System; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using XamLoginUIDemo.Droid; 7 | using Xamarin.Forms; 8 | using ACanvas = Android.Graphics.Canvas; 9 | using Xamarin.Forms.Platform.Android; 10 | using XamUIDemo.Renderers; 11 | 12 | namespace XamUIDemo.Droid.Renderers 13 | { 14 | public class PancakeDrawable : Drawable 15 | { 16 | readonly PancakeView _pancake; 17 | readonly Func _convertToPixels; 18 | Bitmap _normalBitmap; 19 | bool _isDisposed; 20 | 21 | public override int Opacity 22 | { 23 | get { return 0; } 24 | } 25 | 26 | public PancakeDrawable(PancakeView pancake, Func convertToPixels) 27 | { 28 | _pancake = pancake; 29 | _convertToPixels = convertToPixels; 30 | _pancake.PropertyChanged += PancakeViewOnPropertyChanged; 31 | } 32 | 33 | public override void Draw(ACanvas canvas) 34 | { 35 | int width = Bounds.Width(); 36 | int height = Bounds.Height(); 37 | 38 | if (width <= 0 || height <= 0) 39 | { 40 | DisposeBitmap(); 41 | 42 | return; 43 | } 44 | 45 | try 46 | { 47 | if (_normalBitmap == null || _normalBitmap.Height != height || _normalBitmap.Width != width) 48 | { 49 | // If the user changes the orientation of the screen, make sure to destroy reference before 50 | // reassigning a new bitmap reference. 51 | DisposeBitmap(); 52 | 53 | _normalBitmap = CreateBitmap(false, width, height); 54 | } 55 | } 56 | catch (ObjectDisposedException) 57 | { 58 | // This bitmap will sometimes be disposed as ListView/CollectionView scrolling or refreshing happens, 59 | // so we re-create the bitmap again. 60 | _normalBitmap = CreateBitmap(false, width, height); 61 | } 62 | 63 | using (var paint = new Paint()) 64 | { 65 | canvas.DrawBitmap(_normalBitmap, 0, 0, paint); 66 | } 67 | } 68 | 69 | private void DisposeBitmap() 70 | { 71 | if (_normalBitmap != null) 72 | { 73 | _normalBitmap.Dispose(); 74 | _normalBitmap = null; 75 | } 76 | } 77 | 78 | public override void SetAlpha(int alpha) 79 | { 80 | } 81 | 82 | public override void SetColorFilter(ColorFilter colorFilter) 83 | { 84 | } 85 | 86 | protected override bool OnStateChange(int[] state) 87 | { 88 | return false; 89 | } 90 | 91 | Bitmap CreateBitmap(bool pressed, int width, int height) 92 | { 93 | Bitmap bitmap; 94 | 95 | using (Bitmap.Config config = Bitmap.Config.Argb8888) 96 | { 97 | bitmap = Bitmap.CreateBitmap(width, height, config); 98 | } 99 | 100 | using (var canvas = new ACanvas(bitmap)) 101 | { 102 | DrawCanvas(canvas, width, height, pressed); 103 | } 104 | 105 | return bitmap; 106 | } 107 | 108 | void DrawBackground(ACanvas canvas, int width, int height, CornerRadius cornerRadius, bool pressed) 109 | { 110 | using (var paint = new Paint { AntiAlias = true }) 111 | using (Path.Direction direction = Path.Direction.Cw) 112 | using (Paint.Style style = Paint.Style.Fill) 113 | { 114 | var path = new Path(); 115 | 116 | if (_pancake.Sides != 4) 117 | { 118 | path = ShapeUtils.CreatePolygonPath(width, height, _pancake.Sides, _pancake.CornerRadius.TopLeft, _pancake.OffsetAngle); 119 | } 120 | else 121 | { 122 | float topLeft = _convertToPixels(cornerRadius.TopLeft); 123 | float topRight = _convertToPixels(cornerRadius.TopRight); 124 | float bottomRight = _convertToPixels(cornerRadius.BottomRight); 125 | float bottomLeft = _convertToPixels(cornerRadius.BottomLeft); 126 | 127 | path = ShapeUtils.CreateRoundedRectPath(width, height, topLeft, topRight, bottomRight, bottomLeft); 128 | } 129 | 130 | if ((_pancake.BackgroundGradientStartColor != default(Xamarin.Forms.Color) && _pancake.BackgroundGradientEndColor != default(Xamarin.Forms.Color)) || (_pancake.BackgroundGradientStops != null && _pancake.BackgroundGradientStops.Any())) 131 | { 132 | var angle = _pancake.BackgroundGradientAngle / 360.0; 133 | 134 | // Calculate the new positions based on angle between 0-360. 135 | var a = width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.75) / 2)), 2); 136 | var b = height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.0) / 2)), 2); 137 | var c = width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.25) / 2)), 2); 138 | var d = height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.5) / 2)), 2); 139 | 140 | if (_pancake.BackgroundGradientStops != null && _pancake.BackgroundGradientStops.Count > 0) 141 | { 142 | // A range of colors is given. Let's add them. 143 | var orderedStops = _pancake.BackgroundGradientStops.OrderBy(x => x.Offset).ToList(); 144 | var colors = orderedStops.Select(x => x.Color.ToAndroid().ToArgb()).ToArray(); 145 | var locations = orderedStops.Select(x => x.Offset).ToArray(); 146 | 147 | var shader = new LinearGradient(width - (float)a, (float)b, width - (float)c, (float)d, colors, locations, Shader.TileMode.Clamp); 148 | paint.SetShader(shader); 149 | } 150 | else 151 | { 152 | // Only two colors provided, use that. 153 | var shader = new LinearGradient(width - (float)a, (float)b, width - (float)c, (float)d, _pancake.BackgroundGradientStartColor.ToAndroid(), _pancake.BackgroundGradientEndColor.ToAndroid(), Shader.TileMode.Clamp); 154 | paint.SetShader(shader); 155 | } 156 | } 157 | else 158 | { 159 | global::Android.Graphics.Color color = _pancake.BackgroundColor.ToAndroid(); 160 | paint.SetStyle(style); 161 | paint.Color = color; 162 | } 163 | 164 | canvas.DrawPath(path, paint); 165 | } 166 | } 167 | 168 | void PancakeViewOnPropertyChanged(object sender, PropertyChangedEventArgs e) 169 | { 170 | if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || 171 | e.PropertyName == PancakeView.CornerRadiusProperty.PropertyName || 172 | e.PropertyName == PancakeView.BackgroundGradientAngleProperty.PropertyName || 173 | e.PropertyName == PancakeView.BackgroundGradientStartColorProperty.PropertyName || 174 | e.PropertyName == PancakeView.BackgroundGradientEndColorProperty.PropertyName || 175 | e.PropertyName == PancakeView.BackgroundGradientStopsProperty.PropertyName || 176 | e.PropertyName == PancakeView.SidesProperty.PropertyName || 177 | e.PropertyName == PancakeView.OffsetAngleProperty.PropertyName) 178 | { 179 | if (_normalBitmap == null) 180 | return; 181 | 182 | using (var canvas = new ACanvas(_normalBitmap)) 183 | { 184 | int width = Bounds.Width(); 185 | int height = Bounds.Height(); 186 | canvas.DrawColor(global::Android.Graphics.Color.Black, PorterDuff.Mode.Clear); 187 | DrawCanvas(canvas, width, height, false); 188 | } 189 | 190 | InvalidateSelf(); 191 | } 192 | } 193 | 194 | void DrawCanvas(ACanvas canvas, int width, int height, bool pressed) 195 | { 196 | DrawBackground(canvas, width, height, _pancake.CornerRadius, pressed); 197 | } 198 | 199 | protected override void Dispose(bool disposing) 200 | { 201 | if (disposing && !_isDisposed) 202 | { 203 | DisposeBitmap(); 204 | 205 | if (_pancake != null) 206 | { 207 | _pancake.PropertyChanged -= PancakeViewOnPropertyChanged; 208 | } 209 | 210 | _isDisposed = true; 211 | } 212 | 213 | base.Dispose(disposing); 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /XamUIDemo.Android/RenderersAndroid/PancakeViewRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using XamUIDemo.Droid.Renderers; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using Android.Content; 6 | using Android.Graphics; 7 | using Android.OS; 8 | using Android.Support.V4.View; 9 | using Xamarin.Forms; 10 | using ACanvas = Android.Graphics.Canvas; 11 | using Xamarin.Forms.Platform.Android; 12 | using XamUIDemo.Styles; 13 | using XamUIDemo.Renderers; 14 | 15 | [assembly: ExportRenderer(typeof(PancakeView), typeof(PancakeViewRenderer))] 16 | 17 | namespace XamUIDemo.Droid.Renderers 18 | { 19 | public class PancakeViewRenderer : VisualElementRenderer 20 | { 21 | bool _disposed; 22 | private PancakeDrawable _drawable; 23 | 24 | public PancakeViewRenderer(Context context) : base(context) 25 | { 26 | } 27 | 28 | /// 29 | /// This method ensures that we don't get stripped out by the linker. 30 | /// 31 | public static void Init() 32 | { 33 | #pragma warning disable 0219 34 | var ignore1 = typeof(PancakeViewRenderer); 35 | var ignore2 = typeof(PancakeView); 36 | #pragma warning restore 0219 37 | } 38 | 39 | protected override void OnElementChanged(ElementChangedEventArgs e) 40 | { 41 | base.OnElementChanged(e); 42 | 43 | if (e.NewElement != null && e.OldElement == null) 44 | { 45 | var pancake = (Element as PancakeView); 46 | 47 | // HACK: When there are no children we add a Grid element to trigger DrawChild. 48 | // This should be improved upon, but I haven't found out a nice way to be able to clip 49 | // the children and add the border on top without using DrawChild. 50 | if (pancake.Content == null) 51 | { 52 | pancake.Content = new Grid(); 53 | } 54 | 55 | Validate(pancake); 56 | 57 | this.SetBackground(_drawable = new PancakeDrawable(pancake, Context.ToPixels)); 58 | 59 | SetupShadow(pancake); 60 | } 61 | } 62 | 63 | private void Validate(PancakeView pancake) 64 | { 65 | // Angle needs to be between 0-360. 66 | if (pancake.BackgroundGradientAngle < 0 || pancake.BackgroundGradientAngle > 360) 67 | throw new ArgumentException("Please provide a valid background gradient angle.", nameof(PancakeView.BackgroundGradientAngle)); 68 | 69 | if (pancake.OffsetAngle < 0 || pancake.OffsetAngle > 360) 70 | throw new ArgumentException("Please provide a valid offset angle.", nameof(PancakeView.OffsetAngle)); 71 | 72 | // min value for sides is 3 73 | if (pancake.Sides < 3) 74 | throw new ArgumentException("Please provide a valid value for sides.", nameof(PancakeView.Sides)); 75 | 76 | } 77 | 78 | private void SetupShadow(PancakeView pancake) 79 | { 80 | if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) 81 | { 82 | // clear previous shadow/elevation 83 | this.Elevation = 0; 84 | this.TranslationZ = 0; 85 | 86 | bool hasShadowOrElevation = pancake.HasShadow || pancake.Elevation > 0; 87 | 88 | // If it has a shadow, give it a default Droid looking shadow. 89 | if (pancake.HasShadow) 90 | { 91 | this.Elevation = 10; 92 | this.TranslationZ = 10; 93 | } 94 | 95 | // However if it has a specified elevation add the desired one 96 | if (pancake.Elevation > 0) 97 | { 98 | this.Elevation = 0; 99 | this.TranslationZ = 0; 100 | ViewCompat.SetElevation(this, Context.ToPixels(pancake.Elevation)); 101 | } 102 | 103 | if (hasShadowOrElevation) 104 | { 105 | // To have shadow show up, we need to clip. 106 | this.OutlineProvider = new RoundedCornerOutlineProvider(pancake, Context.ToPixels); 107 | this.ClipToOutline = true; 108 | } 109 | else 110 | { 111 | this.OutlineProvider = null; 112 | this.ClipToOutline = false; 113 | } 114 | } 115 | } 116 | 117 | protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) 118 | { 119 | var pancake = Element as PancakeView; 120 | Validate(pancake); 121 | 122 | base.OnElementPropertyChanged(sender, e); 123 | if (e.PropertyName == PancakeView.BorderColorProperty.PropertyName || 124 | e.PropertyName == PancakeView.BorderThicknessProperty.PropertyName || 125 | e.PropertyName == PancakeView.BorderIsDashedProperty.PropertyName || 126 | e.PropertyName == PancakeView.BorderDrawingStyleProperty.PropertyName || 127 | e.PropertyName == PancakeView.BorderGradientAngleProperty.PropertyName || 128 | e.PropertyName == PancakeView.BorderGradientEndColorProperty.PropertyName || 129 | e.PropertyName == PancakeView.BorderGradientStartColorProperty.PropertyName || 130 | e.PropertyName == PancakeView.BorderGradientStopsProperty.PropertyName) 131 | { 132 | Invalidate(); 133 | } 134 | else if (e.PropertyName == PancakeView.SidesProperty.PropertyName || 135 | e.PropertyName == PancakeView.OffsetAngleProperty.PropertyName || 136 | e.PropertyName == PancakeView.HasShadowProperty.PropertyName || 137 | e.PropertyName == PancakeView.ElevationProperty.PropertyName) 138 | { 139 | SetupShadow(pancake); 140 | } 141 | else if (e.PropertyName == PancakeView.CornerRadiusProperty.PropertyName) 142 | { 143 | Invalidate(); 144 | SetupShadow(pancake); 145 | } 146 | else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) 147 | { 148 | _drawable.Dispose(); 149 | this.SetBackground(_drawable = new PancakeDrawable(pancake, Context.ToPixels)); 150 | } 151 | } 152 | 153 | protected override void Dispose(bool disposing) 154 | { 155 | base.Dispose(disposing); 156 | 157 | if (disposing && !_disposed) 158 | { 159 | _drawable?.Dispose(); 160 | _disposed = true; 161 | } 162 | } 163 | 164 | protected override void OnDraw(ACanvas canvas) 165 | { 166 | if (Element == null) return; 167 | 168 | var control = (PancakeView)Element; 169 | 170 | SetClipChildren(true); 171 | 172 | //Create path to clip the child 173 | if (control.Sides != 4) 174 | { 175 | using (var path = ShapeUtils.CreatePolygonPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle)) 176 | { 177 | canvas.Save(); 178 | canvas.ClipPath(path); 179 | } 180 | } 181 | else 182 | { 183 | using (var path = ShapeUtils.CreateRoundedRectPath(Width, Height, 184 | Context.ToPixels(control.CornerRadius.TopLeft), 185 | Context.ToPixels(control.CornerRadius.TopRight), 186 | Context.ToPixels(control.CornerRadius.BottomRight), 187 | Context.ToPixels(control.CornerRadius.BottomLeft))) 188 | { 189 | canvas.Save(); 190 | canvas.ClipPath(path); 191 | } 192 | } 193 | 194 | DrawBorder(canvas, control); 195 | } 196 | 197 | protected override bool DrawChild(ACanvas canvas, global::Android.Views.View child, long drawingTime) 198 | { 199 | if (Element == null) return false; 200 | 201 | var control = (PancakeView)Element; 202 | 203 | SetClipChildren(true); 204 | 205 | //Create path to clip the child 206 | if (control.Sides != 4) 207 | { 208 | using (var path = ShapeUtils.CreatePolygonPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle)) 209 | { 210 | canvas.Save(); 211 | canvas.ClipPath(path); 212 | } 213 | } 214 | else 215 | { 216 | using (var path = ShapeUtils.CreateRoundedRectPath(Width, Height, 217 | Context.ToPixels(control.CornerRadius.TopLeft), 218 | Context.ToPixels(control.CornerRadius.TopRight), 219 | Context.ToPixels(control.CornerRadius.BottomRight), 220 | Context.ToPixels(control.CornerRadius.BottomLeft))) 221 | { 222 | canvas.Save(); 223 | canvas.ClipPath(path); 224 | } 225 | } 226 | 227 | // Draw the child first so that the border shows up above it. 228 | var result = base.DrawChild(canvas, child, drawingTime); 229 | canvas.Restore(); 230 | 231 | DrawBorder(canvas, control); 232 | 233 | return result; 234 | } 235 | 236 | private void DrawBorder(ACanvas canvas, PancakeView control) 237 | { 238 | if (control.BorderThickness > 0) 239 | { 240 | var borderThickness = Context.ToPixels(control.BorderThickness); 241 | var halfBorderThickness = borderThickness / 2; 242 | bool hasShadowOrElevation = control.HasShadow || (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop && control.Elevation > 0); 243 | 244 | // TODO: This doesn't look entirely right yet when using it with rounded corners. 245 | using (var paint = new Paint { AntiAlias = true }) 246 | using (Path.Direction direction = Path.Direction.Cw) 247 | using (Paint.Style style = Paint.Style.Stroke) 248 | using (var rect = new RectF(control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? -halfBorderThickness : halfBorderThickness, 249 | control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? -halfBorderThickness : halfBorderThickness, 250 | control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? canvas.Width + halfBorderThickness : canvas.Width - halfBorderThickness, 251 | control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? canvas.Height + halfBorderThickness : canvas.Height - halfBorderThickness)) 252 | { 253 | Path path = null; 254 | if (control.Sides != 4) 255 | { 256 | path = ShapeUtils.CreatePolygonPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle); 257 | } 258 | else 259 | { 260 | path = ShapeUtils.CreateRoundedRectPath(Width, Height, 261 | Context.ToPixels(control.CornerRadius.TopLeft), 262 | Context.ToPixels(control.CornerRadius.TopRight), 263 | Context.ToPixels(control.CornerRadius.BottomRight), 264 | Context.ToPixels(control.CornerRadius.BottomLeft)); 265 | } 266 | 267 | if (control.BorderIsDashed) 268 | { 269 | // dashes merge when thickness is increased 270 | // off-distance should be scaled according to thickness 271 | paint.SetPathEffect(new DashPathEffect(new float[] { 10, 5 * control.BorderThickness }, 0)); 272 | } 273 | 274 | if ((control.BorderGradientStartColor != default(Xamarin.Forms.Color) && control.BorderGradientEndColor != default(Xamarin.Forms.Color)) || (control.BorderGradientStops != null && control.BorderGradientStops.Any())) 275 | { 276 | var angle = control.BorderGradientAngle / 360.0; 277 | 278 | // Calculate the new positions based on angle between 0-360. 279 | var a = canvas.Width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.75) / 2)), 2); 280 | var b = canvas.Height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.0) / 2)), 2); 281 | var c = canvas.Width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.25) / 2)), 2); 282 | var d = canvas.Height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.5) / 2)), 2); 283 | 284 | if (control.BorderGradientStops != null && control.BorderGradientStops.Count > 0) 285 | { 286 | // A range of colors is given. Let's add them. 287 | var orderedStops = control.BorderGradientStops.OrderBy(x => x.Offset).ToList(); 288 | var colors = orderedStops.Select(x => x.Color.ToAndroid().ToArgb()).ToArray(); 289 | var locations = orderedStops.Select(x => x.Offset).ToArray(); 290 | 291 | var shader = new LinearGradient(canvas.Width - (float)a, (float)b, canvas.Width - (float)c, (float)d, colors, locations, Shader.TileMode.Clamp); 292 | paint.SetShader(shader); 293 | } 294 | else 295 | { 296 | // Only two colors provided, use that. 297 | var shader = new LinearGradient(canvas.Width - (float)a, (float)b, canvas.Width - (float)c, (float)d, control.BorderGradientStartColor.ToAndroid(), control.BorderGradientEndColor.ToAndroid(), Shader.TileMode.Clamp); 298 | paint.SetShader(shader); 299 | } 300 | } 301 | else 302 | { 303 | paint.Color = control.BorderColor.ToAndroid(); 304 | } 305 | 306 | paint.StrokeCap = Paint.Cap.Square; 307 | paint.StrokeWidth = borderThickness; 308 | paint.SetStyle(style); 309 | 310 | canvas.DrawPath(path, paint); 311 | } 312 | } 313 | } 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /XamUIDemo.Android/RenderersAndroid/RoundedCornerOutlineProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Android.Graphics; 3 | using Android.Views; 4 | using XamUIDemo.Renderers; 5 | namespace XamUIDemo.Droid.Renderers 6 | { 7 | public class RoundedCornerOutlineProvider : ViewOutlineProvider 8 | { 9 | private readonly PancakeView _pancake; 10 | private readonly Func _convertToPixels; 11 | 12 | public RoundedCornerOutlineProvider(PancakeView pancake, Func convertToPixels) 13 | { 14 | _pancake = pancake; 15 | _convertToPixels = convertToPixels; 16 | } 17 | 18 | public override void GetOutline(global::Android.Views.View view, Outline outline) 19 | { 20 | if (_pancake.Sides != 4) 21 | { 22 | var hexPath = XamUIDemo.Droid.Renderers.ShapeUtils.CreatePolygonPath(view.Width, view.Height, _pancake.Sides, _pancake.HasShadow ? 0 : _pancake.CornerRadius.TopLeft, _pancake.OffsetAngle); 23 | 24 | if (hexPath.IsConvex) 25 | { 26 | outline.SetConvexPath(hexPath); 27 | } 28 | } 29 | else 30 | { 31 | var path = ShapeUtils.CreateRoundedRectPath(view.Width, view.Height, 32 | _convertToPixels(_pancake.CornerRadius.TopLeft), 33 | _convertToPixels(_pancake.CornerRadius.TopRight), 34 | _convertToPixels(_pancake.CornerRadius.BottomRight), 35 | _convertToPixels(_pancake.CornerRadius.BottomLeft)); 36 | 37 | if (path.IsConvex) 38 | { 39 | outline.SetConvexPath(path); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /XamUIDemo.Android/RenderersAndroid/ShapeUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Android.Graphics; 3 | namespace XamUIDemo.Droid.Renderers 4 | { 5 | public static class ShapeUtils 6 | { 7 | public static Path CreateRoundedRectPath(float rectWidth, float rectHeight, float topLeft, float topRight, float bottomRight, float bottomLeft) 8 | { 9 | var path = new Path(); 10 | var radii = new[] { topLeft, topLeft, 11 | topRight, topRight, 12 | bottomRight, bottomRight, 13 | bottomLeft, bottomLeft }; 14 | 15 | 16 | path.AddRoundRect(new RectF(0, 0, rectWidth, rectHeight), radii, Path.Direction.Ccw); 17 | path.Close(); 18 | 19 | return path; 20 | } 21 | 22 | public static Path CreatePolygonPath(double rectWidth, double rectHeight, int sides, double cornerRadius = 0.0, double rotationOffset = 0.0) 23 | { 24 | var offsetRadians = rotationOffset * Math.PI / 180; 25 | 26 | var path = new Path(); 27 | var theta = 2 * Math.PI / sides; 28 | 29 | // depends on the rotation 30 | var width = (-cornerRadius + Math.Min(rectWidth, rectHeight)) / 2; 31 | var center = new Point(rectWidth / 2, rectHeight / 2); 32 | 33 | var radius = width + cornerRadius - (Math.Cos(theta) * cornerRadius) / 2; 34 | 35 | var angle = offsetRadians; 36 | var corner = new Point(center.X + (radius - cornerRadius) * Math.Cos(angle), center.Y + (radius - cornerRadius) * Math.Sin(angle)); 37 | path.MoveTo((float)(corner.X + cornerRadius * Math.Cos(angle + theta)), (float)(corner.Y + cornerRadius * Math.Sin(angle + theta))); 38 | 39 | for (var i = 0; i < sides; i++) 40 | { 41 | angle += theta; 42 | corner = new Point(center.X + (radius - cornerRadius) * Math.Cos(angle), center.Y + (radius - cornerRadius) * Math.Sin(angle)); 43 | var tip = new Point(center.X + radius * Math.Cos(angle), center.Y + radius * Math.Sin(angle)); 44 | var start = new Point(corner.X + cornerRadius * Math.Cos(angle - theta), corner.Y + cornerRadius * Math.Sin(angle - theta)); 45 | var end = new Point(corner.X + cornerRadius * Math.Cos(angle + theta), corner.Y + cornerRadius * Math.Sin(angle + theta)); 46 | 47 | path.LineTo(start.X, start.Y); 48 | path.QuadTo(tip.X, tip.Y, end.X, end.Y); 49 | } 50 | 51 | path.Close(); 52 | 53 | return path; 54 | } 55 | 56 | public class Point 57 | { 58 | public float X { get; set; } 59 | public float Y { get; set; } 60 | public Point(double X, double Y) 61 | { 62 | this.X = (float)X; 63 | this.Y = (float)Y; 64 | } 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/AboutResources.txt: -------------------------------------------------------------------------------- 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 2 | in your application as resource files. Various Android APIs are designed to 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 4 | directly. 5 | 6 | For example, a sample Android app that contains a user interface layout (main.xml), 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 8 | would keep its resources in the "Resources" directory of the application: 9 | 10 | Resources/ 11 | drawable-hdpi/ 12 | icon.png 13 | 14 | drawable-ldpi/ 15 | icon.png 16 | 17 | drawable-mdpi/ 18 | icon.png 19 | 20 | layout/ 21 | main.xml 22 | 23 | values/ 24 | strings.xml 25 | 26 | In order to get the build system to recognize Android resources, set the build action to 27 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 28 | instead operate on resource IDs. When you compile an Android application that uses resources, 29 | the build system will package the resources for distribution and generate a class called 30 | "Resource" that contains the tokens for each one of the resources included. For example, 31 | for the above Resources layout, this is what the Resource class would expose: 32 | 33 | public class Resource { 34 | public class drawable { 35 | public const int icon = 0x123; 36 | } 37 | 38 | public class layout { 39 | public const int main = 0x456; 40 | } 41 | 42 | public class strings { 43 | public const int first_string = 0xabc; 44 | public const int second_string = 0xbcd; 45 | } 46 | } 47 | 48 | You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main 49 | to reference the layout/main.xml file, or Resource.strings.first_string to reference the first 50 | string in the dictionary file values/strings.xml. 51 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/drawable/bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/drawable/bg1.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/drawable/bg9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/drawable/bg9.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/drawable/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/drawable/logo.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/layout/Tabbar.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/layout/Toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-anydpi-v26/icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-anydpi-v26/icon_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-hdpi/icon.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-hdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-hdpi/launcher_foreground.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-hdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-hdpi/logo.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-mdpi/icon.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-mdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-mdpi/launcher_foreground.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-mdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-mdpi/logo.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xhdpi/icon.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xhdpi/logo.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xxhdpi/icon.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xxhdpi/logo.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xxxhdpi/icon.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/mipmap-xxxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.Android/Resources/mipmap-xxxhdpi/logo.png -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #3F51B5 5 | #303F9F 6 | #FF4081 7 | -------------------------------------------------------------------------------- /XamUIDemo.Android/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 24 | 27 | -------------------------------------------------------------------------------- /XamUIDemo.Android/XamUIDemo.Android.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {B085165E-2B8E-4CA4-865A-74CC0C38622C} 7 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | {c9e5eea5-ca05-42a1-839b-61506e0a37df} 9 | Library 10 | XamUIDemo.Droid 11 | XamUIDemo.Android 12 | True 13 | Resources\Resource.designer.cs 14 | Resource 15 | Properties\AndroidManifest.xml 16 | Resources 17 | Assets 18 | v9.0 19 | true 20 | true 21 | Xamarin.Android.Net.AndroidClientHandler 22 | 23 | 24 | 25 | 26 | true 27 | portable 28 | false 29 | bin\Debug 30 | DEBUG; 31 | prompt 32 | 4 33 | None 34 | 35 | 36 | true 37 | portable 38 | true 39 | bin\Release 40 | prompt 41 | 4 42 | true 43 | false 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 | {1A72F333-4921-403E-B8D5-541D49EFBA28} 130 | XamUIDemo 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace XamUIDemo.iOS 9 | { 10 | // The UIApplicationDelegate for the application. This class is responsible for launching the 11 | // User Interface of the application, as well as listening (and optionally responding) to 12 | // application events from iOS. 13 | [Register("AppDelegate")] 14 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate 15 | { 16 | // 17 | // This method is invoked when the application has loaded and is ready to run. In this 18 | // method you should instantiate the window, load the UI into it and then make the window 19 | // visible. 20 | // 21 | // You have 17 seconds to return from this method, or iOS will terminate your application. 22 | // 23 | public override bool FinishedLaunching(UIApplication app, NSDictionary options) 24 | { 25 | global::Xamarin.Forms.Forms.Init(); 26 | LoadApplication(new App()); 27 | 28 | return base.FinishedLaunching(app, options); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "filename": "Icon-40.png", 5 | "size": "20x20", 6 | "scale": "2x", 7 | "idiom": "iphone" 8 | }, 9 | { 10 | "filename": "Icon-60.png", 11 | "size": "20x20", 12 | "scale": "3x", 13 | "idiom": "iphone" 14 | }, 15 | { 16 | "filename": "Icon-58.png", 17 | "size": "29x29", 18 | "scale": "2x", 19 | "idiom": "iphone" 20 | }, 21 | { 22 | "filename": "Icon-87.png", 23 | "size": "29x29", 24 | "scale": "3x", 25 | "idiom": "iphone" 26 | }, 27 | { 28 | "filename": "Icon-80.png", 29 | "size": "40x40", 30 | "scale": "2x", 31 | "idiom": "iphone" 32 | }, 33 | { 34 | "filename": "Icon-120.png", 35 | "size": "40x40", 36 | "scale": "3x", 37 | "idiom": "iphone" 38 | }, 39 | { 40 | "filename": "Icon-120-1.png", 41 | "size": "60x60", 42 | "scale": "2x", 43 | "idiom": "iphone" 44 | }, 45 | { 46 | "filename": "Icon-180.png", 47 | "size": "60x60", 48 | "scale": "3x", 49 | "idiom": "iphone" 50 | }, 51 | { 52 | "filename": "Icon-20.png", 53 | "size": "20x20", 54 | "scale": "1x", 55 | "idiom": "ipad" 56 | }, 57 | { 58 | "filename": "Icon-40-1.png", 59 | "size": "20x20", 60 | "scale": "2x", 61 | "idiom": "ipad" 62 | }, 63 | { 64 | "filename": "Icon-29.png", 65 | "size": "29x29", 66 | "scale": "1x", 67 | "idiom": "ipad" 68 | }, 69 | { 70 | "filename": "Icon-58-1.png", 71 | "size": "29x29", 72 | "scale": "2x", 73 | "idiom": "ipad" 74 | }, 75 | { 76 | "filename": "Icon-40-2.png", 77 | "size": "40x40", 78 | "scale": "1x", 79 | "idiom": "ipad" 80 | }, 81 | { 82 | "filename": "Icon-80-1.png", 83 | "size": "40x40", 84 | "scale": "2x", 85 | "idiom": "ipad" 86 | }, 87 | { 88 | "filename": "Icon-167.png", 89 | "size": "83.5x83.5", 90 | "scale": "2x", 91 | "idiom": "ipad" 92 | }, 93 | { 94 | "filename": "Icon-76.png", 95 | "size": "76x76", 96 | "scale": "1x", 97 | "idiom": "ipad" 98 | }, 99 | { 100 | "filename": "Icon-152.png", 101 | "size": "76x76", 102 | "scale": "2x", 103 | "idiom": "ipad" 104 | }, 105 | { 106 | "filename": "Icon-1024.png", 107 | "size": "1024x1024", 108 | "scale": "1x", 109 | "idiom": "ios-marketing" 110 | }, 111 | { 112 | "size": "60x60", 113 | "scale": "2x", 114 | "idiom": "car" 115 | }, 116 | { 117 | "size": "60x60", 118 | "scale": "3x", 119 | "idiom": "car" 120 | }, 121 | { 122 | "role": "notificationCenter", 123 | "size": "24x24", 124 | "subtype": "38mm", 125 | "scale": "2x", 126 | "idiom": "watch" 127 | }, 128 | { 129 | "role": "notificationCenter", 130 | "size": "27.5x27.5", 131 | "subtype": "42mm", 132 | "scale": "2x", 133 | "idiom": "watch" 134 | }, 135 | { 136 | "role": "companionSettings", 137 | "size": "29x29", 138 | "scale": "2x", 139 | "idiom": "watch" 140 | }, 141 | { 142 | "role": "companionSettings", 143 | "size": "29x29", 144 | "scale": "3x", 145 | "idiom": "watch" 146 | }, 147 | { 148 | "role": "appLauncher", 149 | "size": "40x40", 150 | "subtype": "38mm", 151 | "scale": "2x", 152 | "idiom": "watch" 153 | }, 154 | { 155 | "role": "appLauncher", 156 | "size": "44x44", 157 | "subtype": "40mm", 158 | "scale": "2x", 159 | "idiom": "watch" 160 | }, 161 | { 162 | "role": "appLauncher", 163 | "size": "50x50", 164 | "subtype": "44mm", 165 | "scale": "2x", 166 | "idiom": "watch" 167 | }, 168 | { 169 | "role": "quickLook", 170 | "size": "86x86", 171 | "subtype": "38mm", 172 | "scale": "2x", 173 | "idiom": "watch" 174 | }, 175 | { 176 | "role": "quickLook", 177 | "size": "98x98", 178 | "subtype": "42mm", 179 | "scale": "2x", 180 | "idiom": "watch" 181 | }, 182 | { 183 | "role": "quickLook", 184 | "size": "108x108", 185 | "subtype": "44mm", 186 | "scale": "2x", 187 | "idiom": "watch" 188 | }, 189 | { 190 | "size": "1024x1024", 191 | "scale": "1x", 192 | "idiom": "watch-marketing" 193 | }, 194 | { 195 | "size": "16x16", 196 | "scale": "1x", 197 | "idiom": "mac" 198 | }, 199 | { 200 | "size": "16x16", 201 | "scale": "2x", 202 | "idiom": "mac" 203 | }, 204 | { 205 | "size": "32x32", 206 | "scale": "1x", 207 | "idiom": "mac" 208 | }, 209 | { 210 | "size": "32x32", 211 | "scale": "2x", 212 | "idiom": "mac" 213 | }, 214 | { 215 | "size": "128x128", 216 | "scale": "1x", 217 | "idiom": "mac" 218 | }, 219 | { 220 | "size": "128x128", 221 | "scale": "2x", 222 | "idiom": "mac" 223 | }, 224 | { 225 | "size": "256x256", 226 | "scale": "1x", 227 | "idiom": "mac" 228 | }, 229 | { 230 | "size": "256x256", 231 | "scale": "2x", 232 | "idiom": "mac" 233 | }, 234 | { 235 | "size": "512x512", 236 | "scale": "1x", 237 | "idiom": "mac" 238 | }, 239 | { 240 | "size": "512x512", 241 | "scale": "2x", 242 | "idiom": "mac" 243 | } 244 | ], 245 | "info": { 246 | "version": 1, 247 | "author": "xcode" 248 | } 249 | } -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-1024.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-120-1.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-120.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-152.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-167.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-180.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-20.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-29.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-40-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-40-1.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-40-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-40-2.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-58-1.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-58.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-60.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-80-1.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-80.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Assets.xcassets/AppIcon.appiconset/Icon-87.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDeviceFamily 6 | 7 | 1 8 | 2 9 | 10 | UISupportedInterfaceOrientations 11 | 12 | UIInterfaceOrientationPortrait 13 | UIInterfaceOrientationLandscapeLeft 14 | UIInterfaceOrientationLandscapeRight 15 | 16 | UISupportedInterfaceOrientations~ipad 17 | 18 | UIInterfaceOrientationPortrait 19 | UIInterfaceOrientationPortraitUpsideDown 20 | UIInterfaceOrientationLandscapeLeft 21 | UIInterfaceOrientationLandscapeRight 22 | 23 | MinimumOSVersion 24 | 8.0 25 | CFBundleDisplayName 26 | XamUIDemo 27 | CFBundleIdentifier 28 | com.XamDesign.XamUIDemo 29 | CFBundleVersion 30 | 1.0 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | CFBundleName 34 | XamUIDemo 35 | XSAppIconAssets 36 | Assets.xcassets/AppIcon.appiconset 37 | 38 | 39 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace XamUIDemo.iOS 9 | { 10 | public class Application 11 | { 12 | // This is the main entry point of the application. 13 | static void Main(string[] args) 14 | { 15 | // if you want to use a different Application Delegate class from "AppDelegate" 16 | // you can specify it here. 17 | UIApplication.Main(args, null, "AppDelegate"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("XamUIDemo.iOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("XamUIDemo.iOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/RenderersiOS/BorderlessEntryRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using UIKit; 3 | using Xamarin.Forms; 4 | using Xamarin.Forms.Platform.iOS; 5 | using XamUIDemo.iOS.RenderersiOS; 6 | using XamUIDemo.Renderers; 7 | 8 | [assembly: ExportRenderer(typeof(BorderlessEntry), typeof(BorderlessBorderlessEntryRenderer))] 9 | 10 | namespace XamUIDemo.iOS.RenderersiOS 11 | { 12 | public class BorderlessBorderlessEntryRenderer : EntryRenderer 13 | { 14 | protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) 15 | { 16 | base.OnElementPropertyChanged(sender, e); 17 | if (Control == null) return; 18 | Control.Layer.BorderWidth = 0; 19 | Control.BorderStyle = UITextBorderStyle.None; 20 | 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /XamUIDemo.iOS/RenderersiOS/PancakeViewRenderer.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Linq; 6 | using CoreAnimation; 7 | using CoreGraphics; 8 | using XamUIDemo.iOS.Rednerers; 9 | 10 | using Foundation; 11 | using UIKit; 12 | using Xamarin.Forms; 13 | using Xamarin.Forms.Platform.iOS; 14 | using XamUIDemo.Renderers; 15 | 16 | [assembly: ExportRenderer(typeof(PancakeView), typeof(PancakeViewRenderer))] 17 | 18 | namespace XamUIDemo.iOS.Rednerers 19 | { 20 | public class PancakeViewRenderer : ViewRenderer 21 | { 22 | private UIView _actualView; 23 | private UIView _wrapperView; 24 | 25 | private UIColor _colorToRender; 26 | private CGSize _previousSize; 27 | private nfloat _topLeft; 28 | private nfloat _topRight; 29 | private nfloat _bottomLeft; 30 | private nfloat _bottomRight; 31 | 32 | /// 33 | /// This method ensures that we don't get stripped out by the linker. 34 | /// 35 | public static new void Init() 36 | { 37 | #pragma warning disable 0219 38 | var ignore1 = typeof(PancakeViewRenderer); 39 | var ignore2 = typeof(PancakeView); 40 | #pragma warning restore 0219 41 | } 42 | 43 | protected override void OnElementChanged(ElementChangedEventArgs e) 44 | { 45 | base.OnElementChanged(e); 46 | 47 | if (e.NewElement != null) 48 | { 49 | Validate(Element as PancakeView); 50 | 51 | _actualView = new UIView(); 52 | _wrapperView = new UIView(); 53 | 54 | 55 | 56 | foreach (var item in NativeView.Subviews) 57 | { 58 | _actualView.AddSubview(item); 59 | } 60 | 61 | if (NativeView.GestureRecognizers != null) 62 | { 63 | foreach (var gesture in NativeView.GestureRecognizers) 64 | { 65 | _actualView.AddGestureRecognizer(gesture); 66 | } 67 | } 68 | 69 | if (Element.Handle == IntPtr.Zero) 70 | { 71 | 72 | Element.Handle = _actualView.Handle; 73 | 74 | _wrapperView.AddSubview(_actualView); 75 | 76 | SetNativeControl(_wrapperView); 77 | 78 | SetBackgroundColor(Element.BackgroundColor); 79 | SetCornerRadius(); 80 | } 81 | } 82 | } 83 | 84 | protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) 85 | { 86 | base.OnElementPropertyChanged(sender, e); 87 | 88 | Validate(Element as PancakeView); 89 | 90 | if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) 91 | { 92 | SetBackgroundColor(Element.BackgroundColor); 93 | } 94 | else if (e.PropertyName == BoxView.CornerRadiusProperty.PropertyName) 95 | { 96 | SetCornerRadius(); 97 | } 98 | else if ((e.PropertyName == PancakeView.BorderColorProperty.PropertyName) || 99 | (e.PropertyName == PancakeView.BorderDrawingStyleProperty.PropertyName) || 100 | (e.PropertyName == PancakeView.BorderGradientAngleProperty.PropertyName) || 101 | (e.PropertyName == PancakeView.BorderGradientEndColorProperty.PropertyName) || 102 | (e.PropertyName == PancakeView.BorderGradientStartColorProperty.PropertyName) || 103 | (e.PropertyName == PancakeView.BorderGradientStopsProperty.PropertyName) || 104 | (e.PropertyName == PancakeView.BorderIsDashedProperty.PropertyName) || 105 | (e.PropertyName == PancakeView.BorderThicknessProperty.PropertyName)) 106 | { 107 | DrawBorder(); 108 | } 109 | else if ((e.PropertyName == PancakeView.BackgroundGradientStartColorProperty.PropertyName) || 110 | (e.PropertyName == PancakeView.BackgroundGradientEndColorProperty.PropertyName) || 111 | (e.PropertyName == PancakeView.BackgroundGradientAngleProperty.PropertyName) || 112 | (e.PropertyName == PancakeView.BackgroundGradientStopsProperty.PropertyName) || 113 | (e.PropertyName == VisualElement.IsVisibleProperty.PropertyName && Element.IsVisible) || 114 | (e.PropertyName == PancakeView.OffsetAngleProperty.PropertyName) || 115 | (e.PropertyName == PancakeView.HasShadowProperty.PropertyName) || 116 | (e.PropertyName == PancakeView.ElevationProperty.PropertyName) || 117 | (e.PropertyName == PancakeView.SidesProperty.PropertyName)) 118 | { 119 | SetNeedsDisplay(); 120 | } 121 | } 122 | 123 | private void Validate(PancakeView pancake) 124 | { 125 | // Angle needs to be between 0-360. 126 | if (pancake.BackgroundGradientAngle < 0 || pancake.BackgroundGradientAngle > 360) 127 | throw new ArgumentException("Please provide a valid background gradient angle.", nameof(PancakeView.BackgroundGradientAngle)); 128 | 129 | if (pancake.OffsetAngle < 0 || pancake.OffsetAngle > 360) 130 | throw new ArgumentException("Please provide a valid offset angle.", nameof(PancakeView.OffsetAngle)); 131 | 132 | // min value for sides is 3 133 | if (pancake.Sides < 3) 134 | throw new ArgumentException("Please provide a valid value for sides.", nameof(PancakeView.Sides)); 135 | } 136 | 137 | public override void LayoutSubviews() 138 | { 139 | if (_previousSize != Bounds.Size) 140 | SetNeedsDisplay(); 141 | 142 | base.LayoutSubviews(); 143 | } 144 | 145 | public override void Draw(CGRect rect) 146 | { 147 | _actualView.Frame = Bounds; 148 | _wrapperView.Frame = Bounds; 149 | 150 | DrawBackground(); 151 | DrawShadow(); 152 | DrawBorder(); 153 | 154 | base.Draw(rect); 155 | 156 | _previousSize = Bounds.Size; 157 | } 158 | 159 | private void SetCornerRadius() 160 | { 161 | if (Element == null) 162 | return; 163 | 164 | var elementCornerRadius = (Element as PancakeView).CornerRadius; 165 | 166 | _topLeft = (float)elementCornerRadius.TopLeft; 167 | _topRight = (float)elementCornerRadius.TopRight; 168 | _bottomLeft = (float)elementCornerRadius.BottomLeft; 169 | _bottomRight = (float)elementCornerRadius.BottomRight; 170 | 171 | SetNeedsDisplay(); 172 | } 173 | 174 | protected override void SetBackgroundColor(Xamarin.Forms.Color color) 175 | { 176 | if (Element == null) 177 | return; 178 | 179 | var elementColor = Element.BackgroundColor; 180 | 181 | if (!elementColor.IsDefault) 182 | _colorToRender = elementColor.ToUIColor(); 183 | else 184 | _colorToRender = color.ToUIColor(); 185 | 186 | SetNeedsDisplay(); 187 | } 188 | 189 | private void DrawBackground() 190 | { 191 | var pancake = Element as PancakeView; 192 | var layerName = "backgroundLayer"; 193 | 194 | // Remove previous background layer if any 195 | var prevBackgroundLayer = _actualView.Layer.Sublayers?.FirstOrDefault(x => x.Name == layerName); 196 | prevBackgroundLayer?.RemoveFromSuperLayer(); 197 | 198 | UIBezierPath cornerPath = null; 199 | 200 | if (pancake.Sides != 4) 201 | { 202 | cornerPath = ShapeUtils.CreatePolygonPath(Bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle); 203 | } 204 | else 205 | { 206 | cornerPath = ShapeUtils.CreateRoundedRectPath(Bounds, pancake.CornerRadius); 207 | } 208 | 209 | // The layer used to mask other layers we draw on the background. 210 | var maskLayer = new CAShapeLayer 211 | { 212 | Frame = Bounds, 213 | Path = cornerPath.CGPath 214 | }; 215 | 216 | _actualView.Layer.Mask = maskLayer; 217 | _actualView.Layer.MasksToBounds = true; 218 | 219 | if ((pancake.BackgroundGradientStartColor != default(Xamarin.Forms.Color) && pancake.BackgroundGradientEndColor != default(Xamarin.Forms.Color)) || (pancake.BackgroundGradientStops != null && pancake.BackgroundGradientStops.Any())) 220 | { 221 | // Create a gradient layer that draws our background. 222 | var gradientLayer = CreateGradientLayer(pancake.BackgroundGradientAngle, Bounds); 223 | gradientLayer.Name = layerName; 224 | 225 | if (pancake.BackgroundGradientStops != null && pancake.BackgroundGradientStops.Count > 0) 226 | { 227 | // A range of colors is given. Let's add them. 228 | var orderedStops = pancake.BackgroundGradientStops.OrderBy(x => x.Offset).ToList(); 229 | gradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray(); 230 | gradientLayer.Locations = orderedStops.Select(x => new NSNumber(x.Offset)).ToArray(); 231 | } 232 | else 233 | { 234 | // Only two colors provided, use that. 235 | gradientLayer.Colors = new CGColor[] { pancake.BackgroundGradientStartColor.ToCGColor(), pancake.BackgroundGradientEndColor.ToCGColor() }; 236 | } 237 | 238 | AddLayer(gradientLayer, 0, _actualView); 239 | } 240 | else 241 | { 242 | // Create a shape layer that draws our background. 243 | var shapeLayer = new CAShapeLayer 244 | { 245 | Frame = Bounds, 246 | Path = cornerPath.CGPath, 247 | MasksToBounds = true, 248 | FillColor = _colorToRender.CGColor, 249 | Name = layerName 250 | }; 251 | 252 | AddLayer(shapeLayer, 0, _actualView); 253 | } 254 | } 255 | 256 | private void DrawBorder() 257 | { 258 | var pancake = Element as PancakeView; 259 | var layerName = "borderLayer"; 260 | 261 | // remove previous background layer if any 262 | var prevBorderLayer = _wrapperView.Layer.Sublayers?.FirstOrDefault(x => x.Name == layerName); 263 | prevBorderLayer?.RemoveFromSuperLayer(); 264 | 265 | if (pancake.BorderThickness > 0) 266 | { 267 | var borderLayer = new CAShapeLayer 268 | { 269 | StrokeColor = pancake.BorderColor == Xamarin.Forms.Color.Default ? UIColor.Clear.CGColor : pancake.BorderColor.ToCGColor(), 270 | FillColor = null, 271 | LineWidth = pancake.BorderThickness, 272 | Name = layerName 273 | }; 274 | 275 | // Create arcs for the given corner radius. 276 | bool hasShadowOrElevation = pancake.HasShadow || pancake.Elevation > 0; 277 | 278 | borderLayer.Path = pancake.Sides != 4 ? 279 | ShapeUtils.CreatePolygonPath(Bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle).CGPath : 280 | ShapeUtils.CreateRoundedRectPath(Bounds, pancake.CornerRadius).CGPath; // insetBounds? 281 | 282 | var layerPosition = new CGPoint(borderLayer.Path.BoundingBox.Width / 2, borderLayer.Path.BoundingBox.Height / 2); 283 | 284 | borderLayer.Frame = borderLayer.Path.BoundingBox; 285 | borderLayer.Position = layerPosition; 286 | 287 | // Dash pattern for the border. 288 | if (pancake.BorderIsDashed) 289 | { 290 | borderLayer.LineDashPattern = new NSNumber[] { new NSNumber(6), new NSNumber(3) }; 291 | } 292 | 293 | if ((pancake.BorderGradientStartColor != default(Xamarin.Forms.Color) && pancake.BorderGradientEndColor != default(Xamarin.Forms.Color)) || (pancake.BorderGradientStops != null && pancake.BorderGradientStops.Any())) 294 | { 295 | var gradientFrame = Bounds.Inset(-pancake.BorderThickness, -pancake.BorderThickness); 296 | var gradientLayer = CreateGradientLayer(pancake.BorderGradientAngle, gradientFrame); 297 | gradientLayer.Position = new CGPoint((gradientFrame.Width / 2) - (pancake.BorderThickness), (gradientFrame.Height / 2) - (pancake.BorderThickness)); 298 | 299 | // Create a clone from the border layer and use that one as the mask. 300 | // Why? Because the mask and the border somehow can't be the same, so 301 | // don't want to do adjustments to borderLayer because it would influence the border. 302 | var maskLayer = new CAShapeLayer() 303 | { 304 | Path = borderLayer.Path, 305 | Position = new CGPoint(pancake.BorderThickness, pancake.BorderThickness), 306 | FillColor = null, 307 | LineWidth = pancake.BorderThickness, 308 | StrokeColor = UIColor.Red.CGColor, 309 | LineDashPattern = borderLayer.LineDashPattern 310 | }; 311 | 312 | gradientLayer.Mask = maskLayer; 313 | gradientLayer.Name = layerName; 314 | 315 | if (pancake.BorderGradientStops != null && pancake.BorderGradientStops.Count > 0) 316 | { 317 | // A range of colors is given. Let's add them. 318 | var orderedStops = pancake.BorderGradientStops.OrderBy(x => x.Offset).ToList(); 319 | gradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray(); 320 | gradientLayer.Locations = orderedStops.Select(x => new NSNumber(x.Offset)).ToArray(); 321 | } 322 | else 323 | { 324 | // Only two colors provided, use that. 325 | gradientLayer.Colors = new CGColor[] { pancake.BorderGradientStartColor.ToCGColor(), pancake.BorderGradientEndColor.ToCGColor() }; 326 | } 327 | 328 | AddLayer(gradientLayer, -1, _wrapperView); 329 | } 330 | else 331 | { 332 | AddLayer(borderLayer, -1, _wrapperView); 333 | } 334 | } 335 | } 336 | 337 | private void DrawShadow() 338 | { 339 | var pancake = Element; 340 | 341 | bool hasShadowOrElevation = pancake.HasShadow || pancake.Elevation > 0; 342 | nfloat cornerRadius = (nfloat)pancake.CornerRadius.TopLeft; 343 | 344 | if (pancake.HasShadow) 345 | { 346 | DrawDefaultShadow(_wrapperView.Layer, Bounds, cornerRadius); 347 | } 348 | 349 | if (pancake.Elevation > 0) 350 | { 351 | DrawElevation(_wrapperView.Layer, pancake.Elevation, Bounds, cornerRadius); 352 | } 353 | 354 | if (hasShadowOrElevation) 355 | { 356 | // _actualView.Layer.CornerRadius = (nfloat)pancake.CornerRadius.TopLeft; 357 | _actualView.ClipsToBounds = true; 358 | } 359 | else 360 | { 361 | _wrapperView.Layer.ShadowOpacity = 0; 362 | } 363 | 364 | // Set the rasterization for performance optimization. 365 | _wrapperView.Layer.RasterizationScale = UIScreen.MainScreen.Scale; 366 | _wrapperView.Layer.ShouldRasterize = true; 367 | 368 | _actualView.Layer.RasterizationScale = UIScreen.MainScreen.Scale; 369 | _actualView.Layer.ShouldRasterize = true; 370 | } 371 | 372 | private void DrawDefaultShadow(CALayer layer, CGRect bounds, nfloat cornerRadius) 373 | { 374 | var pancake = Element as PancakeView; 375 | 376 | // Ideally we want to be able to have individual corner radii + shadows 377 | // However, on iOS we can only do one radius + shadow. 378 | layer.CornerRadius = cornerRadius; 379 | layer.ShadowRadius = 10; 380 | layer.ShadowColor = UIColor.Black.CGColor; 381 | layer.ShadowOpacity = 0.4f; 382 | layer.ShadowOffset = new SizeF(); 383 | 384 | if (pancake.Sides != 4) 385 | { 386 | layer.ShadowPath = ShapeUtils.CreatePolygonPath(bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle).CGPath; 387 | } 388 | else 389 | { 390 | layer.ShadowPath = ShapeUtils.CreateRoundedRectPath(bounds, pancake.CornerRadius).CGPath; 391 | } 392 | } 393 | 394 | private void DrawElevation(CALayer layer, int elevation, CGRect bounds, nfloat cornerRadius) 395 | { 396 | // Source: https://medium.com/material-design-for-ios/part-1-elevation-e48ff795c693 397 | var pancake = Element as PancakeView; 398 | 399 | layer.CornerRadius = cornerRadius; 400 | layer.ShadowRadius = elevation; 401 | layer.ShadowColor = UIColor.Black.CGColor; 402 | layer.ShadowOpacity = 0.24f; 403 | layer.ShadowOffset = new CGSize(0, elevation); 404 | 405 | if (pancake.Sides != 4) 406 | { 407 | layer.ShadowPath = ShapeUtils.CreatePolygonPath(bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle).CGPath; 408 | } 409 | else 410 | { 411 | layer.ShadowPath = ShapeUtils.CreateRoundedRectPath(bounds, pancake.CornerRadius).CGPath; 412 | } 413 | 414 | layer.MasksToBounds = false; 415 | } 416 | 417 | private CAGradientLayer CreateGradientLayer(int angle, CGRect rect) 418 | { 419 | var totalAngle = angle / 360.0; 420 | 421 | // Calculate the new positions based on angle between 0-360. 422 | var a = Math.Pow(Math.Sin(2 * Math.PI * ((totalAngle + 0.75) / 2)), 2); 423 | var b = Math.Pow(Math.Sin(2 * Math.PI * ((totalAngle + 0.0) / 2)), 2); 424 | var c = Math.Pow(Math.Sin(2 * Math.PI * ((totalAngle + 0.25) / 2)), 2); 425 | var d = Math.Pow(Math.Sin(2 * Math.PI * ((totalAngle + 0.5) / 2)), 2); 426 | 427 | // Create a gradient layer that draws our background. 428 | return new CAGradientLayer 429 | { 430 | Frame = rect, 431 | StartPoint = new CGPoint(1 - a, b), 432 | EndPoint = new CGPoint(1 - c, d) 433 | }; 434 | } 435 | 436 | public void AddLayer(CALayer layer, int position, UIView viewToAddTo) 437 | { 438 | // If there is already a layer with the given name, remove it before inserting. 439 | if (layer != null) 440 | { 441 | // There's no background layer yet, insert it. 442 | if (position > -1) 443 | viewToAddTo.Layer.InsertSublayer(layer, position); 444 | else 445 | viewToAddTo.Layer.AddSublayer(layer); 446 | } 447 | } 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/RenderersiOS/ShapeUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CoreGraphics; 3 | using UIKit; 4 | using Xamarin.Forms; 5 | 6 | namespace XamUIDemo.iOS.Rednerers 7 | { 8 | public static class ShapeUtils 9 | { 10 | public static UIBezierPath CreateRoundedRectPath(CGRect rect, CornerRadius cornerRadius) 11 | { 12 | var path = new UIBezierPath(); 13 | 14 | path.MoveTo(new CGPoint(rect.Width - cornerRadius.TopRight, rect.Y)); 15 | path.AddArc(new CGPoint((float)rect.X + rect.Width - cornerRadius.TopRight, (float)rect.Y + cornerRadius.TopRight), (nfloat)cornerRadius.TopRight, (float)(Math.PI * 1.5), (float)Math.PI * 2, true); 16 | path.AddLineTo(new CGPoint(rect.Width, rect.Height - cornerRadius.BottomRight)); 17 | path.AddArc(new CGPoint((float)rect.X + rect.Width - cornerRadius.BottomRight, (float)rect.Y + rect.Height - cornerRadius.BottomRight), (nfloat)cornerRadius.BottomRight, 0, (float)(Math.PI * .5), true); 18 | path.AddLineTo(new CGPoint(cornerRadius.BottomLeft, rect.Height)); 19 | path.AddArc(new CGPoint((float)rect.X + cornerRadius.BottomLeft, (float)rect.Y + rect.Height - cornerRadius.BottomLeft), (nfloat)cornerRadius.BottomLeft, (float)(Math.PI * .5), (float)Math.PI, true); 20 | path.AddLineTo(new CGPoint(rect.X, cornerRadius.TopLeft)); 21 | path.AddArc(new CGPoint((float)rect.X + cornerRadius.TopLeft, (float)rect.Y + cornerRadius.TopLeft), (nfloat)cornerRadius.TopLeft, (float)Math.PI, (float)(Math.PI * 1.5), true); 22 | 23 | path.ClosePath(); 24 | 25 | return path; 26 | } 27 | 28 | public static UIBezierPath CreatePolygonPath(CGRect rect, int sides, double cornerRadius = 0.0, double rotationOffset = 0.0) 29 | { 30 | var offsetRadians = rotationOffset * Math.PI / 180; 31 | var path = new UIBezierPath(); 32 | var theta = 2 * Math.PI / sides; 33 | 34 | var width = (-cornerRadius + Math.Min(rect.Size.Width, rect.Size.Height)) / 2; 35 | var center = new CGPoint(rect.Width / 2, rect.Height / 2); 36 | 37 | var radius = width + cornerRadius - (Math.Cos(theta) * cornerRadius) / 2; 38 | 39 | var angle = offsetRadians; 40 | var corner = new CGPoint(center.X + (radius - cornerRadius) * Math.Cos(angle), center.Y + (radius - cornerRadius) * Math.Sin(angle)); 41 | path.MoveTo(new CGPoint(corner.X + cornerRadius * Math.Cos(angle + theta), corner.Y + cornerRadius * Math.Sin(angle + theta))); 42 | 43 | for (var i = 0; i < sides; i++) 44 | { 45 | angle += theta; 46 | corner = new CGPoint(center.X + (radius - cornerRadius) * Math.Cos(angle), center.Y + (radius - cornerRadius) * Math.Sin(angle)); 47 | var tip = new CGPoint(center.X + radius * Math.Cos(angle), center.Y + radius * Math.Sin(angle)); 48 | var start = new CGPoint(corner.X + cornerRadius * Math.Cos(angle - theta), corner.Y + cornerRadius * Math.Sin(angle - theta)); 49 | var end = new CGPoint(corner.X + cornerRadius * Math.Cos(angle + theta), corner.Y + cornerRadius * Math.Sin(angle + theta)); 50 | 51 | path.AddLineTo(start); 52 | path.AddQuadCurveToPoint(end, tip); 53 | } 54 | 55 | path.ClosePath(); 56 | 57 | return path; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/Default-Portrait.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/Default-Portrait@2x.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/Default.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/Default@2x.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/bg1.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/bg9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/bg9.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/Resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufukhawk/XamUIDemo/7ba39dc3f98975207bb9fe7ced3a399fe0318bf4/XamUIDemo.iOS/Resources/logo.png -------------------------------------------------------------------------------- /XamUIDemo.iOS/XamUIDemo.iOS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | iPhoneSimulator 6 | 8.0.30703 7 | 2.0 8 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B} 9 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | {6143fdea-f3c2-4a09-aafa-6e230626515e} 11 | Exe 12 | XamUIDemo.iOS 13 | Resources 14 | XamUIDemo.iOS 15 | true 16 | NSUrlSessionHandler 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\iPhoneSimulator\Debug 23 | DEBUG 24 | prompt 25 | 4 26 | x86_64 27 | None 28 | true 29 | 30 | 31 | none 32 | true 33 | bin\iPhoneSimulator\Release 34 | prompt 35 | 4 36 | None 37 | x86_64 38 | 39 | 40 | true 41 | full 42 | false 43 | bin\iPhone\Debug 44 | DEBUG 45 | prompt 46 | 4 47 | ARM64 48 | iPhone Developer 49 | true 50 | Entitlements.plist 51 | 52 | 53 | none 54 | true 55 | bin\iPhone\Release 56 | prompt 57 | 4 58 | ARM64 59 | iPhone Developer 60 | Entitlements.plist 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 | {1A72F333-4921-403E-B8D5-541D49EFBA28} 91 | XamUIDemo 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 | -------------------------------------------------------------------------------- /XamUIDemo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamUIDemo.Android", "XamUIDemo.Android\XamUIDemo.Android.csproj", "{B085165E-2B8E-4CA4-865A-74CC0C38622C}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamUIDemo.iOS", "XamUIDemo.iOS\XamUIDemo.iOS.csproj", "{8ECEB38A-BC93-4099-B689-25A66EEF2F7B}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamUIDemo", "XamUIDemo\XamUIDemo.csproj", "{1A72F333-4921-403E-B8D5-541D49EFBA28}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 15 | Release|iPhoneSimulator = Release|iPhoneSimulator 16 | Debug|iPhone = Debug|iPhone 17 | Release|iPhone = Release|iPhone 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 25 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 26 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 27 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 28 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Debug|iPhone.ActiveCfg = Debug|Any CPU 29 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Debug|iPhone.Build.0 = Debug|Any CPU 30 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Release|iPhone.ActiveCfg = Release|Any CPU 31 | {B085165E-2B8E-4CA4-865A-74CC0C38622C}.Release|iPhone.Build.0 = Release|Any CPU 32 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator 33 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator 34 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator 35 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Release|Any CPU.Build.0 = Release|iPhoneSimulator 36 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator 37 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator 38 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator 39 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator 40 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Debug|iPhone.ActiveCfg = Debug|iPhone 41 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Debug|iPhone.Build.0 = Debug|iPhone 42 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Release|iPhone.ActiveCfg = Release|iPhone 43 | {8ECEB38A-BC93-4099-B689-25A66EEF2F7B}.Release|iPhone.Build.0 = Release|iPhone 44 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 49 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 50 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 51 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 52 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Debug|iPhone.ActiveCfg = Debug|Any CPU 53 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Debug|iPhone.Build.0 = Debug|Any CPU 54 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Release|iPhone.ActiveCfg = Release|Any CPU 55 | {1A72F333-4921-403E-B8D5-541D49EFBA28}.Release|iPhone.Build.0 = Release|Any CPU 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /XamUIDemo/Animations/ViewAnimations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Xamarin.Forms; 4 | 5 | namespace XamUIDemo.Animations 6 | { 7 | public static class ViewAnimations 8 | { 9 | public static async Task FadeAnimY(View view) 10 | { 11 | 12 | 13 | await Task.WhenAll 14 | ( 15 | view.FadeTo(1, 200), 16 | view.TranslateTo(0, 0, 200) 17 | ); 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /XamUIDemo/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /XamUIDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | using Xamarin.Forms.Xaml; 4 | 5 | namespace XamUIDemo 6 | { 7 | public partial class App : Application 8 | { 9 | public App() 10 | { 11 | InitializeComponent(); 12 | 13 | MainPage = new NavigationPage(new MainPage()); 14 | } 15 | 16 | protected override void OnStart() 17 | { 18 | // Handle when your app starts 19 | } 20 | 21 | protected override void OnSleep() 22 | { 23 | // Handle when your app sleeps 24 | } 25 | 26 | protected override void OnResume() 27 | { 28 | // Handle when your app resumes 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /XamUIDemo/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms.Xaml; 2 | 3 | [assembly: XamlCompilation(XamlCompilationOptions.Compile)] -------------------------------------------------------------------------------- /XamUIDemo/LoginPages/LoginPage10.xaml: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | 15 | 16 | 28 | 34 | 38 |