I am trying to create a List with items structured as in the picture. I cant figure out how I should combine that kind of ListItem that can be expanded (see arrow) plus having the text fields like shown in the picture. On top of it I am trying to include so that each section of the list should have an header. Could somebody give me a hint of how to achieve the ListView as below:
I have created a control AwesomeView:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="BillingMobile.Controls.AwesomeView"> <ContentView.Content> <Frame> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid Grid.Row="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="75*"/> <ColumnDefinition Width="25*"/> </Grid.ColumnDefinitions> <Grid Grid.Column="0" ColumnSpacing="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="30*"/> <ColumnDefinition Width="70*"/> </Grid.ColumnDefinitions> <Image Grid.Column="0" x:Name="Image" BackgroundColor="Yellow" HeightRequest="60"/> <StackLayout Grid.Column="1" VerticalOptions="Center"> <Label x:Name="HeaderLabel" BackgroundColor="Yellow" FontSize="20"/> <Label x:Name="DescriptionLabel" BackgroundColor="Blue" FontSize="20"/> </StackLayout> </Grid> <Grid Grid.Column="1"> <StackLayout VerticalOptions="Center"> <Label x:Name="InfoLabel" HorizontalOptions="Center" FontSize="18" VerticalOptions="Center"/> <Button Text="Run" HorizontalOptions="Center" HeightRequest="40" FontSize="14" Padding="2"/> </StackLayout> </Grid> </Grid> <Button x:Name="ExpandButton" Grid.Row="1" BackgroundColor="Transparent" Clicked="OnExpandClicked" HorizontalOptions="Start" WidthRequest="30" HeightRequest="30"> <Button.ImageSource> <FileImageSource File="expand"/> </Button.ImageSource> </Button> <Frame Grid.Row="2" x:Name="ExpandableArea" BackgroundColor="Transparent" BorderColor="Black" IsVisible="False"> <Label Text="Google maps view"/> </Frame> </Grid> </Frame> </ContentView.Content> </ContentView> public partial class AwesomeView : ContentView { public static readonly BindableProperty IsExpandedProperty = BindableProperty.Create(nameof(IsExpanded), typeof(bool), typeof(AwesomeView), false, BindingMode.TwoWay, propertyChanged: OnIsExpandedChanged); public bool IsExpanded { get { return (bool)GetValue(IsExpandedProperty); } set { SetValue(IsExpandedProperty, value); } } public static readonly BindableProperty HeaderProperty = BindableProperty.Create(nameof(Header), typeof(string), typeof(AwesomeView), default(string), BindingMode.TwoWay, propertyChanged: OnHeaderChanged); public string Header { get { return (string)GetValue(HeaderProperty); } set { SetValue(HeaderProperty, value); } } public static readonly BindableProperty DescriptionProperty = BindableProperty.Create(nameof(Description), typeof(string), typeof(AwesomeView), default(string), BindingMode.TwoWay, propertyChanged: OnDescriptionChanged); public string Description { get { return (string)GetValue(DescriptionProperty); } set { SetValue(DescriptionProperty, value); } } public static readonly BindableProperty InfoProperty = BindableProperty.Create(nameof(Info), typeof(string), typeof(AwesomeView), default(string), BindingMode.TwoWay, propertyChanged: OnInfoChanged); public string Info { get { return (string)GetValue(InfoProperty); } set { SetValue(InfoProperty, value); } } public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create(nameof(ImageSource), typeof(ImageSource), typeof(AwesomeView), default(ImageSource), BindingMode.TwoWay, propertyChanged: OnImageSourceChanged); public ImageSource ImageSource { get { return (ImageSource)GetValue(IsExpandedProperty); } set { SetValue(IsExpandedProperty, value); } } public AwesomeView() { InitializeComponent(); } private void OnExpandClicked(object sender, EventArgs e) { this.IsExpanded = !this.IsExpanded; } private async Task HideExpandableContent() { this.ExpandButton.RotateTo(0, 250, Easing.CubicInOut); await this.ExpandableArea.FadeTo(0, 250, Easing.CubicInOut); this.ExpandableArea.IsVisible = false; } private async Task ShowExpandableContent() { this.ExpandableArea.IsVisible = true; await this.ExpandButton.RotateTo(180, 250, Easing.CubicInOut); await this.ExpandableArea.FadeTo(100, 500, Easing.CubicInOut); } private static async void OnIsExpandedChanged(BindableObject bindable, object oldValue, object newValue) { if (!(bindable is AwesomeView view)) { return; } bool isExpanded = Convert.ToBoolean(newValue); if (isExpanded) { await view.ShowExpandableContent(); } else { await view.HideExpandableContent(); } } private static void OnImageSourceChanged(BindableObject bindable, object oldValue, object newValue) { if (!(bindable is AwesomeView view)) { return; } view.Image.Source = (ImageSource)newValue; } private static void OnHeaderChanged(BindableObject bindable, object oldValue, object newValue) { if (!(bindable is AwesomeView view)) { return; } view.HeaderLabel.Text = (string)newValue; } private static void OnDescriptionChanged(BindableObject bindable, object oldValue, object newValue) { if (!(bindable is AwesomeView view)) { return; } view.DescriptionLabel.Text = (string)newValue; } private static void OnInfoChanged(BindableObject bindable, object oldValue, object newValue) { if (!(bindable is AwesomeView view)) { return; } view.InfoLabel.Text = (string)newValue; } }
I have attached used pictures.
Usage
In your ListView's ItemTemplate add this:
<controls:AwesomeView Header="{Binding Header}" Description="{Binding Description}" ImageSource="{Binding ImageSource}" Info="{Binding Info}"/>
Answers
Your text is Label or Entry?
I have created a control AwesomeView:
I have attached used pictures.
Usage
In your ListView's ItemTemplate add this:
<controls:AwesomeView Header="{Binding Header}" Description="{Binding Description}" ImageSource="{Binding ImageSource}" Info="{Binding Info}"/>
For grouping see this or this
https://github.com/xamarin/Xamarin.Forms/pull/9044
Syncfusion Sflistview has this option. You can use it if you like.
@igorkr_10 - What's the situation with expandable cells in ListView on iOS now? It used to be problematic, but I haven't tried it for quite a while so don't know if the problem was resolved.
I don't know. I develop only for android at this time
@igorkr_10
When I used the view like this:
<ListView ItemsSource="{Binding Items}"> <ListView.ItemTemplate> <DataTemplate> <local:AwesomeView /> </DataTemplate> </ListView.ItemTemplate> </ListView>
I get this exception:
What am I missing here?
at (wrapper castclass) System.Object.__castclass_with_cache(object,intptr,intptr) at Xamarin.Forms.Internals.TemplatedItemsList
2[TView,TItem].ActivateContent (System.Int32 index, System.Object item) [0x00000] inat Xamarin.Forms.Internals.TemplatedItemsList
2[TView,TItem].CreateContent (System.Int32 index, System.Object item, System.Boolean insert) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:543 at Xamarin.Forms.Internals.TemplatedItemsList
2[TView,TItem].GetOrCreateContent (System.Int32 index, System.Object item) [0x00023] inat Xamarin.Forms.Internals.TemplatedItemsList
2[TView,TItem].get_Item (System.Int32 index) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:337 at Xamarin.Forms.Platform.Android.ListViewAdapter.GetCellsFromPosition (System.Int32 position, System.Int32 take) [0x0003b] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:539 at Xamarin.Forms.Platform.Android.ListViewAdapter.GetCellForPosition (System.Int32 position) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:454 at Xamarin.Forms.Platform.Android.ListViewAdapter.GetView (System.Int32 position, Android.Views.View convertView, Android.Views.ViewGroup parent) [0x0006d] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:225 at Android.Widget.BaseAdapter.n_GetView_ILandroid_view_View_Landroid_view_ViewGroup_ (System.IntPtr jnienv, System.IntPtr native__this, System.Int32 position, System.IntPtr native_convertView, System.IntPtr native_parent) [0x0001a] in <f136c45b4a184119b54f2647ad4225f6>:0 at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.98(intptr,intptr,int,intptr,intptr)
Any idea on why this happens @igorkr_10 ?
CollectionView does not need ViewCell
Thanks for answering @igorkr_10
If I put the AwesomeView inside of a ViewCell it shows me empty default ListItems.
Cant understand what Im doing wrong. This is the code now:
<ListView ItemsSource="{Binding Items}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <local:AwesomeView /> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
Got it working. Thank you very much @igorkr_10
> Got it working. Thank you very much @igorkr_10
And what the problem was?
@igorkr_10 Adding the ViewCell element and raising the requested height so it became visible