Skip to content

Commit 3824c6a

Browse files
Provided the EnableVirtualization property to the TabView control.
1 parent aeab265 commit 3824c6a

File tree

3 files changed

+167
-3
lines changed

3 files changed

+167
-3
lines changed

maui/src/TabView/Control/HorizontalContent/SfHorizontalContent.cs

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ internal partial class SfHorizontalContent : SfTabViewExt, ITouchListener, ITapG
3232
bool? _isTowardsRight;
3333
int _visibleItemCount;
3434
int _currentIndex;
35+
int _previousVisibleIndex;
36+
int _nextVisibleIndex;
3537
bool _isPreviousItemVisible;
3638
bool _isNextItemVisible;
3739
SelectionChangingEventArgs? _selectionChangingEventArgs;
@@ -103,6 +105,19 @@ internal partial class SfHorizontalContent : SfTabViewExt, ITouchListener, ITapG
103105
typeof(double),
104106
typeof(SfHorizontalContent),
105107
100d);
108+
109+
/// <summary>
110+
/// Identifies the <see cref="EnableVirtualization"/> bindable property.
111+
/// </summary>
112+
/// <value>
113+
/// The identifier for <see cref="EnableVirtualization"/> bindable property.
114+
/// </value>
115+
internal static readonly BindableProperty EnableVirtualizationProperty =
116+
BindableProperty.Create(
117+
nameof(EnableVirtualization),
118+
typeof(bool),
119+
typeof(SfHorizontalContent),
120+
false);
106121
#endregion
107122

108123
#region Properties
@@ -155,6 +170,18 @@ internal IList? ItemsSource
155170
set => SetValue(ItemsSourceProperty, value);
156171
}
157172

173+
/// <summary>
174+
/// Gets or sets a value indicating whether lazy loading is enabled during the initial load.
175+
/// </summary>
176+
/// <value>
177+
/// It accepts the bool values and the default value is false.
178+
/// </value>
179+
internal bool EnableVirtualization
180+
{
181+
get => (bool)GetValue(EnableVirtualizationProperty);
182+
set => SetValue(EnableVirtualizationProperty, value);
183+
}
184+
158185
/// <summary>
159186
/// Gets or sets the value that defines the content width of each tab header item.
160187
/// </summary>
@@ -373,6 +400,11 @@ void ClearTabContent(SfTabItem tabItem, int index)
373400
void UpdateSelectedIndex()
374401
{
375402
_isSelectionProcessed = true;
403+
if (EnableVirtualization)
404+
{
405+
LoadItemsContent(SelectedIndex);
406+
}
407+
376408
UpdateTabItemContentPosition();
377409
}
378410

@@ -439,10 +471,29 @@ void AddTabContentItems(SfTabItem item, int index = -1)
439471
{
440472
if (item.Content != null)
441473
{
442-
SfGrid parentGrid = CreateParentGrid(item);
474+
SfGrid parentGrid = new();
475+
476+
if (!EnableVirtualization || (EnableVirtualization && !(index != SelectedIndex && item.IsVisible)))
477+
{
478+
parentGrid = CreateParentGrid(item);
479+
}
480+
443481
if (index >= 0)
444482
{
445-
_horizontalStackLayout?.Children.Insert(index, parentGrid);
483+
if (EnableVirtualization && index != SelectedIndex && item.IsVisible)
484+
{
485+
var content = new BoxView
486+
{
487+
WidthRequest = 0,
488+
HeightRequest = 0,
489+
Opacity = 0
490+
};
491+
_horizontalStackLayout?.Children.Insert(index, content);
492+
}
493+
else
494+
{
495+
_horizontalStackLayout?.Children.Insert(index, parentGrid);
496+
}
446497
}
447498
else
448499
{
@@ -849,6 +900,12 @@ void AdjustForFirstIndex(double difference)
849900
{
850901
if (_horizontalStackLayout != null && IsTowardsRight == true)
851902
{
903+
if (EnableVirtualization)
904+
{
905+
var index = _nextVisibleIndex;
906+
LoadItemsContent(index);
907+
}
908+
852909
#if !WINDOWS
853910
if (((this as IVisualElementController).EffectiveFlowDirection & EffectiveFlowDirection.RightToLeft) != EffectiveFlowDirection.RightToLeft)
854911
_horizontalStackLayout.TranslationX = Math.Clamp(_horizontalStackLayout.TranslationX + difference, -ContentWidth, 0);
@@ -866,6 +923,17 @@ void AdjustForMiddleIndices(double difference)
866923
{
867924
if (_isPreviousItemVisible && _isNextItemVisible)
868925
{
926+
if (EnableVirtualization)
927+
{
928+
int index = -1;
929+
if (IsTowardsRight is not null)
930+
{
931+
index = IsTowardsRight == true ? _nextVisibleIndex : _previousVisibleIndex;
932+
}
933+
934+
LoadItemsContent(index);
935+
}
936+
869937
#if !WINDOWS
870938
if (((this as IVisualElementController).EffectiveFlowDirection & EffectiveFlowDirection.RightToLeft) != EffectiveFlowDirection.RightToLeft)
871939
_horizontalStackLayout.TranslationX = Math.Clamp(_horizontalStackLayout.TranslationX + difference, -ContentWidth * (_currentIndex + 1), -ContentWidth * (_currentIndex - 1));
@@ -877,6 +945,12 @@ void AdjustForMiddleIndices(double difference)
877945
}
878946
else if (_isPreviousItemVisible)
879947
{
948+
if (EnableVirtualization)
949+
{
950+
var index = _previousVisibleIndex;
951+
LoadItemsContent(index);
952+
}
953+
880954
#if !WINDOWS
881955
if (((this as IVisualElementController).EffectiveFlowDirection & EffectiveFlowDirection.RightToLeft) != EffectiveFlowDirection.RightToLeft)
882956
_horizontalStackLayout.TranslationX = Math.Clamp(_horizontalStackLayout.TranslationX + difference, -ContentWidth * _currentIndex, -ContentWidth * (_currentIndex - 1));
@@ -888,6 +962,12 @@ void AdjustForMiddleIndices(double difference)
888962
}
889963
else if (_isNextItemVisible)
890964
{
965+
if (EnableVirtualization)
966+
{
967+
var index = _nextVisibleIndex;
968+
LoadItemsContent(index);
969+
}
970+
891971
#if !WINDOWS
892972
if (((this as IVisualElementController).EffectiveFlowDirection & EffectiveFlowDirection.RightToLeft) != EffectiveFlowDirection.RightToLeft)
893973
_horizontalStackLayout.TranslationX = Math.Clamp(_horizontalStackLayout.TranslationX + difference, -ContentWidth * (_currentIndex + 1), -ContentWidth * _currentIndex);
@@ -904,6 +984,15 @@ void AdjustForLastIndex(double difference)
904984
{
905985
if (_horizontalStackLayout != null)
906986
{
987+
if (EnableVirtualization)
988+
{
989+
var index = _previousVisibleIndex;
990+
if (IsTowardsRight is false)
991+
{
992+
LoadItemsContent(index);
993+
}
994+
}
995+
907996
#if !WINDOWS
908997
if (((this as IVisualElementController).EffectiveFlowDirection & EffectiveFlowDirection.RightToLeft) != EffectiveFlowDirection.RightToLeft)
909998
_horizontalStackLayout.TranslationX = Math.Clamp(_horizontalStackLayout.TranslationX + difference, -ContentWidth * (_visibleItemCount - 1), -ContentWidth * (_visibleItemCount - 2));
@@ -915,6 +1004,24 @@ void AdjustForLastIndex(double difference)
9151004
}
9161005
}
9171006

1007+
/// <summary>
1008+
/// This method is used to replace the placeholder view with a tab item when the EnableVirtualization is true.
1009+
/// </summary>
1010+
/// <param name="index">This index position of the child in the HorizontalStackLayout to replaced with a tab item.</param>
1011+
void LoadItemsContent(int index)
1012+
{
1013+
if (_horizontalStackLayout != null)
1014+
{
1015+
if (Items is not null && index >= 0 && index < _horizontalStackLayout.Children.Count && _horizontalStackLayout.Children[index] is BoxView)
1016+
{
1017+
SfGrid parentGrid = CreateParentGrid(Items[index]);
1018+
_horizontalStackLayout?.Children.RemoveAt(index);
1019+
_horizontalStackLayout?.Children.Insert(index, parentGrid);
1020+
UpdateDynamicChanges();
1021+
}
1022+
}
1023+
}
1024+
9181025
/// <summary>
9191026
/// This method is used to update the tab item position after swipe complete.
9201027
/// </summary>
@@ -1377,6 +1484,7 @@ void UpdateVisibilityWithoutTemplate()
13771484
if (Items[i].IsVisible == true)
13781485
{
13791486
_isNextItemVisible = true;
1487+
_nextVisibleIndex = i;
13801488
break;
13811489
}
13821490
}
@@ -1386,6 +1494,7 @@ void UpdateVisibilityWithoutTemplate()
13861494
if (Items[i].IsVisible == true)
13871495
{
13881496
_isPreviousItemVisible = true;
1497+
_previousVisibleIndex = i;
13891498
break;
13901499
}
13911500
}

maui/src/TabView/Control/SfTabBar.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,11 @@ internal void UpdateSelectedIndex(int newIndex, int oldIndex)
720720
{
721721
if (newIndex != -1)
722722
{
723-
_isSelectionProcessed = true;
723+
if (IsLoaded)
724+
{
725+
_isSelectionProcessed = true;
726+
}
727+
724728
UpdateSelectedTabItemIsSelected(newIndex, oldIndex);
725729
UpdateTabIndicatorWidth();
726730
if (_tabSelectionChangedEventArgs != null)

maui/src/TabView/Control/SfTabView.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,17 @@ public class SfTabView : ContentView, IParentThemeElement
306306
BindingMode.Default,
307307
null);
308308

309+
/// <summary>
310+
/// Identifies the <see cref="EnableVirtualization"/> bindable property.
311+
/// </summary>
312+
public static readonly BindableProperty EnableVirtualizationProperty =
313+
BindableProperty.Create(
314+
nameof(EnableVirtualization),
315+
typeof(bool),
316+
typeof(SfTabView),
317+
false,
318+
propertyChanged: OnEnableVirtualizationChanged);
319+
309320
static readonly BindableProperty IsContentTransitionEnabledProperty =
310321
BindableProperty.Create(
311322
nameof(IsContentTransitionEnabled),
@@ -1257,6 +1268,32 @@ public double ContentTransitionDuration
12571268
set => SetValue(ContentTransitionDurationProperty, value);
12581269
}
12591270

1271+
/// <summary>
1272+
/// Gets or sets a value indicating whether lazy loading is enabled during the initial load.
1273+
/// </summary>
1274+
/// <value>
1275+
/// A boolean value indicating whether lazy loading is enabled. The default value is false.
1276+
/// </value>
1277+
/// <example>
1278+
/// Here is an example of how to set the <see cref="EnableVirtualization"/> property.
1279+
///
1280+
/// # [XAML](#tab/tabid-1)
1281+
/// <code><![CDATA[
1282+
/// <tabView:SfTabView EnableVirtualization="True" />
1283+
/// ]]></code>
1284+
///
1285+
/// # [C#](#tab/tabid-2)
1286+
/// <code><![CDATA[
1287+
/// SfTabView tabView = new SfTabView();
1288+
/// tabView.EnableVirtualization = true;
1289+
/// ]]></code>
1290+
/// </example>
1291+
public bool EnableVirtualization
1292+
{
1293+
get => (bool)GetValue(EnableVirtualizationProperty);
1294+
set => SetValue(EnableVirtualizationProperty, value);
1295+
}
1296+
12601297
/// <summary>
12611298
/// Gets or sets a value that can be used to customize the scroll button’s background color in the <see cref="SfTabView"/>.
12621299
/// </summary>
@@ -1557,6 +1594,11 @@ internal void RaiseSelectionChangingEvent(SelectionChangingEventArgs args)
15571594
/// </summary>
15581595
static void OnFontAutoScalingEnabledChanged(BindableObject bindable, object oldValue, object newValue) => (bindable as SfTabView)?.UpdateFontAutoScalingEnabled((Boolean)newValue);
15591596

1597+
/// <summary>
1598+
/// Handles changes to the <see cref="EnableVirtualization"/> property.
1599+
/// </summary>
1600+
static void OnEnableVirtualizationChanged(BindableObject bindable, object oldValue, object newValue) => (bindable as SfTabView)?.UpdateEnableVirtualization();
1601+
15601602
#endregion
15611603

15621604
#region Private Methods
@@ -1955,6 +1997,15 @@ void UpdateFontAutoScalingEnabled(bool newValue)
19551997
}
19561998
}
19571999

2000+
/// <summary>
2001+
/// Updates the enable virtualization.
2002+
/// </summary>
2003+
void UpdateEnableVirtualization()
2004+
{
2005+
if (_tabContentContainer != null)
2006+
_tabContentContainer.EnableVirtualization = EnableVirtualization;
2007+
}
2008+
19582009
/// <summary>
19592010
/// Gets the theme dictionary for the tab view.
19602011
/// </summary>

0 commit comments

Comments
 (0)