2016-06-26 5 views
0

Я разрабатываю кросс-платформенное приложение с использованием Xamarin.Forms. На одной из страниц у меня есть аватар, какая-то информация, а затем ListView. Дело в том, что все это завернуто в ScrollView, поэтому я могу прокручивать содержимое. Проблема в том, что я теряю поведение прокрутки ListView. This're несколько скриншотов:Xamarin.Forms - Высота изменения ListView во время выполнения

enter image description here

enter image description here

Как вы можете видеть представление XAML в основном, аватар Image (в пожарном изображения), затем «Последний этап проверки» информацию, а затем у нас есть ListView. Я жестко закодировал HeightRequest в ListView, так что он имеет большую высоту. Но дело в том, что когда я прокручиваю нижнюю часть страницы, я не могу продолжать прокручивать ListView, потому что ScrollView бесполезно с этим поведением. I нужно использовать ListView, потому что список проверочных отчетов, которые я показываю там, заполнен из веб-службы, и я обновляю этот список, когда я вхожу и выхожу из страницы. Это код XAML:

<?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:checkReport="clr-namespace:HalliganTL.View;assembly=HalliganTL" 
       xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions" 
      x:Class="HalliganTL.View.ApparatusDetailPage" BackgroundColor="#FFFFFFFF"> 
    <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> 
    <ScrollView x:Name="GeneralScrollView" 
       Orientation="Vertical" VerticalOptions="FillAndExpand" 
       HorizontalOptions="FillAndExpand"> 
     <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="180"></RowDefinition> 
      <RowDefinition Height="40"></RowDefinition> 
      <RowDefinition Height="80"></RowDefinition> 
      <RowDefinition Height="40"></RowDefinition> 
      <RowDefinition Height="360"></RowDefinition> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"></ColumnDefinition> 
     </Grid.ColumnDefinitions> 

     <!-- Top Image --> 
     <ContentView Grid.Column="0" Grid.Row="0" Padding="15"> 
      <controls:CircleImage x:Name="ApparatusImage" 
      HeightRequest="150" WidthRequest="150" 
      VerticalOptions="Center" 
      BorderColor="#3B5685" 
      BorderThickness="2" 
      HorizontalOptions="Center" 
      Aspect="AspectFill"> 
      </controls:CircleImage> 
     </ContentView> 

     <!-- Last Check Separator --> 
     <AbsoluteLayout Grid.Column="0" Grid.Row="1" x:Name="LastCheckContainerTitle" BackgroundColor="#FFE4E4E9" Padding="5,15,15,5" VerticalOptions="End" > 
      <Label Text="LAST CHECK" Style="{StaticResource separatorLabel}" /> 
     </AbsoluteLayout> 
     <!-- Last Check Detail --> 
     <checkReport:CheckReportViewPage Grid.Column="0" Grid.Row="2" x:Name="LastCheckReportView"> 
      <checkReport:CheckReportViewPage.GestureRecognizers> 
      <TapGestureRecognizer Tapped="OnLastCheckReportClicked" NumberOfTapsRequired="1" /> 
      </checkReport:CheckReportViewPage.GestureRecognizers> 
     </checkReport:CheckReportViewPage> 

     <AbsoluteLayout Grid.Column="0" Grid.Row="3" x:Name="CheckHistoryTitle" BackgroundColor="#FFE4E4E9" Padding="5,15,15,5" > 
      <Label Text="CHECK HISTORY" Style="{StaticResource separatorLabel}" FontAttributes="None" VerticalOptions="End" /> 
     </AbsoluteLayout> 

     <!-- Apparatus check history --> 
     <ListView x:Name="CheckHistoryListView" 
        HeightRequest="380" 
        Grid.Column="0" Grid.Row="4" 
        HorizontalOptions="FillAndExpand" 
        HasUnevenRows="True" 
        IsPullToRefreshEnabled="False" 
        VerticalOptions="FillAndExpand" ItemTapped="OnItemTapped"> 
      <ListView.ItemTemplate> 
      <DataTemplate> 
       <ViewCell> 
       <checkReport:CheckReportViewPage/> 
       </ViewCell> 
      </DataTemplate> 
      </ListView.ItemTemplate> 
     </ListView> 
     </Grid> 
    </ScrollView> 

    <Label Text="Start Check" HeightRequest="60" VerticalOptions="End" BackgroundColor="#3B5685" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" FontSize="18" TextColor="White"> 
     <Label.GestureRecognizers> 
     <TapGestureRecognizer 
       Tapped="OnStartCheckClicked" 
       NumberOfTapsRequired="1" /> 
     </Label.GestureRecognizers> 
    </Label> 

    </StackLayout> 



</ContentPage> 

Поэтому в основном то, что я спрашиваю, как можно добиться чего-то вроде эффекта параллакса, прокрутка вниз, а затем делегировать поведение прокрутки в ListView таким образом я могу прокручивать каждый пункт в ListView. В настоящее время я просто могу видеть элементы, которые соответствуют размеру ListView HeightRequest. В примере скриншота, который я, например, shoing, есть несколько других элементов в этом ListView, но я не могу прокручивать их, потому что ScrollView возился с поведением прокрутки ListView.

ответ

2

Рекомендуемый подход для размещения контента на странице с ListView является использование свойства верхнего и нижних колонтитулов на ListView.

Посмотрите ListView Headers and Footers

<ListView x:Name="listView"> 
    <ListView.Footer> 
    <Label Text="Footer" /> 
    </ListView.Footer> 
</ListView> 

Таким образом, вам не нужно обернуть в другой свиток.

+0

Определенно, путь ... работал в нескольких строках – 4gus71n

+0

Быстрый вопрос, есть ли способ показать заголовок, когда ListView не имеет элементов? Потому что, если в моем ListView нет элементов, Заголовок не отображается. – 4gus71n

1

ListView не следует размещать внутри прокручивающегося контейнера. Когда вы это делаете, вы теряете все преимущества ListView (виртуализация, прокрутка и т. Д.).

Если необходимо реализовать эффект параллакса с помощью прокрутки некоторых других данные синхронизированного с ListView позиции, то вы всегда можете наложить список поверх другой вид прокрутки (но не как ребенок этой точки зрения прокрутки) ,

+0

Спасибо, что нашли время ответить мне. Я очень хорошо знаю, что не правильно размещать прокручиваемый элемент управления в другом прокручиваемом элементе управления, но можете ли вы увидеть, что я пытаюсь указать здесь? Можете ли вы предложить мне какую-то организацию XAML? – 4gus71n

+0

Возможно, я не понимаю, что вы ищете.Вы хотите, чтобы ваш аватар плюс статическая информация наверху оставалась видимой при прокрутке списка? –

+0

Нет, я хочу, чтобы эта информация прокручивалась, когда я просматриваю ListView, но не волнуйся, поместив эту информацию в ListView.Header, решив проблему. – 4gus71n

0

Я считаю, что вам нужен RepeaterView, элемент управления, который повторяет элементы, но не является прокручиваемым, и вы можете привязать его к ObservableCollection.

Он просто работает

using System; 
    using System.Collections; 
    using System.Collections.Specialized; 
    using Xamarin.Forms; 

    public delegate void RepeaterViewItemAddedEventHandler(object sender, RepeaterViewItemAddedEventArgs args); 

    // in lieu of an actual Xamarin Forms ItemsControl, this is a heavily modified version of code from https://forums.xamarin.com/discussion/21635/xforms-needs-an-itemscontrol 
    public class RepeaterView : StackLayout 
    { 
     public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create<RepeaterView, IEnumerable>(
      p => p.ItemsSource, 
      null, 
      BindingMode.OneWay, 
      propertyChanged: ItemsChanged); 

     public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create<RepeaterView, DataTemplate>(
      p => p.ItemTemplate, 
      default(DataTemplate)); 

     public event RepeaterViewItemAddedEventHandler ItemCreated; 

     public IEnumerable ItemsSource 
     { 
      get { return (IEnumerable)GetValue(ItemsSourceProperty); } 
      set { SetValue(ItemsSourceProperty, value); } 
     } 

     public DataTemplate ItemTemplate 
     { 
      get { return (DataTemplate)GetValue(ItemTemplateProperty); } 
      set { SetValue(ItemTemplateProperty, value); } 
     } 

     private static void ItemsChanged(BindableObject bindable, IEnumerable oldValue, IEnumerable newValue) 
     { 
      var control = (RepeaterView)bindable; 
      var oldObservableCollection = oldValue as INotifyCollectionChanged; 

      if (oldObservableCollection != null) 
      { 
       oldObservableCollection.CollectionChanged -= control.OnItemsSourceCollectionChanged; 
      } 

      var newObservableCollection = newValue as INotifyCollectionChanged; 

      if (newObservableCollection != null) 
      { 
       newObservableCollection.CollectionChanged += control.OnItemsSourceCollectionChanged; 
      } 

      control.Children.Clear(); 

      if (newValue != null) 
      { 
       foreach (var item in newValue) 
       { 
        var view = control.CreateChildViewFor(item); 
        control.Children.Add(view); 
        control.OnItemCreated(view); 
       } 
      } 

      control.UpdateChildrenLayout(); 
      control.InvalidateLayout(); 
     } 

     protected virtual void OnItemCreated(View view) => 
      this.ItemCreated?.Invoke(this, new RepeaterViewItemAddedEventArgs(view, view.BindingContext)); 

     private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      var invalidate = false; 

      if (e.OldItems != null) 
      { 
       this.Children.RemoveAt(e.OldStartingIndex); 
       invalidate = true; 
      } 

      if (e.NewItems != null) 
      { 
       for (var i = 0; i < e.NewItems.Count; ++i) 
       { 
        var item = e.NewItems[i]; 
        var view = this.CreateChildViewFor(item); 

        this.Children.Insert(i + e.NewStartingIndex, view); 
        OnItemCreated(view); 
       } 

       invalidate = true; 
      } 

      if (invalidate) 
      { 
       this.UpdateChildrenLayout(); 
       this.InvalidateLayout(); 
      } 
     } 

     private View CreateChildViewFor(object item) 
     { 
      this.ItemTemplate.SetValue(BindableObject.BindingContextProperty, item); 
      return (View)this.ItemTemplate.CreateContent(); 
     } 
    } 

    public class RepeaterViewItemAddedEventArgs : EventArgs 
    { 
     private readonly View view; 
     private readonly object model; 

     public RepeaterViewItemAddedEventArgs(View view, object model) 
     { 
      this.view = view; 
      this.model = model; 
     } 

     public View View => this.view; 

     public object Model => this.model; 
    } 

Read this thread in Xamarin Forms Forums

Смежные вопросы