├── src ├── iOS │ ├── ITunesArtwork │ ├── ITunesArtwork@2x │ ├── Resources │ │ ├── pin.png │ │ ├── Default.png │ │ ├── Icon-76.png │ │ ├── pin@2x.png │ │ ├── Default@2x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-Small.png │ │ ├── Default-568h@2x.png │ │ ├── Icon-Small-40.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Default-Portrait.png │ │ ├── Icon-Small-40@2x.png │ │ ├── Icon-Small-40@3x.png │ │ ├── Default-Portrait@2x.png │ │ └── LaunchScreen.storyboard │ ├── packages.config │ ├── Entitlements.plist │ ├── AppDelegate.cs │ ├── Main.cs │ ├── Renderers │ │ └── CarouselLayoutRenderer.cs │ ├── Info.plist │ └── CustomLayouts.iOS.csproj ├── Droid │ ├── Resources │ │ ├── drawable │ │ │ ├── icon.png │ │ │ ├── one.jpeg │ │ │ ├── pin.png │ │ │ ├── pip.png │ │ │ └── pip_selected.png │ │ ├── drawable-hdpi │ │ │ └── icon.png │ │ ├── drawable-xhdpi │ │ │ └── icon.png │ │ ├── drawable-xxhdpi │ │ │ └── icon.png │ │ └── AboutResources.txt │ ├── Properties │ │ ├── AndroidManifest.xml │ │ └── AssemblyInfo.cs │ ├── MainActivity.cs │ ├── Assets │ │ └── AboutAssets.txt │ ├── Renderers │ │ ├── CustomNavigationRenderer.cs │ │ └── CarouselLayoutRenderer.cs │ ├── packages.config │ └── CustomLayouts.Droid.csproj ├── .gitignore ├── CustomLayouts │ ├── App.cs │ ├── HomeView.cs │ ├── CustomLayouts.shproj │ ├── SwitcherPage.cs │ ├── CustomLayouts.projitems │ ├── ViewModels │ │ ├── SwitcherPageViewModel.cs │ │ └── BaseViewModel.cs │ ├── PagerIndicatorDots.cs │ ├── Controls │ │ └── CarouselLayout.cs │ ├── HomePage.cs │ └── PagerIndicatorTabs.cs └── CustomLayouts.sln ├── Images └── carousel_view.gif └── README.md /src/iOS/ITunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/ITunesArtwork -------------------------------------------------------------------------------- /Images/carousel_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/Images/carousel_view.gif -------------------------------------------------------------------------------- /src/iOS/ITunesArtwork@2x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/ITunesArtwork@2x -------------------------------------------------------------------------------- /src/iOS/Resources/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/pin.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Default.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-76.png -------------------------------------------------------------------------------- /src/iOS/Resources/pin@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/pin@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Default@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-60@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-60@3x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-76@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-Small.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable/icon.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/one.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable/one.jpeg -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable/pin.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/pip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable/pip.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-Small-40.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-Small@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-Small@3x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Default-Portrait.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/iOS/Resources/Default-Portrait@2x.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/pip_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisriesgo/xamarin-forms-carouselview/HEAD/src/Droid/Resources/drawable/pip_selected.png -------------------------------------------------------------------------------- /src/iOS/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Droid/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | 2 | using Foundation; 3 | using UIKit; 4 | 5 | namespace CustomLayouts.iOS 6 | { 7 | [Register("AppDelegate")] 8 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate 9 | { 10 | public override bool FinishedLaunching(UIApplication app, NSDictionary options) 11 | { 12 | global::Xamarin.Forms.Forms.Init(); 13 | 14 | LoadApplication(new App()); 15 | 16 | return base.FinishedLaunching(app, options); 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/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 CustomLayouts.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 | 22 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | #Autosave files 2 | *~ 3 | 4 | #build 5 | [Oo]bj/ 6 | [Bb]in/ 7 | packages/ 8 | TestResults/ 9 | 10 | # globs 11 | Makefile.in 12 | *.DS_Store 13 | *.sln.cache 14 | *.suo 15 | *.cache 16 | *.pidb 17 | *.userprefs 18 | *.usertasks 19 | config.log 20 | config.make 21 | config.status 22 | aclocal.m4 23 | install-sh 24 | autom4te.cache/ 25 | *.user 26 | *.tar.gz 27 | tarballs/ 28 | test-results/ 29 | Thumbs.db 30 | 31 | #Mac bundle stuff 32 | *.dmg 33 | *.app 34 | 35 | #resharper 36 | *_Resharper.* 37 | *.Resharper 38 | 39 | #dotCover 40 | *.dotCover 41 | 42 | Resource.designer.cs -------------------------------------------------------------------------------- /src/Droid/MainActivity.cs: -------------------------------------------------------------------------------- 1 | 2 | using Android.App; 3 | using Android.Content.PM; 4 | using Android.OS; 5 | 6 | namespace CustomLayouts.Droid 7 | { 8 | [Activity(Label = "CarouselView Demo", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] 9 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity 10 | { 11 | protected override void OnCreate(Bundle bundle) 12 | { 13 | base.OnCreate(bundle); 14 | 15 | global::Xamarin.Forms.Forms.Init(this, bundle); 16 | 17 | LoadApplication(new App()); 18 | } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/CustomLayouts/App.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Xamarin.Forms; 4 | 5 | namespace CustomLayouts 6 | { 7 | public class App : Application 8 | { 9 | public App() 10 | { 11 | // The root page of your application 12 | var navPage = new NavigationPage(new SwitcherPage()); 13 | navPage.Icon = null; 14 | MainPage = navPage; 15 | } 16 | 17 | protected override void OnStart() 18 | { 19 | // Handle when your app starts 20 | } 21 | 22 | protected override void OnSleep() 23 | { 24 | // Handle when your app sleeps 25 | } 26 | 27 | protected override void OnResume() 28 | { 29 | // Handle when your app resumes 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/CustomLayouts/HomeView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | 4 | namespace CustomLayouts 5 | { 6 | public class HomeView : ContentView 7 | { 8 | public HomeView() 9 | { 10 | BackgroundColor = Color.White; 11 | 12 | var label = new Label { 13 | HorizontalTextAlignment = TextAlignment.Center, 14 | TextColor = Color.Black 15 | }; 16 | 17 | label.SetBinding(Label.TextProperty, "Title"); 18 | this.SetBinding(ContentView.BackgroundColorProperty, "Background"); 19 | 20 | Content = new StackLayout { 21 | VerticalOptions = LayoutOptions.CenterAndExpand, 22 | Children = { 23 | label 24 | } 25 | }; 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/Droid/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 | -------------------------------------------------------------------------------- /src/Droid/Renderers/CustomNavigationRenderer.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Graphics.Drawables; 3 | using Xamarin.Forms; 4 | using Xamarin.Forms.Platform.Android; 5 | using CustomLayouts.Droid.Renderers; 6 | 7 | [assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))] 8 | 9 | namespace CustomLayouts.Droid.Renderers 10 | { 11 | public class CustomNavigationRenderer : NavigationRenderer 12 | { 13 | protected override void OnElementChanged(ElementChangedEventArgs e) 14 | { 15 | base.OnElementChanged (e); 16 | 17 | RemoveAppIconFromActionBar (); 18 | } 19 | 20 | void RemoveAppIconFromActionBar() 21 | { 22 | // http://stackoverflow.com/questions/14606294/remove-icon-logo-from-action-bar-on-android 23 | var actionBar = ((Activity)Context).ActionBar; 24 | actionBar.SetIcon (new ColorDrawable(Color.Transparent.ToAndroid())); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/CustomLayouts/CustomLayouts.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {77990895-4247-4E5A-9474-E3456B62A28D} 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Droid/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xamarin.Forms CarouselView 2 | 3 | _A version of this recipe that uses the **Xamarin.Forms.CarouselView** [from NuGet](https://www.nuget.org/packages/Xamarin.Forms.CarouselView/), can be found on [this branch](https://github.com/chrisriesgo/xamarin-forms-carouselview/issues/37)._ 4 | 5 | --- 6 | 7 | Thanks to my friends at [Firefly Logic](https://github.com/FireflyLogic/couchbase-connect-14) and to [Michael Watson](https://github.com/xamarin/customersuccess/tree/master/samples/Xamarin.Forms/SliderView) for the inspiration in creating this custom control. 8 | 9 | This control mirrors the functionality of the CarouselPage - except the "pages" are simply Content Views. 10 | 11 | I have examples that show the CarouselView used as: 12 | 13 | - A full-page control with no page indicators 14 | - A gallery-style control with **dots** as page indicators 15 | - A full-page control with **tabs** as page indicators 16 | 17 |

18 | 19 |

20 | -------------------------------------------------------------------------------- /src/Droid/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using Android.App; 4 | 5 | // Information about this assembly is defined by the following attributes. 6 | // Change them to the values specific to your project. 7 | 8 | [assembly: AssemblyTitle("CustomLayouts.Droid")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("")] 13 | [assembly: AssemblyCopyright("chrisriesgo")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 18 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 19 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 20 | 21 | [assembly: AssemblyVersion("1.0.0")] 22 | 23 | // The following attributes are used to specify the signing key for the assembly, 24 | // if desired. See the Mono documentation for more information about signing. 25 | 26 | //[assembly: AssemblyDelaySign(false)] 27 | //[assembly: AssemblyKeyFile("")] 28 | 29 | -------------------------------------------------------------------------------- /src/CustomLayouts/SwitcherPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | using CustomLayouts.Controls; 4 | 5 | namespace CustomLayouts 6 | { 7 | public class SwitcherPage : ContentPage 8 | { 9 | public SwitcherPage() 10 | { 11 | Title = "Pager Layout w/ Indicators"; 12 | 13 | var none = new Button { 14 | HorizontalOptions = LayoutOptions.Center, 15 | Text = "No pager indicator", 16 | Command = new Command(async (obj) => await Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.None))) 17 | }; 18 | var dots = new Button { 19 | HorizontalOptions = LayoutOptions.Center, 20 | Text = "Dots", 21 | Command = new Command(async (obj) => await Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Dots))) 22 | }; 23 | var tabs = new Button { 24 | HorizontalOptions = LayoutOptions.Center, 25 | Text = "Tabs", 26 | Command = new Command(async (obj) => await Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Tabs))) 27 | }; 28 | Content = new StackLayout { 29 | Orientation = StackOrientation.Vertical, 30 | VerticalOptions = LayoutOptions.Center, 31 | Spacing = 20, 32 | Children = { 33 | none, 34 | dots, 35 | tabs 36 | } 37 | }; 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/CustomLayouts/CustomLayouts.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {77990895-4247-4E5A-9474-E3456B62A28D} 7 | 8 | 9 | CustomLayouts 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/CustomLayouts/ViewModels/SwitcherPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Xamarin.Forms; 5 | 6 | namespace CustomLayouts.ViewModels 7 | { 8 | public class SwitcherPageViewModel : BaseViewModel 9 | { 10 | public SwitcherPageViewModel() 11 | { 12 | Pages = new List() { 13 | new HomeViewModel { Title = "1", Background = Color.White, ImageSource = "icon.png" }, 14 | new HomeViewModel { Title = "2", Background = Color.Red, ImageSource = "icon.png" }, 15 | new HomeViewModel { Title = "3", Background = Color.Blue, ImageSource = "icon.png" }, 16 | new HomeViewModel { Title = "4", Background = Color.Yellow, ImageSource = "icon.png" }, 17 | }; 18 | 19 | CurrentPage = Pages.First(); 20 | } 21 | 22 | IEnumerable _pages; 23 | public IEnumerable Pages { 24 | get { 25 | return _pages; 26 | } 27 | set { 28 | SetObservableProperty (ref _pages, value); 29 | CurrentPage = Pages.FirstOrDefault (); 30 | } 31 | } 32 | 33 | HomeViewModel _currentPage; 34 | public HomeViewModel CurrentPage { 35 | get { 36 | return _currentPage; 37 | } 38 | set { 39 | SetObservableProperty (ref _currentPage, value); 40 | } 41 | } 42 | } 43 | 44 | public class HomeViewModel : BaseViewModel, ITabProvider 45 | { 46 | public HomeViewModel() {} 47 | 48 | public string Title { get; set; } 49 | public Color Background { get; set; } 50 | public string ImageSource { get; set; } 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/CustomLayouts/ViewModels/BaseViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | using Xamarin.Forms; 7 | using System.Security.Cryptography; 8 | using System.Text; 9 | 10 | namespace CustomLayouts.ViewModels 11 | { 12 | public abstract class BaseViewModel : INotifyPropertyChanged 13 | { 14 | public INavigation Navigation { get; set; } 15 | 16 | internal virtual Task Initialize (params object[] args) 17 | { 18 | return Task.FromResult (0); 19 | } 20 | 21 | protected void OnPropertyChanged(string propertyName) { 22 | if (PropertyChanged == null) return; 23 | PropertyChanged (this, new PropertyChangedEventArgs (propertyName)); 24 | } 25 | 26 | protected void SetObservableProperty( 27 | ref T field, 28 | T value, 29 | [CallerMemberName] string propertyName = "") 30 | { 31 | if (EqualityComparer.Default.Equals(field, value)) return; 32 | field = value; 33 | OnPropertyChanged (propertyName); 34 | } 35 | 36 | // string Md5Hash (string value) 37 | // { 38 | // var hash = MD5.Create (); 39 | // var data = hash.ComputeHash (Encoding.UTF8.GetBytes (value)); 40 | // var builder = new StringBuilder (); 41 | // for (var i = 0; i < data.Length; i++) { 42 | // builder.Append (data [i].ToString ("x2")); 43 | // } 44 | // return builder.ToString (); 45 | // } 46 | 47 | #region INotifyPropertyChanged implementation 48 | public event PropertyChangedEventHandler PropertyChanged; 49 | #endregion 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/Droid/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.axml), 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/ 12 | icon.png 13 | 14 | layout/ 15 | main.axml 16 | 17 | values/ 18 | strings.xml 19 | 20 | In order to get the build system to recognize Android resources, set the build action to 21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 22 | instead operate on resource IDs. When you compile an Android application that uses resources, 23 | the build system will package the resources for distribution and generate a class called "R" 24 | (this is an Android convention) that contains the tokens for each one of the resources 25 | included. For example, for the above Resources layout, this is what the R class would expose: 26 | 27 | public class R { 28 | public class drawable { 29 | public const int icon = 0x123; 30 | } 31 | 32 | public class layout { 33 | public const int main = 0x456; 34 | } 35 | 36 | public class strings { 37 | public const int first_string = 0xabc; 38 | public const int second_string = 0xbcd; 39 | } 40 | } 41 | 42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main 43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first 44 | string in the dictionary file values/strings.xml. 45 | -------------------------------------------------------------------------------- /src/iOS/Renderers/CarouselLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | using CustomLayouts.Controls; 4 | using CustomLayouts.iOS.Renderers; 5 | using Xamarin.Forms.Platform.iOS; 6 | using UIKit; 7 | using System.ComponentModel; 8 | using System.Drawing; 9 | 10 | [assembly:ExportRenderer(typeof(CarouselLayout), typeof(CarouselLayoutRenderer))] 11 | 12 | namespace CustomLayouts.iOS.Renderers 13 | { 14 | public class CarouselLayoutRenderer : ScrollViewRenderer 15 | { 16 | UIScrollView _native; 17 | 18 | public CarouselLayoutRenderer () 19 | { 20 | PagingEnabled = true; 21 | ShowsHorizontalScrollIndicator = false; 22 | } 23 | 24 | protected override void OnElementChanged(VisualElementChangedEventArgs e) 25 | { 26 | base.OnElementChanged(e); 27 | 28 | if (e.OldElement != null) return; 29 | 30 | _native = (UIScrollView)NativeView; 31 | _native.Scrolled += NativeScrolled; 32 | e.NewElement.PropertyChanged += ElementPropertyChanged; 33 | } 34 | 35 | void NativeScrolled (object sender, EventArgs e) 36 | { 37 | var center = _native.ContentOffset.X + (_native.Bounds.Width / 2); 38 | ((CarouselLayout)Element).SelectedIndex = ((int)center) / ((int)_native.Bounds.Width); 39 | } 40 | 41 | void ElementPropertyChanged(object sender, PropertyChangedEventArgs e) { 42 | if (e.PropertyName == CarouselLayout.SelectedIndexProperty.PropertyName && !Dragging) { 43 | ScrollToSelection (false); 44 | } 45 | } 46 | 47 | void ScrollToSelection (bool animate) 48 | { 49 | if (Element == null) return; 50 | 51 | _native.SetContentOffset (new CoreGraphics.CGPoint 52 | (_native.Bounds.Width * 53 | Math.Max(0, ((CarouselLayout)Element).SelectedIndex), 54 | _native.ContentOffset.Y), 55 | animate); 56 | } 57 | 58 | public override void Draw(CoreGraphics.CGRect rect) 59 | { 60 | base.Draw (rect); 61 | ScrollToSelection (false); 62 | } 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | CarouselView Demo 7 | CFBundleIdentifier 8 | com.chrisriesgo.xamarin-forms-carouselview 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1.0 13 | LSRequiresIPhoneOS 14 | 15 | MinimumOSVersion 16 | 7.0 17 | UIDeviceFamily 18 | 19 | 1 20 | 2 21 | 22 | UIRequiredDeviceCapabilities 23 | 24 | armv7 25 | 26 | UISupportedInterfaceOrientations 27 | 28 | UIInterfaceOrientationPortrait 29 | UIInterfaceOrientationLandscapeLeft 30 | UIInterfaceOrientationLandscapeRight 31 | 32 | UISupportedInterfaceOrientations~ipad 33 | 34 | UIInterfaceOrientationPortrait 35 | UIInterfaceOrientationPortraitUpsideDown 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | CFBundleIconFiles 40 | 41 | Icon-60@2x 42 | Icon-60@3x 43 | Icon-76 44 | Icon-76@2x 45 | Default 46 | Default@2x 47 | Default-568h 48 | Default-568h@2x 49 | Default-Landscape 50 | Default-Landscape@2x 51 | Default-Portrait 52 | Default-Portrait@2x 53 | Icon-Small-40 54 | Icon-Small-40@2x 55 | Icon-Small-40@3x 56 | Icon-Small 57 | Icon-Small@2x 58 | Icon-Small@3x 59 | 60 | UILaunchStoryboardName 61 | LaunchScreen 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/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 | 40 | -------------------------------------------------------------------------------- /src/CustomLayouts.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CustomLayouts", "CustomLayouts\CustomLayouts.shproj", "{77990895-4247-4E5A-9474-E3456B62A28D}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomLayouts.iOS", "iOS\CustomLayouts.iOS.csproj", "{E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomLayouts.Droid", "Droid\CustomLayouts.Droid.csproj", "{26422919-3EAD-440B-B516-E41B10D2AC56}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 13 | Release|iPhone = Release|iPhone 14 | Release|iPhoneSimulator = Release|iPhoneSimulator 15 | Debug|iPhone = Debug|iPhone 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhone.ActiveCfg = Debug|Any CPU 23 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhone.Build.0 = Debug|Any CPU 24 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 25 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 26 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhone.ActiveCfg = Release|Any CPU 29 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhone.Build.0 = Release|Any CPU 30 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 31 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 32 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator 33 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator 34 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhone.ActiveCfg = Debug|iPhone 35 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhone.Build.0 = Debug|iPhone 36 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator 37 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator 38 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|Any CPU.ActiveCfg = Release|iPhone 39 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|Any CPU.Build.0 = Release|iPhone 40 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhone.ActiveCfg = Release|iPhone 41 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhone.Build.0 = Release|iPhone 42 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator 43 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /src/CustomLayouts/PagerIndicatorDots.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | using System.Collections; 4 | using System.Linq; 5 | 6 | namespace CustomLayouts 7 | { 8 | public interface ITabProvider 9 | { 10 | string ImageSource { get; set; } 11 | } 12 | 13 | public class PagerIndicatorDots : StackLayout 14 | { 15 | int _selectedIndex; 16 | 17 | public Color DotColor { get; set; } 18 | public double DotSize { get; set; } 19 | 20 | public PagerIndicatorDots() 21 | { 22 | HorizontalOptions = LayoutOptions.CenterAndExpand; 23 | VerticalOptions = LayoutOptions.Center; 24 | Orientation = StackOrientation.Horizontal; 25 | DotColor = Color.Black; 26 | } 27 | 28 | void CreateDot() 29 | { 30 | //Make one button and add it to the dotLayout 31 | var dot = new Button { 32 | BorderRadius = Convert.ToInt32(DotSize/2), 33 | HeightRequest = DotSize, 34 | WidthRequest = DotSize, 35 | BackgroundColor = DotColor 36 | }; 37 | Children.Add(dot); 38 | } 39 | 40 | void CreateTabs() 41 | { 42 | foreach(var item in ItemsSource) 43 | { 44 | var tab = item as ITabProvider; 45 | var image = new Image { 46 | HeightRequest = 42, 47 | WidthRequest = 42, 48 | BackgroundColor = DotColor, 49 | Source = tab.ImageSource, 50 | }; 51 | Children.Add(image); 52 | } 53 | } 54 | 55 | public static BindableProperty ItemsSourceProperty = 56 | BindableProperty.Create( 57 | nameof(ItemsSource), 58 | typeof(IList), 59 | typeof(PagerIndicatorDots), 60 | null, 61 | BindingMode.OneWay, 62 | propertyChanging: (bindable, oldValue, newValue) => 63 | { 64 | ((PagerIndicatorDots)bindable).ItemsSourceChanging(); 65 | }, 66 | propertyChanged: (bindable, oldValue, newValue) => 67 | { 68 | ((PagerIndicatorDots)bindable).ItemsSourceChanged(); 69 | } 70 | ); 71 | 72 | public IList ItemsSource { 73 | get { 74 | return (IList)GetValue(ItemsSourceProperty); 75 | } 76 | set { 77 | SetValue (ItemsSourceProperty, value); 78 | } 79 | } 80 | 81 | public static BindableProperty SelectedItemProperty = 82 | BindableProperty.Create( 83 | nameof(SelectedItem), 84 | typeof(object), 85 | typeof(PagerIndicatorDots), 86 | null, 87 | BindingMode.TwoWay, 88 | propertyChanged: (bindable, oldValue, newValue) => 89 | { 90 | ((PagerIndicatorDots)bindable).SelectedItemChanged(); 91 | } 92 | ); 93 | 94 | public object SelectedItem { 95 | get { 96 | return GetValue (SelectedItemProperty); 97 | } 98 | set { 99 | SetValue (SelectedItemProperty, value); 100 | } 101 | } 102 | 103 | void ItemsSourceChanging () 104 | { 105 | if (ItemsSource != null) 106 | _selectedIndex = ItemsSource.IndexOf (SelectedItem); 107 | } 108 | 109 | void ItemsSourceChanged () 110 | { 111 | if (ItemsSource == null) return; 112 | 113 | // Dots ************************************* 114 | var countDelta = ItemsSource.Count - Children.Count; 115 | 116 | if (countDelta > 0) { 117 | for (var i = 0; i < countDelta; i++) 118 | { 119 | CreateDot(); 120 | } 121 | } 122 | else if (countDelta < 0) 123 | { 124 | for (var i = 0; i < -countDelta; i++) 125 | { 126 | Children.RemoveAt (0); 127 | } 128 | } 129 | //******************************************* 130 | } 131 | 132 | void SelectedItemChanged () { 133 | 134 | var selectedIndex = ItemsSource.IndexOf (SelectedItem); 135 | var pagerIndicators = Children.Cast