I'm implementing my own version of auto-complete feature in my Xamarin Forms 5 app where I display suggestions to user's entry in a ListView
.
The problem I'm running into is that I don't want ListView
to push down succeeding Entry
controls in the form. Instead, I'd like the ListView
to be above them. Is there a way to set the z-index of ListView
.
<Entry
Text="{Binding SearchText}"
Placeholder="Position you're applying for e.g. Director of Marketing"/>
<ListView
ItemsSource="{Binding Suggestions}"
IsVisible="{Binding ShowSuggestions}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding PositionName}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Entry
Text="{Binding Salary}"
Placeholder="Desired salary"/>
In this example, I don't want the "Salary" Entry
box to be pushed down when user gets suggestions.
P.S. I have a view model for this page so I'd like to handle things in the view model if I can as opposed to events in code behind for the page.
CodePudding user response:
I don't want the "Salary" Entry box to be pushed down when user gets suggestions.
Yes, you can use grid
to achieve this function, and set the Height of RowDefinition
to *
for the second row.
Please refer to the xaml code:
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Entry Text="{Binding SearchText}" Placeholder="Position you're applying for e.g. Director of Marketing"/>
<ListView Grid.Row="1"
ItemsSource="{Binding Suggestions}"
IsVisible="{Binding ShowSuggestions}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding PositionName}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Entry Text="{Binding Salary}" Placeholder="Desired salary" Grid.Row="2"/>
</Grid>
CodePudding user response:
You can use RelativeLayout to achieve the desired result:
<RelativeLayout x:Name="mainLayout">
<Entry
x:Name="searchEntry"
Text="{Binding SearchText}"
Placeholder="Position you're applying for e.g. Director of Marketing"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
Focused="SearchEntry_Focused"
Unfocused="SearchEntry_Unfocused"/>
<Frame
x:Name="searchList"
Padding="0"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, ElementName=searchEntry, Property=X}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=searchEntry, Property=Y, Constant=50}">
<ListView
ItemsSource="{Binding Suggestions}"
IsVisible="{Binding ShowSuggestions}"
ItemTapped="ListView_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding PositionName}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
<Entry
Text="{Binding Salary}"
Placeholder="Desired salary"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, ElementName=searchEntry, Property=X}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=searchEntry, Property=Y, Constant=50}"/>
</RelativeLayout>
Elements are linked to each other using constraints. Please read RelativeLayout Documentation for more info. I've wrapped ListView using a Frame for styling, you can also group together with the Entry to make it a reusable component.
And in your show/hide logic (Focused/Unfocused/ItemTapped or whatever) you need to call:
mainLayout.RaiseChild(searchList); // so list gets on top of other elements.
mainLayout.LowerChild(searchList); // list goes behind so you can interact with other elements again.
P.S. From RelativeLayout Documentation:
Avoid using a RelativeLayout whenever possible. It will result in the CPU having to perform significantly more work.
A RelativeLayout that uses relative values can position and size children so that they don't fit within the bounds of the layout.
So use with caution!