Последние элементы списка не отображаются при реализации нижнего листа в формах Xamarin

#xamarin.forms #bottom-sheet

Вопрос:

Я попытался реализовать нижний лист для своего приложения Xamarin forms. Я реализовал несколько методов, включая nugets. В моем основном представлении сзади у меня есть представление списка. На нижнем листе обычные рамки и надписи. Моя проблема в том, что последние один или два элемента не отображаются или частично отображаются в представлении списка почти во всех вариантах.

     <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:yummy="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView" 
                 x:Class="RSMapp.Views.RSMview">
        <ContentPage.ToolbarItems>
            <ToolbarItem Name="MenuItem" Command="{Binding filterCommand}" Order="Primary" Icon="filter.png" Text="" Priority="0" IsEnabled="{Binding IsEnabled}" />
        </ContentPage.ToolbarItems>
        <ContentPage.Content>
    
            <RelativeLayout>
    
                <StackLayout BackgroundColor="#d4d4d4" x:Name="mainView" Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand">
    
                    <Grid RowSpacing="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="70"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
    
                        <yummy:PancakeView HeightRequest="55" BackgroundColor="{Binding mainBgColor}" Padding="10" HorizontalOptions="FillAndExpand" x:Name="dropdownLayout" CornerRadius="0,0,15,15" VerticalOptions="CenterAndExpand" Grid.Row="0">
    
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="AUTO"/>
                                </Grid.ColumnDefinitions>
    
                                <Frame IsVisible="{Binding isMonthVisible}" HasShadow="{OnPlatform Android=true, iOS=false}" HorizontalOptions="FillAndExpand" BackgroundColor="WhiteSmoke" Padding="10,0,10,0" CornerRadius="15" Grid.Column="0">
    
                                    <Picker                            
                                            Title="{Binding SelectedItem.mName}"
                                            IsVisible="{Binding isMonthVisible}"   
                                            TitleColor="Black"   
                                            VerticalTextAlignment="Center"
                                            Margin="0,0,20,0"
                                            Focused="Picker_Focused"
                                            TextColor="#565656"                      
                                            ItemsSource="{Binding MyList}"
                                            SelectedItem="{Binding SelectedItem}"
                                            ItemDisplayBinding="{Binding mName}" />
    
                                </Frame>
    
                                <StackLayout WidthRequest="60" IsVisible="{Binding extraBtnVisible}" VerticalOptions="Center" HorizontalOptions="Center" Grid.Column="1">
                                    <ImageButton HeightRequest="50" WidthRequest="30" Command="{Binding regionClassCommand}" VerticalOptions="Center" IsVisible="{Binding extraBtnVisible}" BackgroundColor="#F44336" Source="extra.png"/>
                                </StackLayout>
    
                            </Grid>
    
                        </yummy:PancakeView>
    
                        <StackLayout BackgroundColor="#d4d4d4" Grid.Row="1" Orientation="Vertical">
    
                            <ListView IsVisible="{Binding hasLifeData}" ItemTapped="RSMListView_ItemTapped" 
                                  SeparatorVisibility="None" 
                                  IsPullToRefreshEnabled="False"
                                  ItemsSource="{Binding rsmLifeRankingList}" 
                                  x:Name="RSMListView" 
                                  Margin="0,0,0,2"
                                  HasUnevenRows="True">
                                <ListView.ItemTemplate>
                                    <DataTemplate>
                                        <ViewCell>
    
                                            <Frame Margin="2,4,2,4" BackgroundColor="White" IsVisible="True" HasShadow="{OnPlatform Android='true',iOS='false'}" CornerRadius="10" Padding="2,4,2,4">
    
                                                <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="White" Orientation="Vertical">
    
                                                </StackLayout>
    
                                            </Frame>
    
                                        </ViewCell>
                                    </DataTemplate>
                                </ListView.ItemTemplate>
                            </ListView>
    
                            <StackLayout IsVisible="{Binding noData}" HorizontalOptions="CenterAndExpand" VerticalOptions="StartAndExpand">
    
                                <Image Source="nodata" HorizontalOptions="Center"/>
    
                            </StackLayout>
    
                        </StackLayout>
    
                    </Grid>
    
                </StackLayout>
    
                <yummy:PancakeView CornerRadius="10,10,0,0" Padding="0" BackgroundColor="#faf9f8"
                         x:Name="bottomSheet" RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
                            Property=Height,Factor=.96,Constant=0}" RelativeLayout.WidthConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Width,Factor=1,Constant=0}" RelativeLayout.HeightConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Height,Factor=1,Constant=0}">
                    <yummy:PancakeView.GestureRecognizers>
                        <PanGestureRecognizer PanUpdated="OnPanUpdated" />
                    </yummy:PancakeView.GestureRecognizers>
                    <StackLayout BackgroundColor="Gray" Spacing="0">
    
                        <BoxView HeightRequest="5" CornerRadius="2" Margin="0,6,0,8" WidthRequest="80" BackgroundColor="LightGray" HorizontalOptions="Center"/>
    
                        <StackLayout Orientation="Vertical">
    
                            <StackLayout IsVisible="{Binding hasLifeData}" BackgroundColor="WhiteSmoke" Orientation="Vertical" Grid.Row="1">
    
                                <StackLayout IsVisible="{Binding layoutVisible}" Spacing="0" Orientation="Vertical">
    
                                    <yummy:PancakeView Padding="10,0,10,10" CornerRadius="0,0,15,15" BackgroundColor="{StaticResource colorLife}">
    
                                        <StackLayout Orientation="Vertical">
    
    
                                        </StackLayout>
    
                                    </yummy:PancakeView>
    
                                    <ScrollView Padding="0,5,0,5">
    
                                        <StackLayout Margin="2,0,2,0" Orientation="Vertical">
    
    
    
                                        </StackLayout>
    
                                    </ScrollView>
    
                                </StackLayout>
    
                            </StackLayout>
    
                        </StackLayout>
    
                    </StackLayout>
                </yummy:PancakeView>
    
            </RelativeLayout>
    
        </ContentPage.Content>
    </ContentPage>
 

Код за

     public partial class RSMview : ContentPage
    {
        private RSMViewModel vm;
        private string company;
        private string lifColor = "#f2b22c";
        private double x, y;
    
        public RSMview()
        {
            InitializeComponent();
        }
    
        public RSMview(string company, string userRegion)
        {
            InitializeComponent();
    
            this.company = company;
    
            BindingContext = new RSMViewModel();
            vm = BindingContext as RSMViewModel;
    
            Title = userRegion   " (RSM)";
    
            ToolbarStatusBarTheme.ToolbarWithStatusBar(company);
    
            if (NetworkCheck.IsInternet())
            {
                if (company.Equals("G"))
                {
    
                    dropdownLayout.BackgroundColor = Color.FromHex(genColor);
                    vm.GetGenRSMData(userRegion, "G");
    
                }
                else if (company.Equals("L"))
                {
    
                    dropdownLayout.BackgroundColor = Color.FromHex(lifColor);
                    vm.GetLifeRSMData(userRegion, "L");
    
                }
    
            }
    
        }
    
        private async void RSMListView_ItemTapped(object sender, ItemTappedEventArgs e)
        {
            var item = (LifeRSMData)e.Item;
            await Navigation.PushAsync(new SMviewHead(company, item));
        }
    
        protected override void OnAppearing()
        {
            base.OnAppearing();
            if (Device.Idiom == TargetIdiom.Phone)
            {
    
                CrossDeviceOrientation.Current.LockOrientation(Plugin.DeviceOrientation.Abstractions.DeviceOrientations.Portrait);
    
            }
    
        }
    
        void OnPanUpdated(object sender, PanUpdatedEventArgs e)
        {
            // Handle the pan
            switch (e.StatusType)
            {
                case GestureStatus.Running:
                    // Translate and ensure we don't y   e.TotalY pan beyond the wrapped user interface element bounds.
                    var translateY = Math.Max(Math.Min(0, y   e.TotalY), -Math.Abs((Height * .25) - Height));
                    bottomSheet.TranslateTo(bottomSheet.X, translateY, 20);
                    break;
                case GestureStatus.Completed:
                    // Store the translation applied during the pan
                    y = bottomSheet.TranslationY;
    
                    //at the end of the event - snap to the closest location
                    var finalTranslation = Math.Max(Math.Min(0, -1000), -Math.Abs(GetClosestLockState(e.TotalY   y)));
    
                    //depending on Swipe Up or Down - change the snapping animation
                    if (isSwipeUp(e))
                    {
                        bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 250, Easing.SpringIn);
                    }
                    else
                    {
                        bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 250, Easing.SpringOut);
                    }
    
                    //dismiss the keyboard after a transition
                    //SearchBox.Unfocus();
                    y = bottomSheet.TranslationY;
                   
                    break;
    
            }
    
        }
    
        public bool isSwipeUp(PanUpdatedEventArgs e)
        {
            if (e.TotalY < 0)
            {
                return true;
            }
            return false;
        }
    
        //TO-DO: Make this cleaner
        private double GetClosestLockState(double TranslationY)
        {
            //Play with these values to adjust the locking motions - this will change depending on the amount of content ona  apge
            var lockStates = new double[] { 0, .5, .88 };
    
            //get the current proportion of the sheet in relation to the screen
            var distance = Math.Abs(TranslationY);
            var currentProportion = distance / Height;
    
            //calculate which lockstate it's the closest to
            var smallestDistance = 10000.0;
            var closestIndex = 0;
            for (var i = 0; i < lockStates.Length; i  )
            {
                var state = lockStates[i];
                var absoluteDistance = Math.Abs(state - currentProportion);
                if (absoluteDistance < smallestDistance)
                {
                    smallestDistance = absoluteDistance;
                    closestIndex = i;
                }
            }
    
            var selectedLockState = lockStates[closestIndex];
            var TranslateToLockState = GetProportionCoordinate(selectedLockState);
    
            return TranslateToLockState;
        }
    
        private double GetProportionCoordinate(double proportion)
        {
            return proportion * Height;
        }
    
        private void DismissBottomSheet()
        {
    
            //SearchBox.Unfocus();
            var finalTranslation = Math.Max(Math.Min(0, -1000), -Math.Abs(GetProportionCoordinate(0)));
            bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 450, Easing.SpringOut);
            //SearchBox.Text = string.Empty;
        }
    
        private void Picker_Focused(object sender, FocusEventArgs e)
        {
            DismissBottomSheet();
        }
    
        private void OpenBottomSheet()
        {
            var finalTranslation = Math.Max(Math.Min(0, -1000), -Math.Abs(GetProportionCoordinate(.85)));
            bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 150, Easing.SpringIn);
        }
    
    }
 

Модель представления

 public class RSMViewModel : BaseViewModelHelper
   {       

       public RSMViewModel()
       {
           btnImage = "upbtn.png";
           extraBtnVisible = false;
           isKpiEnable = false;
       }

       private void CreateToplayout(string company, string sList)
       {

           if (company.Equals("L"))
           {

               if (sList != null)
               {

                   var itemList = JsonConvert.DeserializeObject<List<SummaryLifeRegionalData>>(sList);
                   //var itemList = mList.rsmLifeData;

                   if (itemList.Count > 0)
                   {

                       foreach (var item in itemList)
                       {

                           FYR_NOP_TO_BE_PAID = item.FYR_NOP_TO_BE_PAID.ToString();
                           ....

                       }

                   }
                   else
                   {

                   }

               }
               else
               {

               }

           }
           else if (company.Equals("G"))
           {

               if (sList != null)
               {
                  
                   var mList = JsonConvert.DeserializeObject<SummaryRegionalHeaderData>(sList);
                   var itemList = mList.rsmMotorData;

                   if (itemList.Count > 0)
                   {

                       foreach (var item in itemList)
                       {

                           RENEWAL_VEHICLE_COUNT = item.RENEWAL_VEHICLE_COUNT.ToString();
                           ....

                       }

                   }
                   else
                   {

                   }

               }
               else
               {

               }

           }

       }

       public void GetLifeRSMData(string p_region, string cType)
       {
           extraBtnVisible = false;
           this.p_region = p_region;
           this.companyType = cType;
           IsEnabled = false;
           SelectedItem = getCurrentMonth(cType);
       }   

       public MonthData SelectedItem
       {
           get => _selectedItem;
           set
           {
               _selectedItem = value;

               Task.Run(async () =>
               {

                   AcrDialogClass.ShowLoadingDialog("Loading...");

                   if (firstRun)
                   {

                       string selectedSelectedItem = _selectedItem.ToString();
                       string getSubStringMonth = selectedSelectedItem.Substring(1, 2);
                       string getSubStringYear = selectedSelectedItem.Substring(9, 4);

                       await ChangeListAsync(getSubStringYear, getSubStringMonth, p_region, companyType);

                       string sList = null;

                       if (companyType.Equals("L"))
                       {

                           mainBgColor = "#f2b22c";
                           sList = await _apiServices.GetLifeSummaryDataRM(getSubStringYear, getSubStringMonth, p_region);

                       }
                       else if (companyType.Equals("G"))
                       {

                           mainBgColor = "#F44336";
                           sList = await _apiServices.getRSMsummaryData(getSubStringYear, getSubStringMonth, p_region, null);

                       }

                       CreateToplayout(companyType, sList);

                   }
                   else
                   {

                       firstRun = true;

                   }

                   AcrDialogClass.HideLoadingDialog();

               });

               OnPropertyChanged();
           }


       }

       private async Task ChangeListAsync(string getSubStringYear, string getSubStringMonth, string p_region, string companyType)
       {

           if (companyType.Equals("L"))
           {
               kpiImage = "kpi_chart.png";
               isKpiEnable = false;
               IsEnabled = false;

               //lifeValue = await _apiServices.getLifeRSMDataList(getSubStringYear, getSubStringMonth, p_region, authenticateData1);
               lifeValue = await _apiServices.GetLifeRSMDataList(getSubStringYear, getSubStringMonth, p_region);

               if (lifeValue != null)
               {
                   hasLifeData = true;
                   hasGenData = false;
                   noData = false;
                   IsEnabled = true;
                   layoutVisible = true;
                   layoutVisibleGen = false;

                   foreach (LifeRSMData ss in lifeValue)
                   {
                       ss.TOTAL_PREM_TO_BE_PAID_STRING = ss.TOTAL_PREM_TO_BE_PAID.ToString("N", CultureInfo.InvariantCulture);
                       ss.LIFE_TARGET_S = ss.LIFE_TARGET.ToString("N", CultureInfo.InvariantCulture);
                       ss.LIFE_ACHIVEMENT_S = ss.LIFE_ACHIVEMENT.ToString("N", CultureInfo.InvariantCulture);
                       Device.BeginInvokeOnMainThread(() =>
                       {
                           createChart(ss);
                       });
                       
                   }

                   rsmLifeRankingList = lifeValue;

               }
               else
               {

                   hasLifeData = false;
                   hasGenData = false;
                   noData = true;
                   IsEnabled = false;
                   layoutVisible = false;
                   layoutVisibleGen = false;
                   rsmLifeRankingList.Clear();

               }

           }
           else if (companyType.Equals("G"))
           {
               kpiImage = "kpi_chart.png";
               isKpiEnable = false;
               IsEnabled = false;

               genValue = await _apiServices.getGenRSMDataList(getSubStringYear, getSubStringMonth, p_region, null);

               if (genValue != null)
               {
                   hasGenData = true;
                   hasLifeData = false;
                   noData = false;
                   IsEnabled = true;
                   layoutVisible = false;
                   layoutVisibleGen = true;

                   foreach (GenRSMData ss in genValue)
                   {
                       ss.RENEWAL_PREMIUM_TO_BE_PAID_S = ss.RENEWAL_PREMIUM_TO_BE_PAID.ToString("N", CultureInfo.InvariantCulture);
                       ss.GENERAL_TARGET_S = ss.GENERAL_TARGET.ToString("N", CultureInfo.InvariantCulture);
                       ss.GENERAL_ACHIVEMENT_S = ss.GENERAL_ACHIVEMENT.ToString("N", CultureInfo.InvariantCulture);
                       createChartGen(ss);
                   }

                   rsmGenRankingList = genValue;

               }
               else
               {

                   hasGenData = false;
                   hasLifeData = false;
                   noData = true;
                   IsEnabled = false;
                   layoutVisible = false;
                   layoutVisibleGen = false;
                   rsmGenRankingList.Clear();

               }

           }
           else
           {

           }

       }

       private void createChart(LifeRSMData ss)
       {

           var labels = new List<string>();
           var lineEntries = new List<EntryChart>();

           float achPercentg = (float)((ss.LIFE_ACHIVEMENT / ss.LIFE_TARGET) * 100);

           lineEntries.Add(new EntryChart(0, 100));
           lineEntries.Add(new EntryChart(1, achPercentg));

           labels.Add("Tar:");
           labels.Add("Ach:");

           var lineDataSet4 = new BarDataSet(lineEntries, "")
           {
               Colors = new List<Color>{
                   Color.FromHex("#248acf"), Color.FromHex("#36DBBB")
               }
           };
           var lineData4 = new BarChartData(new List<IBarDataSet>() { lineDataSet4 });

           AxisLeft = new YAxisConfig();
           AxisLeft.DrawGridLines = false;
           AxisLeft.DrawAxisLine = true;
           AxisLeft.Enabled = true;
           AxisLeft.AxisMinimum = 0;
           AxisLeft.AxisMaximum = 100;

           AxisRight = new YAxisConfig();
           AxisRight.DrawAxisLine = false;
           AxisRight.DrawGridLines = false;
           AxisRight.Enabled = false;

           XAxis = new XAxisConfig();
           XAxis.Granularity = 1f;
           XAxis.XAXISPosition = XAXISPosition.BOTTOM;
           XAxis.DrawGridLines = false;
           XAxis.DrawLabels = true;
           XAxis.AxisValueFormatter = new TextByIndexXAxisFormatter(labels);

           Legend = new LegendXF();
           Legend.Enabled = false;

           DescriptionChart = new ChartDescription();
           DescriptionChart.Enabled = false;
           DescriptionChart.Text = "";

           ss.AxisLeft = AxisLeft;
           ss.AxisRight = AxisRight;
           ss.XAxis = XAxis;
           ss.Legend = Legend;
           ss.DescriptionChart = DescriptionChart;
           ss.chartData = lineData4;
       }

       public ICommand filterCommand
       {
           get
           {
               return new Command(() =>
               {
                   if (IsEnabled)
                   {
                       if (companyType != null)
                       {
                           if (companyType.Equals("L"))
                           {
                               UserDialogs.Instance.ActionSheet(new ActionSheetConfig().SetTitle("Sort using...")
                                   .Add("Due", () => this.SortData("DueA", companyType), "fup.png")
                                   .Add("Due", () => this.SortData("DueD", companyType), "fdown.png")
                                   .Add("Achievement", () => this.SortData("AchA", companyType), "fup.png")
                                   .Add("Achievement", () => this.SortData("AchD", companyType), "fdown.png").SetUseBottomSheet(true));

                           }
                           else if (companyType.Equals("G"))
                           {
                               UserDialogs.Instance.ActionSheet(new ActionSheetConfig().SetTitle("Sort using...")
                                   .Add("Due", () => this.SortData("DueA", companyType), "fup.png")
                                   .Add("Due", () => this.SortData("DueD", companyType), "fdown.png").SetUseBottomSheet(true));
                           }
                       }
                   }
               });
           }
       }

       public ICommand regionClassCommand
       {
           get
           {
               return new Command(() =>
               {

                   Application.Current.MainPage.Navigation.PushAsync(new RSMclassView(p_region, SelectedItem));

               });
           }
       }

       private void SortData(string caseSwitch, string companyType)
       {
         
       }

       private MonthData getCurrentMonth(string cType)
       {

           DateTime now = DateTime.Now;
         
           string currMonth_2 = now.AddMonths(-2).ToString("(MM)/MMM yyyy");
           string currMonth_1 = now.AddMonths(-1).ToString("(MM)/MMM yyyy");
           string currMonth0 = now.ToString("(MM)/MMM yyyy");
           string currMonth1 = now.AddMonths(1).ToString("(MM)/MMM yyyy");

           if (cType.Equals("L"))
           {
               MyList.Add(new MonthData { mName = currMonth_2 });
               MyList.Add(new MonthData { mName = currMonth_1 });
               MyList.Add(new MonthData { mName = currMonth0 });
               MyList.Add(new MonthData { mName = currMonth1 });
           }
           else
           {
               MyList.Add(new MonthData { mName = currMonth_2 });
               MyList.Add(new MonthData { mName = currMonth_1 });
               MyList.Add(new MonthData { mName = currMonth0 });
           }

           return new MonthData { mName = currMonth0 };
       }

   }
 

Комментарии:

1. Не могли бы вы, пожалуйста, отправить почтовый индекс RSMViewModel ?

2. Я обновил модель представления

3. Каков код LifeRSMData , SummaryLifeRegionalData , LifeRSMData ? Если это удобно для вас,не могли бы вы опубликовать базовую демонстрационную версию на github или onedriver и поделиться ссылкой здесь, чтобы мы могли вам лучше помочь?

4. github.com/dush135/TestBottomSheet.git

Ответ №1:

Вы можете настроить ListView отображение над нижней рамкой. Пожалуйста, удалите внешний элемент ItemListView и добавьте следующие свойства для ItemListView :

              RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}" 
             RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}"  
             RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
             RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=1.0}"
 

Весь код является :

 <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             BackgroundColor="Yellow"
             x:Class="TestBottomSheet.MainPage">

    <RelativeLayout>

            <ListView x:Name="ItemListView" HasUnevenRows="true" 
                 RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}" 
                 RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}"  
                 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
                 RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.91}"    
                      
                      >
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Frame HasShadow="True" BackgroundColor="White" CornerRadius="15" Margin="5">
                                <StackLayout Orientation="Vertical">
                                    <Label Text="{Binding title}" FontSize="Medium"/>
                                    <Label Text="{Binding id}" FontSize="Default"/>
                                </StackLayout>
                            </Frame>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
    
       
        <Frame HasShadow="true" CornerRadius="8" Padding="1,4,1,0" BackgroundColor="#faf9f8"
                     x:Name="bottomSheet" RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
                        Property=Height,Factor=.92,Constant=0}" RelativeLayout.WidthConstraint="{ConstraintExpression
                        Type=RelativeToParent,Property=Width,Factor=1,Constant=0}" RelativeLayout.HeightConstraint="{ConstraintExpression
                        Type=RelativeToParent,Property=Height,Factor=1,Constant=0}">
            <Frame.GestureRecognizers>
                <PanGestureRecognizer PanUpdated="OnPanUpdated" />
            </Frame.GestureRecognizers>
            <StackLayout Spacing="5">
                <BoxView HeightRequest="5" CornerRadius="2" WidthRequest="50" BackgroundColor="Gray" HorizontalOptions="Center"/>
                <StackLayout BackgroundColor="White" HeightRequest="25">
                    
                </StackLayout>

                <ListView x:Name="ItemListView2" HasUnevenRows="true" >
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Frame HasShadow="True" BackgroundColor="FloralWhite" CornerRadius="15" Margin="5">
                                    <StackLayout Orientation="Vertical">
                                        <Label Text="{Binding id}" FontSize="Default"/>
                                    </StackLayout>
                                </Frame>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

            </StackLayout>
        </Frame>
    </RelativeLayout>

</ContentPage>
 

В результате получается:

введите описание изображения здесь

Комментарии:

1. Я также дал тот же коэффициент=.92 для ограничения высоты ListView. теперь идеально