Skip to content

Commit a7ea777

Browse files
Merge pull request #1142 from telerik/new-kb-tabview-line-break-header-tabs-fit-screen-dotnet-maui-7c57c2248b2c40209fcd40abc24adbc6
Added new kb article tabview-line-break-header-tabs-fit-screen-dotnet-maui
2 parents 1951258 + d7a6935 commit a7ea777

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
---
2+
title: Adding Line Breaks to Header Text and Fitting Tabs to Screen in TabView for .NET MAUI
3+
description: Learn how to add line breaks to header text and adjust tab widths to fit all tabs within the screen in TabView for .NET MAUI.
4+
type: how-to
5+
page_title: Adjusting Header Text and Tab Size in TabView for .NET MAUI
6+
slug: tabview-line-break-header-tabs-fit-screen-dotnet-maui
7+
tags: tabview, .net-maui, headertext, linebreak, fit-screen
8+
res_type: kb
9+
---
10+
11+
## Environment
12+
13+
| Version | Product | Author |
14+
| --- | --- | ---- |
15+
| 10.1.0 | Telerik UI for .NET MAUI TabView | [Dobrinka Yordanova](https://www.telerik.com/blogs/author/dobrinka-yordanova) |
16+
17+
## Description
18+
19+
I want to enable line breaks for the header text in the [TabView](https://docs.telerik.com/devtools/maui/controls/tabview/overview) component when the text is lengthy. Additionally, I need all tabs to fit within a single screen when there are multiple tabs.
20+
21+
This knowledge base article also answers the following questions:
22+
- How to make header text wrap in TabView for .NET MAUI?
23+
- How to fit all tabs within the screen in TabView for .NET MAUI?
24+
- How to customize tab headers in TabView for .NET MAUI?
25+
26+
## Solution
27+
28+
The solution suggested below shows how to enable line breaks in the header text and ensure all tabs fit within the screen.
29+
30+
### Step 1: Define a Custom Header Template
31+
32+
Create a `ControlTemplate` that enables line breaks in the header text. Use `LineBreakMode="WordWrap"` in the `Label` element to allow text wrapping.
33+
34+
```xml
35+
<VisualElement.Resources>
36+
<ControlTemplate x:Key="TabViewHeaderTemplate">
37+
<Grid local:TabViewUtils.EqualHeaderItemWidth="True" RowDefinitions="Auto, Auto">
38+
<Image Source="{TemplateBinding ImageSource}" Aspect="Center" />
39+
<Label Text="{TemplateBinding Text}" Grid.Row="1" LineBreakMode="WordWrap" HorizontalTextAlignment="Center" />
40+
</Grid>
41+
</ControlTemplate>
42+
</VisualElement.Resources>
43+
```
44+
45+
### Step 2: Use the Custom Header Template in RadTabView
46+
47+
Apply the custom header template to the TabView and define your tabs.
48+
49+
```xml
50+
<Grid>
51+
<telerik:RadTabView x:Name="tabView"
52+
HeaderItemTemplate="{StaticResource TabViewHeaderTemplate}">
53+
```
54+
55+
### Step 3: Add a Utility Class to Calculate Equal Widths for Tabs
56+
57+
Implement a custom utility class `TabViewUtils` to ensure equal widths for all tabs. The key property here is `EqualHeaderItemWidth`. This class dynamically calculates the width for each tab based on the total width of the TabView and the number of tabs.
58+
59+
Include the following utility class in your application code:
60+
61+
```csharp
62+
public static class TabViewUtils
63+
{
64+
public static readonly BindableProperty EqualHeaderItemWidthProperty = BindableProperty.Create("EqualHeaderItemWidth", typeof(bool), typeof(TabViewUtils), false, propertyChanged: OnEqualHeaderItemWidthChanged);
65+
66+
private static readonly BindableProperty SizeHelperProperty = BindableProperty.Create("SizeHelper", typeof(SizeHelper), typeof(TabViewUtils), null);
67+
private static readonly BindableProperty TabViewProperty = BindableProperty.Create("TabView", typeof(RadTabView), typeof(TabViewUtils), null, propertyChanged: OnTabViewChanged);
68+
69+
public static bool GetEqualHeaderItemWidth(BindableObject bindable) => (bool)bindable.GetValue(EqualHeaderItemWidthProperty);
70+
public static void SetEqualHeaderItemWidth(BindableObject bindable, bool value) => bindable.SetValue(EqualHeaderItemWidthProperty, value);
71+
72+
private static void OnEqualHeaderItemWidthChanged(BindableObject bindable, object oldValue, object newValue)
73+
{
74+
VisualElement visualElement = (VisualElement)bindable;
75+
76+
SizeHelper sizeHelper = (SizeHelper)visualElement.GetValue(SizeHelperProperty);
77+
if (sizeHelper != null)
78+
{
79+
sizeHelper.Disconnect();
80+
visualElement.SetValue(SizeHelperProperty, null);
81+
visualElement.RemoveBinding(TabViewUtils.TabViewProperty);
82+
}
83+
84+
if ((bool)newValue)
85+
{
86+
sizeHelper = new SizeHelper(visualElement);
87+
visualElement.SetValue(SizeHelperProperty, sizeHelper);
88+
visualElement.SetBinding(TabViewUtils.TabViewProperty, new Binding { Path = Binding.SelfPath, Source = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestor, typeof(RadTabView)) });
89+
}
90+
}
91+
92+
private static void OnTabViewChanged(BindableObject bindable, object oldValue, object newValue)
93+
{
94+
SizeHelper sizeHelper = (SizeHelper)bindable.GetValue(SizeHelperProperty);
95+
if (sizeHelper != null)
96+
{
97+
sizeHelper.TabView = newValue as RadTabView;
98+
}
99+
}
100+
101+
class SizeHelper
102+
{
103+
private VisualElement visualElement;
104+
private RadTabView tabView;
105+
private IList<TabViewItem> items;
106+
107+
public SizeHelper(VisualElement visualElement)
108+
{
109+
this.visualElement = visualElement;
110+
}
111+
112+
internal RadTabView TabView
113+
{
114+
set
115+
{
116+
if (this.tabView != value)
117+
{
118+
RadTabView oldValue = this.tabView;
119+
this.tabView = value;
120+
this.OnTabViewChanged(oldValue);
121+
}
122+
}
123+
}
124+
125+
private IList<TabViewItem> Items
126+
{
127+
set
128+
{
129+
if (this.items != value)
130+
{
131+
IList<TabViewItem> oldValue = this.items;
132+
this.items = value;
133+
this.OnItemsChanged(oldValue);
134+
}
135+
}
136+
}
137+
138+
internal void Disconnect()
139+
{
140+
if (this.visualElement != null)
141+
{
142+
this.visualElement = null;
143+
}
144+
145+
this.TabView = null;
146+
}
147+
148+
private void OnTabViewChanged(RadTabView oldValue)
149+
{
150+
if (oldValue != null)
151+
{
152+
oldValue.PropertyChanged -= this.TabView_PropertyChanged;
153+
}
154+
155+
if (this.tabView != null)
156+
{
157+
this.tabView.PropertyChanged += this.TabView_PropertyChanged;
158+
}
159+
160+
this.Items = this.tabView?.Items;
161+
}
162+
163+
private void OnItemsChanged(IList<TabViewItem> oldValue)
164+
{
165+
INotifyCollectionChanged incc = oldValue as INotifyCollectionChanged;
166+
167+
if (incc != null)
168+
{
169+
incc.CollectionChanged -= this.Items_CollectionChanged;
170+
}
171+
172+
incc = this.items as INotifyCollectionChanged;
173+
174+
if (incc != null)
175+
{
176+
incc.CollectionChanged += this.Items_CollectionChanged;
177+
}
178+
179+
this.UpdateSize();
180+
}
181+
182+
private void TabView_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs args)
183+
{
184+
if (args.PropertyName == nameof(this.tabView.Bounds) || args.PropertyName == nameof(this.tabView.Width))
185+
{
186+
this.UpdateSize();
187+
}
188+
else if (args.PropertyName == nameof(this.tabView.Items))
189+
{
190+
this.Items = this.tabView?.Items;
191+
}
192+
}
193+
194+
private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
195+
{
196+
this.UpdateSize();
197+
}
198+
199+
private void UpdateSize()
200+
{
201+
if (this.visualElement == null || this.tabView == null || this.items == null || this.tabView.Bounds.Width == -1)
202+
{
203+
return;
204+
}
205+
206+
int count = this.items.Count != 0 ? this.items.Count : 1;
207+
double newWidth = Math.Max((this.tabView.Bounds.Width / count) - 1, 10);
208+
this.visualElement.WidthRequest = newWidth;
209+
}
210+
}
211+
}
212+
213+
public static class LocalVisualTreeHelper
214+
{
215+
internal static T ParentOfType<T>(Element element)
216+
where T : Element
217+
{
218+
var parentElement = element.Parent;
219+
220+
while (parentElement != null)
221+
{
222+
var targetElement = parentElement as T;
223+
224+
if (targetElement != null)
225+
{
226+
return targetElement;
227+
}
228+
229+
parentElement = parentElement.Parent;
230+
}
231+
232+
return null;
233+
}
234+
}
235+
```
236+
237+
Now, set `local:TabViewUtils.EqualHeaderItemWidth="True"` in the header template to apply equal widths to all tabs.
238+
239+
## See Also
240+
241+
- [TabView Overview](https://docs.telerik.com/devtools/maui/controls/tabview/overview)

0 commit comments

Comments
 (0)