Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] TabView #121

Closed
1 of 10 tasks
brminnick opened this issue Sep 28, 2021 · 45 comments
Closed
1 of 10 tasks

[Proposal] TabView #121

brminnick opened this issue Sep 28, 2021 · 45 comments
Assignees
Labels
approved This Proposal has been approved and is ready to be added to the Toolkit champion A member of the .NET MAUI Toolkit core team has chosen to champion this feature help wanted This proposal has been approved and is ready to be implemented pending documentation This feature requires documentation proposal A fully fleshed out proposal describing a new feature in syntactic and semantic detail

Comments

@brminnick
Copy link
Collaborator

TabView

  • Proposed
  • Prototype: Not Started
  • Implementation: Not Started
    • iOS Support
    • Android Support
    • macOS Support
    • Windows Support
  • Unit Tests: Not Started
  • Sample: Not Started
  • Documentation: Not Started

Summary

The TabView control allows the user to display a set of tabs and their content. The TabView is fully customizable, other than the native tab bars

Detailed Design

TabView.shared.cs

public class TabView : ContentView, IDisposable
{
  public static readonly BindableProperty TabItemsSourceProperty;
  public static readonly BindableProperty TabViewItemDataTemplateProperty;
  public static readonly BindableProperty TabContentDataTemplateProperty;
  public static readonly BindableProperty SelectedIndexProperty;
  public static readonly BindableProperty TabStripPlacementProperty;
  public static readonly BindableProperty TabStripBackgroundColorProperty;
  public static readonly BindableProperty TabStripBackgroundViewProperty;
  public static readonly BindableProperty TabStripBorderColorProperty;
  public static readonly BindableProperty TabContentBackgroundColorProperty;
  public static readonly BindableProperty TabStripHeightProperty;
  public static readonly BindableProperty IsTabStripVisibleProperty;
  public static readonly BindableProperty TabContentHeightProperty;
  public static readonly BindableProperty TabIndicatorColorProperty;
  public static readonly BindableProperty TabIndicatorHeightProperty;
  public static readonly BindableProperty TabIndicatorWidthProperty;
  public static readonly BindableProperty TabIndicatorViewProperty;
  public static readonly BindableProperty TabIndicatorPlacementProperty;
  public static readonly BindableProperty IsTabTransitionEnabledProperty;
  public static readonly BindableProperty IsSwipeEnabledProperty;
  
  public ObservableCollection<TabViewItem> TabItems { get; }
  public IList? TabItemsSource { get; set; }
  public DataTemplate? TabViewItemDataTemplate { get; set; }
  public DataTemplate? TabContentDataTemplate { get; set; }
  public int SelectedIndex { get; set; }
  public TabStripPlacement TabStripPlacement { get; set; }
  public Color TabStripBackgroundColor { get; set; }
  public View? TabStripBackgroundView { get; set; }
  public Color TabStripBorderColor { get; set; }
  public Color TabContentBackgroundColor { get; set; }
  public double TabStripHeight { get; set; }
  public bool IsTabStripVisible { get; set; }
  public double TabContentHeight { get; set; }
  public Color TabIndicatorColor { get; set; }
  public double TabIndicatorHeight { get; set; }
  public double TabIndicatorWidth  { get; set; }
  public View? TabIndicatorView { get; set; }
  public TabIndicatorPlacement TabIndicatorPlacement { get; set; }
  public bool IsTabTransitionEnabled { get; set; }
  public bool IsSwipeEnabled { get; set; }
  
  public event TabSelectionChangedEventHandler? SelectionChanged;
  public event TabViewScrolledEventHandler? Scrolled;
  
  public void Dispose();
}

Usage Syntax

XAML Usage

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
             x:Class="MyLittleApp.MainPage">

     <Grid>
        <xct:TabView
                TabStripPlacement="Bottom"
                TabStripBackgroundColor="Blue"
                TabStripHeight="60"
                TabIndicatorColor="Yellow"
                TabContentBackgroundColor="Yellow">

                <xct:TabViewItem
                    Icon="triangle.png"
                    Text="Tab 1"
                    TextColor="White"
                    TextColorSelected="Yellow"
                    FontSize="12">
                    <Grid 
                        BackgroundColor="Gray">
                        <Label
                            HorizontalOptions="Center"
                            VerticalOptions="Center"
                            Text="TabContent1" />
                    </Grid>
                </xct:TabViewItem>

                <xct:TabViewItem
                    Icon="circle.png"
                    Text="Tab 2"
                    TextColor="White"
                    TextColorSelected="Yellow"
                    FontSize="12">
                    <Grid>
                        <Label    
                            HorizontalOptions="Center"
                            VerticalOptions="Center"
                            Text="TabContent2" />
                    </Grid>
                </xct:TabViewItem>
        </xct:TabView>
  </Grid>

</ContentPage>

C# Usage

Content = new Grid
{
  new TabVIew
  {
    TabItems = 
    {
      new TabItem
      {
        Icon = "circle.png",
        Text = "Tab 2",
        TextColor = Colors.White,
        TextColorSelected = Colors.Yellow,
        FontSize = 12
        View = new Label { Text = "TabContent2" }.Center()
      }
    }
  }
}
@brminnick brminnick added new proposal A fully fleshed out proposal describing a new feature in syntactic and semantic detail labels Sep 28, 2021
@brminnick brminnick added this to the v1.0.0 milestone Sep 28, 2021
@jsuarezruiz jsuarezruiz self-assigned this Oct 6, 2021
@ghost ghost added approved This Proposal has been approved and is ready to be added to the Toolkit help wanted This proposal has been approved and is ready to be implemented and removed new labels Oct 6, 2021
@brminnick brminnick added champion A member of the .NET MAUI Toolkit core team has chosen to champion this feature pending documentation This feature requires documentation labels Oct 6, 2021
@ChaplinMarchais
Copy link

I am currently working on a project which requires a TabView component, so I have began to implement a prototype according to your specification. If you would like for me to do some work toward this issue I would be glad to contribute!

@brminnick
Copy link
Collaborator Author

Thanks @ChaplinMarchais! That'd be fantastic!

I'll assign this to you 👍

ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 23, 2022
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 23, 2022
Added properties and the corresponding `BindableProperty` backing fields as defined in CommunityToolkit#121
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 24, 2022
…olkit#121)

* Added comments on the public members of `TabView`
* Removed the explicit `private` access modifier from members of `TabView`
@ChaplinMarchais
Copy link

@brminnick just a quick question for you about how you guys want events to be implemented in the TabView for SelectionChanged and Scrolled. Currently I am using the following to ensure that the lifetime of any handlers are correctly respected. Although I am not sure if this is the best way of doing it within the Maui framework.

    readonly WeakEventManager selectionChangedManager = new();
    readonly WeakEventManager tabViewScrolledManager = new();


    public event EventHandler<TabSelectionChangedEventArgs> SelectionChanged
    {
        add => selectionChangedManager.AddEventHandler(value);
        remove => selectionChangedManager.RemoveEventHandler(value);
    }


    public event EventHandler<TabViewScrolledEventArgs> Scrolled
    {
        add => tabViewScrolledManager.AddEventHandler(value);
        remove => tabViewScrolledManager.RemoveEventHandler(value);
    }

Any suggestions for improvements would be welcomed!

@brminnick
Copy link
Collaborator Author

Yup! That looks good 👍

ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 25, 2022
…it#121)

Incorporated the generic version of the `WeakEventManager` from (pictos@42343f3e83d98c08e06fcf23f3a470ff77276a46).
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 27, 2022
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 27, 2022
…it#121)

* Refactored the logic in the constructor of `TabView` into it's own `Initialize()` method.
* Added a `Loading` event which is fired off at the start of `Initialize()` to allow the consumer to hook into the `TabView` before content is assigned. The idea here is to support the following scenarios:
    * Tabs are dynamically generated at runtime from data within the `TabView` itself.
    * Easy method for instrumenting performance monitoring/tracing/etc.
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 27, 2022
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 30, 2022
…olkit#121)

The following outlined changes to the sample project's page system were adopted from https://github.com/CommunityToolkit/Maui/tree/badgeview
- - - -

* Refactored the `SectionModel` to take a `Type` rather than a `Page` as the first argument.
* Refactored the `BaseGalleryPage` to utilize the new construction method for `SectionModel`
* Remove the generic `BasePage`
* Update `BasePage` to utilize a parameter-less constructor with a `protected static Page PreparePage(SectionModel)` for construction of the child pages.
* Update all pages to utilize the aforementioned changes.
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 30, 2022
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 30, 2022
…tyToolkit#121)

* Add enum values for placement of the tab strip on the screen
* Add `BindableProperty` values for the features specified in the design specification
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 30, 2022
…kit#121)

* Remove the original csharp only implementation of `TabViewPage` and replaced it with a XAML with code-behind implementation.
* Add `TabViewViewModel` for the `TabView` sample page.
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Jan 31, 2022
…mmunityToolkit#121)

Add two helper methods in `ArgumentNullExceptionExtensions.shared.cs` which take a `object?` and attempts to cast it to a string and perform the static call to the corresponding guard clause helper on `String` then throws `ArgumentNullException(parameterName)` if it returns true, or the object cannot be cast to string and is null.
@ewerspej
Copy link

@ChaplinMarchais If this control should be a way to substitute the native TabBar, then it would make sense that it also taps into Shell's navigation so that the content of the TabView can be controlled using Routes/URIs using Shell.Current.GoToAsync(). That way it would fully integrate into Shell and can actually replace the native TabBar while still being able to use things like Shell's built-in dependency injection.

@ChaplinMarchais
Copy link

@ewerspej ok I am going to take a look at the Shell implementation over the next couple days, and see how exactly they are integrating with the NavigationManager and make sure there is nothing that is going to blow up in our faces. I know that currently the Shell is pretty limited as to what kind of Types it will accept as a navigation target. For instance I believe that we would have to provide the TabViewItem.Content as a Page rather than currently allowing it to be any IView implementation. That is the only thing that I have discovered so far that may possibly restrict us from integrating with it.

@brminnick do you have any further insight into the inner-workings of Shell or know who I could talk to about what would be required for us to integrate in a fully supported manner?

ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Dec 14, 2022
* Renamed `TabView.TabIndicatorDataTemplate` -> `TabView.TabIndicatorTemplateProperty`
* Add default style const properties to `TabViewItem`
** `LabelStyle`
** `ImageStyle`
** `LayoutStyle`
ChaplinMarchais added a commit to ChaplinMarchais/CommunityToolkit.Maui that referenced this issue Dec 14, 2022
Add a `TabViewIndicator` type which will be responsible for managing the logical collection of `TabViewItem` instances being displayed in the Tab Indicator, as well as providing the logic for correctly constructing the `TabViewItem` based on the proper template and styling.
@mouralabank
Copy link

Any updates on this issue?

@bijington
Copy link
Contributor

Any updates on this issue?

It doesn't look like it. Would you be willing to provide assistance?

@VladislavAntonyuk
Copy link
Collaborator

@ewerspej it would be easier to make shell looks like TabView rather then integrating navigation. Here is an example how you can customize shell appearance: https://vladislavantonyuk.github.io/articles/Customizing-.NET-MAUI-Shell

@JRosanowski
Copy link

JRosanowski commented Jun 9, 2023

I think trying to incorporate Shell will side-track this issue. If you want tabs these options are available but with limitations to Shell usage.

  1. TabbedPage https://learn.microsoft.com/en-us/dotnet/maui/user-interface/pages/tabbedpage
  2. Tab within Shell https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/shell/tabs

This proposed TabView would be a good addition and should be unrelated to Shell so there's freedom to use it elsewhere. For e.g. I want to use Shell and Flyout but I want tabs on one of the pages.

@Kapusch
Copy link

Kapusch commented Jun 9, 2023

Hi @JRosanowski , were you able to validate for the second point ?

@standamikes
Copy link

Any updates on this Proposal?

@VladislavAntonyuk
Copy link
Collaborator

Hello @ChaplinMarchais! I see you referenced some commits with this issue. What is your progress with the issue? Could you create a PR with your implementation? Do you need any help?

@smardine
Copy link

I'll be happy to help too

@VladislavAntonyuk
Copy link
Collaborator

VladislavAntonyuk commented Sep 26, 2023

I would suggest to investigate if it can be achived using InticatorView and CarouselView. if yes, we can close this proposal.
https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/indicatorview#define-indicator-appearance

@VladislavAntonyuk VladislavAntonyuk added the needs discussion Discuss it on the next Monthly standup label Sep 26, 2023
@bijington
Copy link
Contributor

I don't think the combination of CarouselView and IndicatorView will replicate the implementation from XCT. That being said the XCT had a lot of issues so I'm not against the idea of it does the bulk of the functionality

@VladislavAntonyuk
Copy link
Collaborator

@vhugogarcia
Copy link
Contributor

vhugogarcia commented Oct 31, 2023

I would suggest to investigate if it can be achived using InticatorView and CarouselView. if yes, we can close this proposal.

https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/indicatorview#define-indicator-appearance

Yes, I can confirm 1000% that a tabview system can be achieved by using CarouselView and Indicator View. I have developed apps simulating tabs with this approach and work fantastic!!

Also I have developed an app using CollectionView with horizontal scrolling simulating the tabs, then on each item selected I perform UI changes to show or hide content views.

Additionally, CarouselView and CollectionView allows you to perform loading on-demand, this means that you don't have to load all tabs contents at first load.

Alert!: While developing the apps, there are some performance impacts when loading the information while switching the position in a carousel view. So, for simple tabs where you render only a ListView/CollectionView with no heavy data it is fine. However, if what it renders is heavy, then this approach may not work.

I just wanted to share my grain of salt.

cc: @VladislavAntonyuk

@VladislavAntonyuk
Copy link
Collaborator

@vhugogarcia let's discuss it on standup. I will show different implementations. and we can decide together if we can close it or not

@vhugogarcia
Copy link
Contributor

@vhugogarcia let's discuss it on standup. I will show different implementations. and we can decide together if we can close it or not

sounds like a plan! Thanks @VladislavAntonyuk 😃

@VladislavAntonyuk
Copy link
Collaborator

TabView can be easily implemented using the combination of .NET MAUI controls, like CarouselView and IndicatorView; ContentView and RadioButton, HorizontalStackLayout and ContentView.
The different implementations can be found here:
https://github.com/VladislavAntonyuk/MauiSamples/tree/main/MauiTabView

@ghost ghost reopened this Nov 14, 2023
@ghost ghost closed this as completed Nov 14, 2023
@CommunityToolkit CommunityToolkit deleted a comment Nov 14, 2023
@VladislavAntonyuk VladislavAntonyuk removed the needs discussion Discuss it on the next Monthly standup label Nov 14, 2023
@sharpwood
Copy link

可以使用 .NET MAUI 控件(如 CarouselView 和 IndicatorView)的组合轻松实现 TabView;ContentView 和 RadioButton、HorizontalStackLayout 和 ContentView。可以在此处找到不同的实现: https://github.com/VladislavAntonyuk/MauiSamples/tree/main/MauiTabView

Since it is easy to implement and there is a high demand for it, why not package it more comprehensively and include it in the community toolkit?

@brminnick
Copy link
Collaborator Author

@sharpwood Feel free to submit us a Pull Request, complete with Unit Tests and Documentation!

@upswing1
Copy link

The toolkit would benefit greatly from having a tabview control instead of having thousands of custom implementations. A tabview control could then be used as the base control to expand functionality has a developer seems fit.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved This Proposal has been approved and is ready to be added to the Toolkit champion A member of the .NET MAUI Toolkit core team has chosen to champion this feature help wanted This proposal has been approved and is ready to be implemented pending documentation This feature requires documentation proposal A fully fleshed out proposal describing a new feature in syntactic and semantic detail
Projects
Development

No branches or pull requests