Reputation: 115
I'm trying to make an expandable ListView, but facing issues (not working) in Android and iOS (Works in UWP). Tried, many layouts and also tried to make a List inside the list and faced the same result. Android and iOS refuse to update the height of the Cell.
My Xaml
<ListView ItemsSource="{Binding groups}"
IsGroupingEnabled="true"
HasUnevenRows="False"
SelectionMode="None"
VerticalScrollBarVisibility="Never"
>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="5" VerticalOptions="FillAndExpand">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding HideShowItems}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>
<Label Text="{Binding GroupKey}" HorizontalOptions="Center" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" VerticalOptions="FillAndExpand"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="0" HeightRequest="{Binding rowHeight}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<BoxView Grid.Row="0" HorizontalOptions="FillAndExpand"
BackgroundColor="{Binding BtnColour}" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Command to handle the change
public Command HideShowItems => new Command(async (sender) =>
{
var dropDown = sender as DropDownMenu;
foreach(DropDownButton dr in dropDown)
{
if (dr.rowHeight > 0)
{
while(dr.rowHeight > 0)
{
dr.rowHeight = dr.rowHeight - 5;
await Task.Delay(5);
}
}
else
{
while(dr.rowHeight < 40)
{
dr.rowHeight = dr.rowHeight + 5;
await Task.Delay(5);
}
}
}
});
Tried quite a few examples found online and none seem to do it.
Still being in the learning stage, it would be helpful if you'd give a feedback when you see anything in the code that could be done better.
Many thanks!
Upvotes: 0
Views: 1795
Reputation: 158
Make sure that HasUnevenRows="true"
to your listview.HasUnevenRows property will be used to expand the cell height based on the content which is present in the cell.
Apply padding to Grid.
EX:<Grid Padding="5">
Upvotes: -1
Reputation: 115
I have created the needed logic using other Xamarin Forms. This is not to say I have answered the question about ListView and changes will probably need to be done by the Xamarin team, but this is what I came out with to create an expandable List.
XAML
<ScrollView x:Name="ScrollActivity" VerticalScrollBarVisibility="Never" >
<Grid x:Name="GridContent" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="80*"/>
</Grid.ColumnDefinitions>
<StackLayout BackgroundColor="#f0dfe2" x:Name="buttonHolder" BindableLayout.ItemsSource="{Binding sideMenu}" >
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout BackgroundColor="#f0dfe2">
<StackLayout HeightRequest="50" BackgroundColor="#38292c">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference buttonHolder}, Path=BindingContext.ShowHideCommand}"
CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<Label FontSize="Medium" HorizontalOptions="Center" VerticalOptions="Center" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="White" Text="{Binding title}"/>
</StackLayout>
<StackLayout HeightRequest="{Binding rowHeight}"
BindableLayout.ItemsSource="{Binding device}" >
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame Padding="0" CornerRadius="10">
<Frame.GestureRecognizers>
<PanGestureRecognizer PanUpdated="PanGestureRecognizer_PanUpdated_1">
</PanGestureRecognizer>
</Frame.GestureRecognizers>
<Grid HeightRequest="40" BackgroundColor="{Binding btnBkColour}" IsVisible="{Binding visibility}" >
<Label HorizontalOptions="Center" VerticalOptions="Center" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="White" Text="{Binding deviceTitle}" />
</Grid>
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout >
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout >
</Grid>
</ScrollView>
Command to handle expansion
public Command ShowHideCommand => new Command(async (sender) =>
{
var sideMenu = sender as SideMenuObject;
if (changeTriggered == false)
{
changeTriggered = true;
if (sideMenu.rowHeight > 0)
{
foreach (SideMenuDevice dev in sideMenu.device)
{
dev.visibility = false;
while (sideMenu.rowHeight >(sideMenu.device.Count - (sideMenu.device.IndexOf(dev) + 1))*40)
{
sideMenu.rowHeight = sideMenu.rowHeight - 5;
await Task.Delay(5);
}
}
}
else
{
foreach (SideMenuDevice dev in sideMenu.device)
{
while (sideMenu.rowHeight <= (sideMenu.device.IndexOf(dev) +1 ) *40)
{
sideMenu.rowHeight = sideMenu.rowHeight + 5;
await Task.Delay(5);
}
dev.visibility = true;
}
}
}
changeTriggered = false;
});
Please give feedback, if you can!
Upvotes: 0
Reputation: 10346
According to your description, you want to update ListView Row height, I suggest you can binding BoxView height instead of Grid.
From your code, I don't know about DropDownMenu, so I use Button click to change ListView Row, please take a look my code:
<StackLayout>
<ListView
HasUnevenRows="False"
IsGroupingEnabled="true"
ItemsSource="{Binding groups}"
SelectionMode="None"
VerticalScrollBarVisibility="Never">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="5" VerticalOptions="FillAndExpand">
<!--<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding HideShowItems}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>-->
<Label
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Text="{Binding GroupKey}"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid
Padding="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<BoxView
BackgroundColor="{Binding BtnColour}"
HeightRequest="{Binding rowHeight}"
HorizontalOptions="FillAndExpand" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
x:Name="btn1"
Clicked="Btn1_Clicked"
Text="change listview row height" />
</StackLayout>
public partial class Page1 : ContentPage
{
public ObservableCollection<GroupModel> groups { get; set; }
public Page1()
{
InitializeComponent();
groups = new ObservableCollection<GroupModel>();
var group1 = new GroupModel() { GroupKey = "Group 1 key" };
var group2 = new GroupModel() { GroupKey = "Group 2 key" };
group1.Add(new model1() { rowHeight = 20, BtnColour = Color.Red });
group1.Add(new model1() { rowHeight = 30, BtnColour = Color.Blue });
group1.Add(new model1() { rowHeight = 40, BtnColour = Color.Green });
group2.Add(new model1() { rowHeight = 20, BtnColour = Color.Gray });
group2.Add(new model1() { rowHeight = 30, BtnColour = Color.Black });
group2.Add(new model1() { rowHeight = 50, BtnColour = Color.Gold });
groups.Add(group1);
groups.Add(group2);
this.BindingContext = this;
}
private void Btn1_Clicked(object sender, EventArgs e)
{
groups[0][0].rowHeight = 60;
}
}
public class GroupModel:ObservableCollection<model1>
{
public string GroupKey { get; set; }
}
public class model1:ViewModelBase
{
private double _rowHeight;
public double rowHeight
{
get { return _rowHeight; }
set
{
_rowHeight = value;
RaisePropertyChanged("rowHeight");
}
}
public Color BtnColour { get; set; }
}
ViewModelBase is the class that implementing INotifyPropertychanged interface.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Upvotes: 0