Home > front end >  Setting z-index of ListView in Xamarin Forms app
Setting z-index of ListView in Xamarin Forms app

Time:03-28

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!

  • Related