Friday 20 February 2015

Xamarin.Forms TabbedPage and Swipe

As of version 1.3.5-pre1 of Xamarin.Forms, there doesn't seem to be a way to swipe a TabbedPage on Android out of the box.

I first thought I could add the gesture via a GestureListener in a Custom Renderer, however this causes issues when trying to swipe while showing a full screen button or ListView, as these two controls consume the Gestures, so this wasn't an option.

I then had an idea about combining a CarouselPage and TabbedPage, hence this post.

This is very convoluted and will not perform very well when used in complex UI layouts, but it might be useful.

First the XAML :-

 
  
   
    
     
      
     
    
    
    
   
  
  
   
    
    
     
      
     
    
    
   
  
  
   
    
    
    
     
      
     
    
   
  
 


As you can see this layout won't work for Windows Phone and I haven't tested this on iOS however I am only really targeting Android at the moment.

Next is the C# :-

public partial class MainPage : TabbedPage
{
 public MainPage()
 {
  InitializeComponent();

  AttachCurrentPageChanged();
 }

 private void AttachCurrentPageChanged()
 {
  Page1.CurrentPageChanged += MultiPage_OnCurrentPageChanged;
  Page2.CurrentPageChanged += MultiPage_OnCurrentPageChanged;
  Page3.CurrentPageChanged += MultiPage_OnCurrentPageChanged;
 }

 private void DetachCurrentPageChanged()
 {
  Page1.CurrentPageChanged -= MultiPage_OnCurrentPageChanged;
  Page2.CurrentPageChanged -= MultiPage_OnCurrentPageChanged;
  Page3.CurrentPageChanged -= MultiPage_OnCurrentPageChanged;
 }

 private void MultiPage_OnCurrentPageChanged(object sender, EventArgs e)
 {
  DetachCurrentPageChanged();

  CarouselPage carouselPage = sender as CarouselPage;
  if (carouselPage != null)
  {
   int indexOf = carouselPage.Children.IndexOf(carouselPage.CurrentPage);

   var tabbedPage = carouselPage.ParentView as TabbedPage;

   if (tabbedPage != null)
   {
    tabbedPage.CurrentPage = tabbedPage.Children[indexOf];

    var newCarouselPage = tabbedPage.CurrentPage as CarouselPage;

    if (newCarouselPage != null)
    {
     newCarouselPage.CurrentPage = newCarouselPage.Children[indexOf];
    }
   }
  }

  AttachCurrentPageChanged();
 }
}
The OnCurrentPageChanged is used to track the Page Change of the CarouselPage, the index of this page is then used to set the CurrentPage of the next CarouselPage.

As this tracking needs to occur the number of child Pages in each of the CarouselPages needs to equal the numbwe of Tabs you would like to show.

If you want to add more Tabs, you add more CarouselPage's as children of the TabbedPage and then ensure that each CarouselPage is updated with the correct number of children.

This is by far an ideal solution but was interesting nevertheless.

The complete sample is here :-

http://www.smartmobiledevice.co.uk/Samples/Xamarin/SwipeTabbedPageSample.zip

10 comments:

  1. cool tweak. swipe works perfect. but clicking on the tab header is not going to new tab page.

    ReplyDelete
  2. found a solution for it.. added below code worked for me. thanks for the sample.

    this.CurrentPageChanged += MultiPage1_OnCurrentPageChanged;

    private void MultiPage1_OnCurrentPageChanged(object sender, EventArgs e)
    {
    TabbedPage tabbedPage = sender as TabbedPage;
    if (tabbedPage != null) {
    CarouselPage currentPage = tabbedPage.CurrentPage as CarouselPage;
    currentPage.CurrentPage = currentPage.Children[tabbedPage.Children.IndexOf(tabbedPage.CurrentPage)];
    }
    }

    ReplyDelete
  3. Download link is not working. please provide working link

    Thanks in adavnce

    ReplyDelete
  4. Hi,
    i tried this solution. it works for upto 3 tabs. For more than 3 it is not showing second tab page in Android.
    Please help

    Thanks in advance

    ReplyDelete
    Replies
    1. For three tabs three content pages added. Then for 4 tabs you should add 4 content page as shown.

      Delete
  5. any idea how to implement this for windows 8.1 using xamarin forms

    ReplyDelete
  6. any idea how to implement this for windows 8.1 using xamarin forms

    ReplyDelete