Closed brminnick closed 1 year ago
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!
Thanks @ChaplinMarchais! That'd be fantastic!
I'll assign this to you 👍
@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!
Yup! That looks good 👍
I really like how https://github.com/roubachof/Sharpnado.Tabs approaches this control. It decouples tab view items from TabStrip and only binds them together through SelectedIndex property. This enables a lot of flexibility, such as implementing a custom tab switching through buttons (if I want my tabs to look like android chips controls). What I lack in most TabView controls is the ability to switch out how the TabStrip is visualy represented - sometimes I want to underline the text, sometimes highlight an icon etc. Setting a TabStripPlacement and TextColorSelected just doesn't cut it sometimes. Would it be worth exploring more flexible options?
How's this coming along? I've been trying to roll my own tab view but it feels like it's held together with popsicle sticks and glue...
How's this coming along? I've been trying to roll my own tab view but it feels like it's held together with popsicle sticks and glue...
The description shows that this has not been started yet. This sadly won't make it in to our first official release because we are in a feature freeze ready so it won't be ready any time soon.
We would love your help writing the code! The Community Toolkit contains features for, and created by, the .NET MAUI Community. We are all volunteers, contributing code in our spare time on nights and weekends. If you'd like to contribute, you can learn more here: https://devblogs.microsoft.com/dotnet/contributing-to-net-maui-community-toolkit/
Hello TabView and LazyView are crazy needed especially for the people who are using basic navigation, and want to have fully customized tabs. Looking forward to it <3
Since it's not going to be in the first release, I downloaded the Xamarin community toolkit sample code and isolated the TabView and lazy view parts, then refactored them to work with maui. It took about 2 work days but wasn't too hard. Its really just a Grid with a carousel view and another grid (as the tab bar). The hard part was simulating stack navigation within a "tab"
Here's the lazy view code:
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
namespace Xamarin.CommunityToolkit.UI.Views
{
/// <summary>
/// Abstract base class for <see cref="LazyView{TView}"/>
/// Taken from Xamarin's community toolkit to use with their Tabview
/// <notes>
/// Eamonn Alphin: April 2022: Imported and refactored to work.
/// </notes>
/// </summary>
public abstract class BaseLazyView : ContentView, IDisposable
{
internal static readonly BindablePropertyKey IsLoadedPropertyKey = BindableProperty.CreateReadOnly(nameof(IsLoaded), typeof(bool), typeof(BaseLazyView), default);
/// <summary>
/// This is a read-only <see cref="BindableProperty"/> that indicates when the view is loaded.
/// </summary>
public static readonly BindableProperty IsLoadedProperty = IsLoadedPropertyKey.BindableProperty;
/// <summary>
/// This is a read-only property that indicates when the view is loaded.
/// </summary>
public new bool IsLoaded => (bool)GetValue(IsLoadedProperty);
/// <summary>
/// This method change the value of the <see cref="IsLoaded"/> property.
/// </summary>
/// <param name="isLoaded"></param>
protected void SetIsLoaded(bool isLoaded) => SetValue(IsLoadedPropertyKey, isLoaded);
/// <summary>
/// Use this method to do the initialization of the <see cref="View"/> and change the status IsLoaded value here.
/// </summary>
/// <returns><see cref="ValueTask"/></returns>
public abstract ValueTask LoadViewAsync();
/// <summary>
/// This method dispose the <see cref="ContentView.Content"/> if it's <see cref="IDisposable"/>.
/// </summary>
public void Dispose()
{
if (Content is IDisposable disposable)
{
disposable.Dispose();
GC.SuppressFinalize(this); //todo: check this if lazy loaded views aren't getting disposed correctly.
}
}
protected override void OnBindingContextChanged()
{
if (Content is not null and not ActivityIndicator)
{
Content.BindingContext = BindingContext;
}
}
}
}
using System.Threading.Tasks;
namespace Xamarin.CommunityToolkit.UI.Views
{
/// <summary>
/// This a basic implementation of the LazyView based on <see cref="BaseLazyView"/> use this an exemple to create yours
/// </summary>
/// <notes>
/// Eamonn Alphin April 2022: Imported and refactored.
/// </notes>
/// <typeparam name="TView">Any <see cref="View"/></typeparam>
public class LazyView<TView> : BaseLazyView where TView : View, new()
{
/// <summary>
/// This method initializes your <see cref="LazyView{TView}"/>.
/// </summary>
/// <returns><see cref="ValueTask"/></returns>
public override ValueTask LoadViewAsync()
{
View view = new TView { BindingContext = BindingContext };
Content = view;
SetIsLoaded(true);
return new ValueTask(Task.FromResult(true));
}
}
}
@eamonn-alphin that is interesting to hear! Would you be willing to assist with the TabView implementation in the toolkit?
My fear with the TabView
is that there are a lot of issues open against the Xamarin Community Toolkit which we should look to avoid inheriting https://github.com/xamarin/XamarinCommunityToolkit/issues?q=is%3Aissue+is%3Aopen+tabview+
Extending the @bijington comment, if you want to do the migration of the LazyView
to here, you're more than welcome <3
Here's the issue for lazy view #112
@eamonn-alphin that is interesting to hear! Would you be willing to assist with the TabView implementation in the toolkit?
My fear with the
TabView
is that there are a lot of issues open against the Xamarin Community Toolkit which we should look to avoid inheriting https://github.com/xamarin/XamarinCommunityToolkit/issues?q=is%3Aissue+is%3Aopen+tabview+
I'm willing to share the code I have for the sake of helping better minds than mine move tabviews along, but it still comes with whatever issues the latest Xamarin CT version has. But it runs at least.
Thanks @eamonn-alphin!
We would love your help writing the code! The Community Toolkit contains features for, and created by, the .NET MAUI Community. We are all volunteers, contributing code in our spare time on nights and weekends. If you'd like to contribute, you can learn more here: https://devblogs.microsoft.com/dotnet/contributing-to-net-maui-community-toolkit/
For future reference, you don’t need to copy/paste any code from Xamarin.CommunityToolkit
to get to work with .NET MAUI. We created Xamarin.CommunityToolkit.MauiCompat
which is the exact Xamarin.CommunityToolkit library ported to .NET MAUI: https://devblogs.microsoft.com/xamarin/introducing-net-maui-compatibility-for-the-xamarin-community-toolkit
FYI - I’m hiding the LazyView comments as “off-topic” to avoid creating noise for future devs interested in helping with this TabView Proposal
I would like to implement this by porting the old TabView with some upgrades but first I need this issue to be fixed - https://github.com/dotnet/maui/issues/6412
@ChaplinMarchais What is the status of your progress? Would you like to continue working on TabView, or would you prefer to hand off the work to another developer?
@brminnick
For future reference, you don’t need to copy/paste any code from Xamarin.CommunityToolkit to get to work with .NET MAUI. We created Xamarin.CommunityToolkit.MauiCompat which is the exact Xamarin.CommunityToolkit library ported to .NET MAUI:
It doesn't work, unfortunately... https://github.com/xamarin/XamarinCommunityToolkit/issues/1873
And @VladislavAntonyuk mentions here, that it's not possible to use it at all, if I understand that correctly: https://github.com/xamarin/XamarinCommunityToolkit/issues/1750#issuecomment-985645536
@ChaplinMarchais @brminnick Will this component be compatible with Shell Navigation?
Since it's not going to be in the first release, I downloaded the Xamarin community toolkit sample code and isolated the TabView and lazy view parts, then refactored them to work with maui. It took about 2 work days but wasn't too hard. Its really just a Grid with a carousel view and another grid (as the tab bar). The hard part was simulating stack navigation within a "tab"
@eamonn-alphin this sounds awesome. Do you have a code sample you would be happy to share please? I am still in XF but I have a large maui refactor on the horizon, so I am wary to add a dependency to something from the XF toolkit that will be unsupported when going to MAUI.
btw for someone wanting a XF and Maui compatible solution now (Oct 2022) there is https://github.com/roubachof/Sharpnado.Tabs
btw for someone wanting a XF and Maui compatible solution now (Oct 2022) there is https://github.com/roubachof/Sharpnado.Tabs
That's indeed a very powerful implementation. However, it is not compatible with Shell and uses Views instead of Pages. I do not regard it as a substitute for the native Shell.TabBar
@ChaplinMarchais What is the status of your progress? Would you like to continue working on TabView, or would you prefer to hand off the work to another developer?
@brminnick Sorry about going totally MIA! Life ended up throwing some major personal things my way. Long story short I wasn't able to get access to a computer for the last 5 months or so. That being said, I will begin work again on the implementation for this proposal!
@ChaplinMarchais glad to have you back!
@ChaplinMarchais @brminnick Will this component be compatible with Shell Navigation?
@ewerspej What exactly do you mean, as far as functionality goes, by "compatible"? Are you looking for the TabView
to generate ShellContent
items for the Shell
or just to have the TabView
integrate your navigation history with the Shell
? A little bit more detail would help to determine the feasibility of integrating with this feature!
@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.
@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?
Any updates on this issue?
Any updates on this issue?
It doesn't look like it. Would you be willing to provide assistance?
@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
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.
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.
Hi @JRosanowski , were you able to validate for the second point ?
Any updates on this Proposal?
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?
I'll be happy to help too
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
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
possible solutions: https://github.com/VladislavAntonyuk/MauiSamples/tree/main/MauiTabView
I would suggest to investigate if it can be achived using InticatorView and CarouselView. if yes, we can close this proposal.
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
@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 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 😃
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
可以使用 .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?
@sharpwood Feel free to submit us a Pull Request, complete with Unit Tests and Documentation!
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.
TabView
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
Usage Syntax
XAML Usage
C# Usage