Category / Section
How to bring the entire item into view on tapping an item in xamarin.forms expandable listview?
3 mins read
You can bring an item into view by calling ScrollToRowIndex method. This article explains how to create expandable listview and how to bring the listview item into view when its being expanded.
In the below code, ItemTemplate of ListView is defined to show or hide additional view based on IsVisible property in Model class (namely Contact).
Xaml
<ContentPage xmlns:sflistview="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms">
<ContentPage.Content>
<Grid x:Name="mainGrid">
<sflistview:SfListView x:Name="listView" AutoFitMode="DynamicHeight">
< sflistview:SfListView.Behaviors>
<local:SfListViewAccordionBehavior />
</ sflistview:SfListView.Behaviors>
<sflistview:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid >
<Frame x:Name="frame">
<Grid>
<Grid x:Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid RowSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Source="{Binding ContactImage}" />
<Grid Grid.Row="0" Grid.Column="1" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Text="{Binding ContactName}">
</Label>
<Label Grid.Row="1" Text="{Binding CallTime}">
</Label>
</Grid>
<Grid Grid.Row="0" Grid.Column="2" >
<Image Source="{Binding PhoneImage}" />
</Grid>
</Grid>
</Grid>
<Grid IsVisible="{Binding IsVisible, Mode=TwoWay}">
<Grid.RowDefinitions>
<RowDefinition Height="1" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<BoxView Grid.Row="0" Grid.Column="0"/>
<Image Grid.Row="1" Grid.Column="0" Source="{Binding NewContact}" />
<Image Grid.Row="2" Grid.Column="0" Source="{Binding AddContact}" />
<Image Grid.Row="3" Grid.Column="0" Source="{Binding SendMessage}" />
<Image Grid.Row="4" Grid.Column="0" Source="{Binding BlockSpan}" />
<Image Grid.Row="5" Grid.Column="0" Source="{Binding CallDetails}"/>
<BoxView Grid.Row="0" Grid.Column="1"/>
<Label Grid.Row="1" Grid.Column="1" Text="Create new contact"/>
<Label Grid.Row="2" Grid.Column="1" Text="Add to a contact"/>
<Label Grid.Row="3" Grid.Column="1" Text="Send a message"/>
<Label Grid.Row="4" Grid.Column="1" Text="Block/report Spam"/>
<Label Grid.Row="5" Grid.Column="1" Text="Call details"/>
</Grid>
</Grid>
</Frame>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</sflistview:SfListView.ItemTemplate>
</sflistview:SfListView>
</Grid>
</ContentPage.Content>
</ContentPage>
Also, code added to change the IsVisible when listview item is tapped. Now expandable listview is ready.
C#
namespace AutoFit
{
internal class SfListViewAccordionBehavior : Behavior<SfListView>
{
public SfListViewAccordionBehavior()
{
AccordionViewModel = new AccordionViewModel();
}
protected override void OnAttachedTo(ContentPage bindable)
{
listview = bindable.FindByName<Syncfusion.ListView.XForms.SfListView>("listView");
listview.ItemsSource = AccordionViewModel.ContactsInfo;
listview.ItemTapped += ListView_ItemTapped;
}
private void ListView_ItemTapped(object sender, Syncfusion.ListView.XForms.ItemTappedEventArgs e)
{
if (tappedItem != null && tappedItem.IsVisible)
{
tappedItem.IsVisible = false;
}
if (tappedItem == ItemData )
{
tappedItem = null;
return;
}
tappedItem = ItemData;
tappedItem.IsVisible = true;
}
}
}
Now, you can call ScrollToRowIndex method when an item is tapped and bring that item into view if it is not fully visible.
C#
namespace AutoFit
{
internal class SfListViewAccordionBehavior : Behavior<SfListView>
{
protected override void OnAttachedTo(ContentPage bindable)
{
listview = bindable.FindByName<Syncfusion.ListView.XForms.SfListView>("listView");
listview.ItemsSource = AccordionViewModel.ContactsInfo;
listview.ItemTapped += ListView_ItemTapped;
}
private void ListView_ItemTapped(object sender, Syncfusion.ListView.XForms.ItemTappedEventArgs e)
{
visibleLines = this.listview.GetVisualContainer().ScrollRows.GetVisibleLines();
var tappedItemIndex = listview.DataSource.DisplayItems.IndexOf(e.ItemData as Contact);
if (visibleLines.Count <= 0)
return;
var endIndex = visibleLines[visibleLines.LastBodyVisibleIndex].LineIndex;
if (tappedItemIndex == endIndex)
{
Device.BeginInvokeOnMainThread(async () =>
{
await Task.Delay(200);
(listview.LayoutManager as LinearLayout).ScrollToRowIndex(tappedItemIndex, Syncfusion.ListView.XForms.ScrollToPosition.End, true);
});
}
}
}
}