├── src ├── iOS │ ├── ITunesArtwork │ ├── ITunesArtwork@2x │ ├── Resources │ │ ├── pin.png │ │ ├── pin@2x.png │ │ ├── Default.png │ │ ├── Icon-76.png │ │ ├── Default@2x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small-40.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Default-568h@2x.png │ │ ├── Default-Portrait.png │ │ ├── Icon-Small-40@2x.png │ │ ├── Icon-Small-40@3x.png │ │ ├── Default-Portrait@2x.png │ │ └── LaunchScreen.storyboard │ ├── packages.config │ ├── Entitlements.plist │ ├── Main.cs │ ├── AppDelegate.cs │ ├── Info.plist │ ├── Renderers │ │ └── CarouselLayoutRenderer.cs │ └── SwippableBottomTabView.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 │ │ └── Resource.designer.cs │ ├── packages.config │ ├── Properties │ │ ├── AndroidManifest.xml │ │ └── AssemblyInfo.cs │ ├── MainActivity.cs │ ├── Assets │ │ └── AboutAssets.txt │ ├── Renderers │ │ ├── CustomNavigationRenderer.cs │ │ └── CarouselLayoutRenderer.cs │ └── SwippableBottomTabView.Droid.csproj ├── repositories.config ├── SwippableBottomTabView │ ├── ViewModels │ │ ├── ICarouselViewModel.cs │ │ ├── TabOneViewModel.cs │ │ ├── TabTwoViewModel.cs │ │ ├── TabbedPageViewModel.cs │ │ ├── BaseViewModel.cs │ │ └── SwitcherPageViewModel.cs │ ├── DynamicTemplateLayout.cs │ ├── TabPageOne.cs │ ├── TabPageTwo.cs │ ├── App.cs │ ├── HomeView.cs │ ├── SwippableBottomTabView.shproj │ ├── SwitcherPage.cs │ ├── SwippableBottomTabView.projitems │ ├── PagerIndicatorDots.cs │ ├── PagerIndicatorTabs.cs │ ├── Controls │ │ └── CarouselLayout.cs │ └── HomePage.cs ├── .gitignore └── SwippableBottomTabView.sln ├── README.md └── LICENSE.md /src/iOS/ITunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/ITunesArtwork -------------------------------------------------------------------------------- /src/iOS/ITunesArtwork@2x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/ITunesArtwork@2x -------------------------------------------------------------------------------- /src/iOS/Resources/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/pin.png -------------------------------------------------------------------------------- /src/iOS/Resources/pin@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/pin@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Default.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-76.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Default@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-60@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-60@3x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-76@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-Small.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-Small-40.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-Small@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-Small@3x.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable/icon.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/one.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable/one.jpeg -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable/pin.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/pip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable/pip.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Default-Portrait.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /src/iOS/Resources/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /src/iOS/Resources/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/iOS/Resources/Default-Portrait@2x.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /src/Droid/Resources/drawable/pip_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imgen/XamarinForms.SwippableBottomTabView/HEAD/src/Droid/Resources/drawable/pip_selected.png -------------------------------------------------------------------------------- /src/iOS/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/repositories.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/ViewModels/ICarouselViewModel.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | 3 | namespace SwippableBottomTabView.ViewModels 4 | { 5 | public interface ICarouselViewModel 6 | { 7 | ContentView View { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Droid/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/Droid/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/ViewModels/TabOneViewModel.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | 3 | namespace SwippableBottomTabView.ViewModels 4 | { 5 | class TabOneViewModel : BaseViewModel, ICarouselViewModel 6 | { 7 | public Color PageOneColor 8 | { 9 | get { return Color.Red; } 10 | } 11 | 12 | public ContentView View 13 | { 14 | get { return new TabPageOne(); } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using UIKit; 2 | 3 | namespace SwippableBottomTabView.iOS 4 | { 5 | public class Application 6 | { 7 | // This is the main entry point of the application. 8 | private static void Main(string[] args) 9 | { 10 | // if you want to use a different Application Delegate class from "AppDelegate" 11 | // you can specify it here. 12 | UIApplication.Main(args, null, "AppDelegate"); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/SwippableBottomTabView/ViewModels/TabTwoViewModel.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | 3 | namespace SwippableBottomTabView.ViewModels 4 | { 5 | class TabTwoViewModel: BaseViewModel, ICarouselViewModel 6 | { 7 | public ContentView View 8 | { 9 | get { return new TabPageTwo(); } 10 | } 11 | 12 | public string PageTwoTitle 13 | { 14 | get 15 | { 16 | return "This is a title"; 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | using UIKit; 3 | 4 | namespace SwippableBottomTabView.iOS 5 | { 6 | [Register("AppDelegate")] 7 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate 8 | { 9 | public override bool FinishedLaunching(UIApplication app, NSDictionary options) 10 | { 11 | global::Xamarin.Forms.Forms.Init(); 12 | 13 | LoadApplication(new App()); 14 | 15 | return base.FinishedLaunching(app, options); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/SwippableBottomTabView/DynamicTemplateLayout.cs: -------------------------------------------------------------------------------- 1 | using SwippableBottomTabView.ViewModels; 2 | using Xamarin.Forms; 3 | 4 | namespace SwippableBottomTabView 5 | { 6 | public class DynamicTemplateLayout : ViewCell 7 | { 8 | protected override void OnBindingContextChanged() 9 | { 10 | base.OnBindingContextChanged(); 11 | 12 | var vm = BindingContext as ICarouselViewModel; 13 | var page = vm.View; 14 | page.BindingContext = vm; 15 | View = page; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/TabPageOne.cs: -------------------------------------------------------------------------------- 1 | using SwippableBottomTabView.ViewModels; 2 | using Xamarin.Forms; 3 | 4 | namespace SwippableBottomTabView 5 | { 6 | class TabPageOne: ContentView 7 | { 8 | public TabPageOne() 9 | { 10 | var box = new BoxView() 11 | { 12 | WidthRequest = 100, 13 | HeightRequest = 100, 14 | }; 15 | box.SetBinding(BoxView.ColorProperty, vm => vm.PageOneColor); 16 | Content = box; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/TabPageTwo.cs: -------------------------------------------------------------------------------- 1 | using SwippableBottomTabView.ViewModels; 2 | using Xamarin.Forms; 3 | 4 | namespace SwippableBottomTabView 5 | { 6 | class TabPageTwo: ContentView 7 | { 8 | public TabPageTwo() 9 | { 10 | BackgroundColor = Color.White; 11 | var label = new Label() 12 | { 13 | FontAttributes = Xamarin.Forms.FontAttributes.Bold, 14 | }; 15 | label.TextColor = Color.Blue; 16 | label.SetBinding(Label.TextProperty, vm => vm.PageTwoTitle); 17 | 18 | Content = label; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XamarinForms.SwippableBottomTabView 2 | This is a Tab control based off Chris Riesgo's excellent Carousel View 3 | 4 | https://github.com/chrisriesgo/xamarin-forms-carouselview 5 | https://gist.github.com/chrisriesgo/2e9c88fa346e57745e73 6 | 7 | with his point of direction of how to implement a Tab View 8 | 9 | One caveat: this code is not very reusable, meaning it's not something you can drop into your project and it will work right away. You still need to do some work to integrate it into your project. 10 | Also, there is no transiton of the tabs when swiping like View Indicator in Android. The tab will be changed after the swipe is in place. 11 | -------------------------------------------------------------------------------- /src/Droid/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Content.PM; 3 | using Android.OS; 4 | 5 | namespace SwippableBottomTabView.Droid 6 | { 7 | [Activity(Label = "TabView Demo", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] 8 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity 9 | { 10 | protected override void OnCreate(Bundle bundle) 11 | { 12 | base.OnCreate(bundle); 13 | 14 | global::Xamarin.Forms.Forms.Init(this, bundle); 15 | 16 | LoadApplication(new App()); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /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/SwippableBottomTabView/App.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | 3 | namespace SwippableBottomTabView 4 | { 5 | public class App : Application 6 | { 7 | public App() 8 | { 9 | // The root page of your application 10 | var navPage = new NavigationPage(new SwitcherPage()); 11 | navPage.Icon = null; 12 | MainPage = navPage; 13 | } 14 | 15 | protected override void OnStart() 16 | { 17 | // Handle when your app starts 18 | } 19 | 20 | protected override void OnSleep() 21 | { 22 | // Handle when your app sleeps 23 | } 24 | 25 | protected override void OnResume() 26 | { 27 | // Handle when your app resumes 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/SwippableBottomTabView/HomeView.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | 3 | namespace SwippableBottomTabView 4 | { 5 | public class HomeView : ContentView 6 | { 7 | public HomeView() 8 | { 9 | BackgroundColor = Color.White; 10 | 11 | var label = new Label 12 | { 13 | XAlign = 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 | { 22 | VerticalOptions = LayoutOptions.CenterAndExpand, 23 | Children = { 24 | label 25 | } 26 | }; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /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/SwippableBottomTabView/SwippableBottomTabView.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {77990895-4247-4E5A-9474-E3456B62A28D} 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Droid/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | // Information about this assembly is defined by the following attributes. 4 | // Change them to the values specific to your project. 5 | 6 | [assembly: AssemblyTitle("SwippableBottomTabView.Droid")] 7 | [assembly: AssemblyDescription("")] 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("")] 11 | [assembly: AssemblyCopyright("chrisriesgo")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | 15 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 16 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 17 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 18 | 19 | [assembly: AssemblyVersion("1.0.0")] 20 | 21 | // The following attributes are used to specify the signing key for the assembly, 22 | // if desired. See the Mono documentation for more information about signing. 23 | 24 | //[assembly: AssemblyDelaySign(false)] 25 | //[assembly: AssemblyKeyFile("")] -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hailin Shu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/ViewModels/TabbedPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace SwippableBottomTabView.ViewModels 5 | { 6 | public class TabbedPageViewModel: BaseViewModel 7 | { 8 | public TabbedPageViewModel() 9 | { 10 | Pages = new List 11 | { 12 | new TabOneViewModel(), 13 | new TabTwoViewModel() 14 | }; 15 | } 16 | 17 | private IEnumerable _pages; 18 | 19 | public IEnumerable Pages 20 | { 21 | get 22 | { 23 | return _pages; 24 | } 25 | set 26 | { 27 | SetObservableProperty(ref _pages, value); 28 | CurrentPage = Pages.FirstOrDefault(); 29 | } 30 | } 31 | 32 | private ICarouselViewModel _currentPage; 33 | 34 | public ICarouselViewModel CurrentPage 35 | { 36 | get 37 | { 38 | return _currentPage; 39 | } 40 | set 41 | { 42 | SetObservableProperty(ref _currentPage, value); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/SwitcherPage.cs: -------------------------------------------------------------------------------- 1 | using SwippableBottomTabView.Controls; 2 | using Xamarin.Forms; 3 | 4 | namespace SwippableBottomTabView 5 | { 6 | public class SwitcherPage : ContentPage 7 | { 8 | public SwitcherPage() 9 | { 10 | Title = "Pager Layout w/ Indicators"; 11 | 12 | var none = new Button 13 | { 14 | HorizontalOptions = LayoutOptions.Center, 15 | Text = "No pager indicator", 16 | Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.None))) 17 | }; 18 | var dots = new Button 19 | { 20 | HorizontalOptions = LayoutOptions.Center, 21 | Text = "Dots", 22 | Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Dots))) 23 | }; 24 | var tabs = new Button 25 | { 26 | HorizontalOptions = LayoutOptions.Center, 27 | Text = "Tabs", 28 | Command = new Command((obj) => Navigation.PushAsync(new HomePage(CarouselLayout.IndicatorStyleEnum.Tabs))) 29 | }; 30 | Content = new StackLayout 31 | { 32 | Orientation = StackOrientation.Vertical, 33 | VerticalOptions = LayoutOptions.Center, 34 | Spacing = 20, 35 | Children = { 36 | none, 37 | dots, 38 | tabs 39 | } 40 | }; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/SwippableBottomTabView/ViewModels/BaseViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | using System.Threading.Tasks; 5 | using Xamarin.Forms; 6 | 7 | namespace SwippableBottomTabView.ViewModels 8 | { 9 | public abstract class BaseViewModel : INotifyPropertyChanged 10 | { 11 | public INavigation Navigation { get; set; } 12 | 13 | internal virtual Task Initialize(params object[] args) 14 | { 15 | return Task.FromResult(0); 16 | } 17 | 18 | protected void OnPropertyChanged(string propertyName) 19 | { 20 | if (PropertyChanged == null) return; 21 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 22 | } 23 | 24 | protected void SetObservableProperty( 25 | ref T field, 26 | T value, 27 | [CallerMemberName] string propertyName = "") 28 | { 29 | if (EqualityComparer.Default.Equals(field, value)) return; 30 | field = value; 31 | OnPropertyChanged(propertyName); 32 | } 33 | 34 | // string Md5Hash (string value) 35 | // { 36 | // var hash = MD5.Create (); 37 | // var data = hash.ComputeHash (Encoding.UTF8.GetBytes (value)); 38 | // var builder = new StringBuilder (); 39 | // for (var i = 0; i < data.Length; i++) { 40 | // builder.Append (data [i].ToString ("x2")); 41 | // } 42 | // return builder.ToString (); 43 | // } 44 | 45 | public event PropertyChangedEventHandler PropertyChanged; 46 | } 47 | } -------------------------------------------------------------------------------- /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/SwippableBottomTabView/ViewModels/SwitcherPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Xamarin.Forms; 4 | 5 | namespace SwippableBottomTabView.ViewModels 6 | { 7 | public class SwitcherPageViewModel : BaseViewModel 8 | { 9 | public SwitcherPageViewModel() 10 | { 11 | Pages = new List() { 12 | new HomeViewModel { Title = "1", Background = Color.White, ImageSource = "icon.png" }, 13 | new HomeViewModel { Title = "2", Background = Color.Red, ImageSource = "icon.png" }, 14 | new HomeViewModel { Title = "3", Background = Color.Blue, ImageSource = "icon.png" }, 15 | new HomeViewModel { Title = "4", Background = Color.Yellow, ImageSource = "icon.png" }, 16 | }; 17 | 18 | CurrentPage = Pages.First(); 19 | } 20 | 21 | private IEnumerable _pages; 22 | 23 | public IEnumerable Pages 24 | { 25 | get 26 | { 27 | return _pages; 28 | } 29 | set 30 | { 31 | SetObservableProperty(ref _pages, value); 32 | CurrentPage = Pages.FirstOrDefault(); 33 | } 34 | } 35 | 36 | private HomeViewModel _currentPage; 37 | 38 | public HomeViewModel CurrentPage 39 | { 40 | get 41 | { 42 | return _currentPage; 43 | } 44 | set 45 | { 46 | SetObservableProperty(ref _currentPage, value); 47 | } 48 | } 49 | } 50 | 51 | public class HomeViewModel : BaseViewModel, ITabProvider 52 | { 53 | public HomeViewModel() 54 | { 55 | } 56 | 57 | public string Title { get; set; } 58 | 59 | public Color Background { get; set; } 60 | 61 | public ImageSource ImageSource { get; set; } 62 | } 63 | } -------------------------------------------------------------------------------- /src/SwippableBottomTabView/SwippableBottomTabView.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {77990895-4247-4E5A-9474-E3456B62A28D} 7 | 8 | 9 | SwippableBottomTabView 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | TabView Demo 7 | CFBundleIdentifier 8 | com.chrisriesgo.xamarin-forms-tabview 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1.0 13 | LSRequiresIPhoneOS 14 | 15 | MinimumOSVersion 16 | 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/Renderers/CarouselLayoutRenderer.cs: -------------------------------------------------------------------------------- 1 | using SwippableBottomTabView.Controls; 2 | using SwippableBottomTabView.iOS.Renderers; 3 | using System; 4 | using System.ComponentModel; 5 | using UIKit; 6 | using Xamarin.Forms; 7 | using Xamarin.Forms.Platform.iOS; 8 | 9 | [assembly: ExportRenderer(typeof(CarouselLayout), typeof(CarouselLayoutRenderer))] 10 | 11 | namespace SwippableBottomTabView.iOS.Renderers 12 | { 13 | public class CarouselLayoutRenderer : ScrollViewRenderer 14 | { 15 | private UIScrollView _native; 16 | 17 | public CarouselLayoutRenderer() 18 | { 19 | PagingEnabled = true; 20 | ShowsHorizontalScrollIndicator = false; 21 | } 22 | 23 | protected override void OnElementChanged(VisualElementChangedEventArgs e) 24 | { 25 | base.OnElementChanged(e); 26 | 27 | if (e.OldElement != null) return; 28 | 29 | _native = (UIScrollView)NativeView; 30 | _native.Scrolled += NativeScrolled; 31 | e.NewElement.PropertyChanged += ElementPropertyChanged; 32 | } 33 | 34 | private void NativeScrolled(object sender, EventArgs e) 35 | { 36 | var center = _native.ContentOffset.X + (_native.Bounds.Width / 2); 37 | ((CarouselLayout)Element).SelectedIndex = ((int)center) / ((int)_native.Bounds.Width); 38 | } 39 | 40 | private void ElementPropertyChanged(object sender, PropertyChangedEventArgs e) 41 | { 42 | if (e.PropertyName == CarouselLayout.SelectedIndexProperty.PropertyName && !Dragging) 43 | { 44 | ScrollToSelection(false); 45 | } 46 | } 47 | 48 | private void ScrollToSelection(bool animate) 49 | { 50 | if (Element == null) return; 51 | 52 | _native.SetContentOffset(new CoreGraphics.CGPoint 53 | (_native.Bounds.Width * 54 | Math.Max(0, ((CarouselLayout)Element).SelectedIndex), 55 | _native.ContentOffset.Y), 56 | animate); 57 | } 58 | 59 | public override void Draw(CoreGraphics.CGRect rect) 60 | { 61 | base.Draw(rect); 62 | ScrollToSelection(false); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/Droid/Resources/Resource.designer.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 1591 2 | //------------------------------------------------------------------------------ 3 | // 4 | // This code was generated by a tool. 5 | // Runtime Version:4.0.30319.34209 6 | // 7 | // Changes to this file may cause incorrect behavior and will be lost if 8 | // the code is regenerated. 9 | // 10 | //------------------------------------------------------------------------------ 11 | 12 | [assembly: global::Android.Runtime.ResourceDesignerAttribute("SwippableBottomTabView.Droid.Resource", IsApplication=true)] 13 | 14 | namespace SwippableBottomTabView.Droid 15 | { 16 | 17 | 18 | [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] 19 | public partial class Resource 20 | { 21 | 22 | static Resource() 23 | { 24 | global::Android.Runtime.ResourceIdManager.UpdateIdValues(); 25 | } 26 | 27 | public static void UpdateIdValues() 28 | { 29 | global::Xamarin.Forms.Platform.Resource.String.ApplicationName = global::SwippableBottomTabView.Droid.Resource.String.ApplicationName; 30 | global::Xamarin.Forms.Platform.Resource.String.Hello = global::SwippableBottomTabView.Droid.Resource.String.Hello; 31 | } 32 | 33 | public partial class Attribute 34 | { 35 | 36 | static Attribute() 37 | { 38 | global::Android.Runtime.ResourceIdManager.UpdateIdValues(); 39 | } 40 | 41 | private Attribute() 42 | { 43 | } 44 | } 45 | 46 | public partial class Drawable 47 | { 48 | 49 | // aapt resource value: 0x7f020000 50 | public const int icon = 2130837504; 51 | 52 | // aapt resource value: 0x7f020001 53 | public const int pin = 2130837505; 54 | 55 | static Drawable() 56 | { 57 | global::Android.Runtime.ResourceIdManager.UpdateIdValues(); 58 | } 59 | 60 | private Drawable() 61 | { 62 | } 63 | } 64 | 65 | public partial class String 66 | { 67 | 68 | // aapt resource value: 0x7f030001 69 | public const int ApplicationName = 2130903041; 70 | 71 | // aapt resource value: 0x7f030000 72 | public const int Hello = 2130903040; 73 | 74 | static String() 75 | { 76 | global::Android.Runtime.ResourceIdManager.UpdateIdValues(); 77 | } 78 | 79 | private String() 80 | { 81 | } 82 | } 83 | } 84 | } 85 | #pragma warning restore 1591 86 | -------------------------------------------------------------------------------- /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/SwippableBottomTabView.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SwippableBottomTabView", "SwippableBottomTabView\SwippableBottomTabView.shproj", "{77990895-4247-4E5A-9474-E3456B62A28D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwippableBottomTabView.iOS", "iOS\SwippableBottomTabView.iOS.csproj", "{E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwippableBottomTabView.Droid", "Droid\SwippableBottomTabView.Droid.csproj", "{26422919-3EAD-440B-B516-E41B10D2AC56}" 11 | EndProject 12 | Global 13 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 14 | SwippableBottomTabView\SwippableBottomTabView.projitems*{77990895-4247-4e5a-9474-e3456b62a28d}*SharedItemsImports = 13 15 | SwippableBottomTabView\SwippableBottomTabView.projitems*{e97c5e1f-83a0-4cd5-b1e1-91897b8c9f86}*SharedItemsImports = 4 16 | SwippableBottomTabView\SwippableBottomTabView.projitems*{26422919-3ead-440b-b516-e41b10d2ac56}*SharedItemsImports = 4 17 | EndGlobalSection 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Debug|iPhone = Debug|iPhone 21 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 22 | Release|Any CPU = Release|Any CPU 23 | Release|iPhone = Release|iPhone 24 | Release|iPhoneSimulator = Release|iPhoneSimulator 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator 28 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator 29 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhone.ActiveCfg = Debug|iPhone 30 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhone.Build.0 = Debug|iPhone 31 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator 32 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator 33 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|Any CPU.ActiveCfg = Release|iPhone 34 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|Any CPU.Build.0 = Release|iPhone 35 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhone.ActiveCfg = Release|iPhone 36 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhone.Build.0 = Release|iPhone 37 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator 38 | {E97C5E1F-83A0-4CD5-B1E1-91897B8C9F86}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator 39 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 42 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhone.ActiveCfg = Debug|Any CPU 43 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhone.Build.0 = Debug|Any CPU 44 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 45 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 46 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhone.ActiveCfg = Release|Any CPU 49 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhone.Build.0 = Release|Any CPU 50 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 51 | {26422919-3EAD-440B-B516-E41B10D2AC56}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /src/SwippableBottomTabView/PagerIndicatorDots.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Linq; 4 | using Xamarin.Forms; 5 | 6 | namespace SwippableBottomTabView 7 | { 8 | public interface ITabProvider 9 | { 10 | ImageSource ImageSource { get; set; } 11 | } 12 | 13 | public class PagerIndicatorDots : StackLayout 14 | { 15 | private int _dotCount = 1; 16 | private int _selectedIndex; 17 | 18 | public Color DotColor { get; set; } 19 | 20 | public double DotSize { get; set; } 21 | 22 | public PagerIndicatorDots() 23 | { 24 | HorizontalOptions = LayoutOptions.CenterAndExpand; 25 | VerticalOptions = LayoutOptions.Center; 26 | Orientation = StackOrientation.Horizontal; 27 | DotColor = Color.Black; 28 | } 29 | 30 | private void CreateDot() 31 | { 32 | //Make one button and add it to the dotLayout 33 | var dot = new Button 34 | { 35 | BorderRadius = Convert.ToInt32(DotSize / 2), 36 | HeightRequest = DotSize, 37 | WidthRequest = DotSize, 38 | BackgroundColor = DotColor 39 | }; 40 | Children.Add(dot); 41 | } 42 | 43 | private void CreateTabs() 44 | { 45 | foreach (var item in ItemsSource) 46 | { 47 | var tab = item as ITabProvider; 48 | var image = new Image 49 | { 50 | HeightRequest = 42, 51 | WidthRequest = 42, 52 | BackgroundColor = DotColor, 53 | Source = tab.ImageSource, 54 | }; 55 | Children.Add(image); 56 | } 57 | } 58 | 59 | public static BindableProperty ItemsSourceProperty = 60 | BindableProperty.Create( 61 | pi => pi.ItemsSource, 62 | null, 63 | BindingMode.OneWay, 64 | propertyChanging: (bindable, oldValue, newValue) => 65 | { 66 | ((PagerIndicatorDots)bindable).ItemsSourceChanging(); 67 | }, 68 | propertyChanged: (bindable, oldValue, newValue) => 69 | { 70 | ((PagerIndicatorDots)bindable).ItemsSourceChanged(); 71 | } 72 | ); 73 | 74 | public IList ItemsSource 75 | { 76 | get 77 | { 78 | return (IList)GetValue(ItemsSourceProperty); 79 | } 80 | set 81 | { 82 | SetValue(ItemsSourceProperty, value); 83 | } 84 | } 85 | 86 | public static BindableProperty SelectedItemProperty = 87 | BindableProperty.Create( 88 | pi => pi.SelectedItem, 89 | null, 90 | BindingMode.TwoWay, 91 | propertyChanged: (bindable, oldValue, newValue) => 92 | { 93 | ((PagerIndicatorDots)bindable).SelectedItemChanged(); 94 | }); 95 | 96 | public object SelectedItem 97 | { 98 | get 99 | { 100 | return GetValue(SelectedItemProperty); 101 | } 102 | set 103 | { 104 | SetValue(SelectedItemProperty, value); 105 | } 106 | } 107 | 108 | private void ItemsSourceChanging() 109 | { 110 | if (ItemsSource != null) 111 | _selectedIndex = ItemsSource.IndexOf(SelectedItem); 112 | } 113 | 114 | private void ItemsSourceChanged() 115 | { 116 | if (ItemsSource == null) return; 117 | 118 | // Dots ************************************* 119 | var countDelta = ItemsSource.Count - Children.Count; 120 | 121 | if (countDelta > 0) 122 | { 123 | for (var i = 0; i < countDelta; i++) 124 | { 125 | CreateDot(); 126 | } 127 | } 128 | else if (countDelta < 0) 129 | { 130 | for (var i = 0; i < -countDelta; i++) 131 | { 132 | Children.RemoveAt(0); 133 | } 134 | } 135 | //******************************************* 136 | } 137 | 138 | private void SelectedItemChanged() 139 | { 140 | var selectedIndex = ItemsSource.IndexOf(SelectedItem); 141 | var pagerIndicators = Children.Cast