2016-03-01 8 views
6

Ich versuche, eine ListView mit anklickbaren Zeilen zu machen. Wenn Sie auf eine Zeile klicken, wird ein untergeordnetes Stacklayout auf true gesetzt. Das funktioniert gut in android, aber nicht in ios. Vielleicht mache ich es falsch. Ich bin noch ein Anfänger, irgendeine Idee, wie man diesen oder irgendeinen anderen besseren Ansatz repariert? Das Problem ist, dass es auf ios öffnet, so dass sich die Sichtbarkeit ändert, aber es aktualisiert die Höhe der Zelle nicht. Die Zelle wird außerhalb des Bildschirms aktualisiert, wenn Sie beispielsweise nach oben scrollen, bis Sie die geöffnete Zelle nicht mehr sehen können, und dann zurückscrollen. Sie werden sehen, dass die Höhe aktualisiert wurde.Listview nicht aktualisiert, wenn IsVisible auf True festgelegt ist

Ich habe versucht, einen benutzerdefinierten Renderer, aber ich habe keine Ahnung, wo ich anfangen soll.

Das ist mein 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" x:Class="Lisa.Excelsis.Mobile.AssessmentPage" xmlns:local="clr-namespace:Lisa.Excelsis.Mobile;assembly=Lisa.Excelsis.Mobile"> 
<StackLayout> 
    <local:SpecialListView x:Name="CategoryList" 
       ItemsSource = "{Binding Categories}" 
       HasUnevenRows="true" 
       RowHeight="-1" 
       GroupDisplayBinding="{Binding Name}" 
       IsGroupingEnabled="true"> 
     <local:SpecialListView.ItemTemplate> 
      <DataTemplate> 
       <ViewCell x:Name="ObservationCell"> 
        <ViewCell.View> 
         <StackLayout x:Name="ObservationContainer" 
            HorizontalOptions="FillAndExpand" 
            Orientation="Vertical" 
            VerticalOptions="StartAndExpand" 
            BackgroundColor="White"> 
          <StackLayout x:Name="Observation" 
             HorizontalOptions="FillAndExpand" 
             VerticalOptions="StartAndExpand"           
             Padding="15, 10, 10, 10" 
             BackgroundColor="White"> 
           <StackLayout.GestureRecognizers> 
            <TapGestureRecognizer Tapped="OpenItem"/> 
           </StackLayout.GestureRecognizers> 

           <Grid HorizontalOptions="FillAndExpand" > 
            <Grid.RowDefinitions> 
             <RowDefinition Height="Auto" />  
             <RowDefinition Height="Auto" />     
            </Grid.RowDefinitions> 

            <Grid.ColumnDefinitions> 
             <ColumnDefinition Width="35" /> 
             <ColumnDefinition Width="*" /> 
            </Grid.ColumnDefinitions> 

            <Label x:Name="ObservationOrder" 
              Text="{Binding Criterion.Order, StringFormat='{0}.'}" 
              FontSize="18" 
              VerticalOptions="StartAndExpand" 
              Grid.Column="0" Grid.Row="0"/> 

            <Label x:Name="ObservationTitle" 
              Text="{Binding Criterion.Title}" 
              FontSize="18" 
              VerticalOptions="StartAndExpand" 
              Grid.Column="1" Grid.Row="0"/> 

           </Grid> 
          </StackLayout> 
          <StackLayout x:Name="ObservationButtons" 
             HorizontalOptions="FillAndExpand" 
             VerticalOptions="StartAndExpand" 
             BackgroundColor="White" 
             IsVisible="false" 
             Padding="0, 0, 0, 20" 
             ClassId = "{Binding Id, StringFormat='ObservationButtons_{0}'}"> 

           <Grid HorizontalOptions="Center"           
             Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"> 
            <Grid.RowDefinitions> 
             <RowDefinition Height="Auto" />     
            </Grid.RowDefinitions> 

            <Grid.ColumnDefinitions> 
             <ColumnDefinition Width="80" /> 
             <ColumnDefinition Width="80" /> 
             <ColumnDefinition Width="10" /> 
             <ColumnDefinition Width="80" /> 
             <ColumnDefinition Width="80" /> 
             <ColumnDefinition Width="80" /> 
             <ColumnDefinition Width="80" /> 
            </Grid.ColumnDefinitions> 

            <StackLayout Grid.Column="0" Grid.Row="0" > 
             <Image Source="yesnobutton0.png" 
               HeightRequest="60" WidthRequest="60" 
               HorizontalOptions="Center" 
               VerticalOptions="Start" 
               x:Name="yesImage"> 
              <Image.GestureRecognizers> 
               <TapGestureRecognizer Tapped="SetYesImage"/> 
              </Image.GestureRecognizers> 
             </Image> 

             <Label Text="Ja" VerticalOptions="End" HorizontalOptions="Center"/> 
            </StackLayout> 

            <StackLayout Grid.Column="1" Grid.Row="0"> 
             <Image Source="yesnobutton0.png" 
               HeightRequest="60" WidthRequest="60" 
               HorizontalOptions="Center" 
               VerticalOptions="Start" 
               x:Name="noImage"> 
              <Image.GestureRecognizers> 
               <TapGestureRecognizer Tapped="SetNoImage"/> 
              </Image.GestureRecognizers> 
             </Image> 

             <Label Text="Nee" VerticalOptions="End" HorizontalOptions="Center"/> 
            </StackLayout> 

            <Image Source="maybenot.png" 
              HeightRequest="60" WidthRequest="60" 
              HorizontalOptions="Center" 
              VerticalOptions="Start" 
              Grid.Column="3" Grid.Row="0"> 
             <Image.GestureRecognizers> 
              <TapGestureRecognizer Tapped="SetMark"/> 
             </Image.GestureRecognizers> 
            </Image> 

            <Image Source="skip.png" 
              HeightRequest="60" WidthRequest="60" 
              HorizontalOptions="Center" 
              VerticalOptions="Start" 
              Grid.Column="4" Grid.Row="0"> 
             <Image.GestureRecognizers> 
              <TapGestureRecognizer Tapped="SetMark"/> 
             </Image.GestureRecognizers> 
            </Image> 

            <Image Source="unclear.png" 
              HeightRequest="60" WidthRequest="60" 
              HorizontalOptions="Center" 
              VerticalOptions="Start" 
              Grid.Column="5" Grid.Row="0"> 
             <Image.GestureRecognizers> 
              <TapGestureRecognizer Tapped="SetMark"/> 
             </Image.GestureRecognizers> 
            </Image> 

            <Image Source="change.png" 
              HeightRequest="60" WidthRequest="60" 
              HorizontalOptions="Center" 
              VerticalOptions="Start" 
              Grid.Column="6" Grid.Row="0"> 
             <Image.GestureRecognizers> 
              <TapGestureRecognizer Tapped="SetMark"/> 
             </Image.GestureRecognizers> 
            </Image> 
           </Grid> 
          </StackLayout> 
         </StackLayout> 
        </ViewCell.View> 
       </ViewCell> 
      </DataTemplate> 
     </local:SpecialListView.ItemTemplate> 
    </local:SpecialListView> 
</StackLayout> 

Dies ist ein Beispiel dafür, wie es funktioniert auf Android und wie ich will es auf ios arbeiten. Listview example

+0

Haben Sie versucht – StarterPack

Antwort

5

Ich reproduzierte Ihr Problem in einem kleinen Testprojekt. Ich bevorzuge Layout-Änderungen über Datenbindung, statt hinter Code.

Beginnen wir mit der Vorlage beginnen:

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
       x:Class="App6.Page1"> 
    <ListView x:Name="CategoryList" 
      BackgroundColor="Gray" 
      ItemsSource="{Binding Categories}" 
       SelectedItem="{Binding SelectedItem}" 
       HasUnevenRows="true" 
       RowHeight="-1"> 
    <ListView.ItemTemplate> 
     <DataTemplate> 
     <ViewCell x:Name="ObservationCell"> 
      <ViewCell.View> 
      <StackLayout x:Name="Observation" 
         HorizontalOptions="FillAndExpand" 
         VerticalOptions="StartAndExpand" 
         Padding="15, 10, 10, 10" 
         BackgroundColor="White"> 

       <Label x:Name="ObservationTitle" 
         Text="{Binding Title}" 
         FontSize="18" 
         TextColor="Black" 
         VerticalOptions="StartAndExpand"/> 

       <StackLayout Orientation="Horizontal" IsVisible="{Binding IsSelected}"> 
       <Image BackgroundColor="Fuchsia" WidthRequest="40" HeightRequest="40"></Image> 
       <Image BackgroundColor="Green" WidthRequest="40" HeightRequest="40"></Image> 
       <Image BackgroundColor="Yellow" WidthRequest="40" HeightRequest="40"></Image> 
       <Image BackgroundColor="Blue" WidthRequest="40" HeightRequest="40"></Image> 
       <Image BackgroundColor="Black" WidthRequest="40" HeightRequest="40"></Image> 
       </StackLayout> 
      </StackLayout> 
      </ViewCell.View> 
     </ViewCell> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
    </ListView> 
</ContentPage> 

Die Datatemplate ist basicaly gleich, aber:

  • die StackLayout hat keine Click-Listener
  • die visbility des StackLayout ist gebunden an IsSelected (IsVisible="{Binding IsSelected}")
  • die SelectedItem der ListView ist verpflichtet, SelectedItem unser Ansichtsmodell

Unsere Seite setzt nur das ViewModel als DataContext

public partial class Page1 : ContentPage 
{ 
    public Page1() 
    { 
     InitializeComponent(); 
     BindingContext = new Page1ViewModel(); 
    } 
} 

Das Ansichtsmodell

  • INotifyPropertyChanged implementiert die benachrichtigen Ansicht über Datenänderungen
  • fügt einige Dummy-Elemente unserer Categories Sammlung
  • eine SelectedItem Eigenschaft hat, dass die IsSelected Eigentum der Kategorien
class Page1ViewModel : INotifyPropertyChanged 
{ 
    private Category _selectedItem; 
    private ObservableCollection<Category> _categories = new ObservableCollection<Category>(); 
    public event PropertyChangedEventHandler PropertyChanged; 

    public ObservableCollection<Category> Categories 
    { 
     get { return _categories; } 
     set 
     { 
      _categories = value; 
      OnPropertyChanged(); 
     } 
    } 

    public Category SelectedItem 
    { 
     get { return _selectedItem; } 
     set 
     { 
      if (_selectedItem == value) 
       return; 

      if (_selectedItem != null) 
      { 
       _selectedItem.IsSelected = false; 
      } 

      _selectedItem = value; 
      if (_selectedItem != null) 
      { 
       _selectedItem.IsSelected = true; 
      } 
     } 
    } 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    public Page1ViewModel() 
    { 
     Categories.Add(new Category()); 
     Categories.Add(new Category()); 
     Categories.Add(new Category()); 
     Categories.Add(new Category()); 
     Categories.Add(new Category()); 
    } 
} 

Letzte Updates, but not least, aber am wichtigsten ist, müssen Sie eine kleine benutzerdefinierter Renderer, der den Standard überschreibt. Wir rufen ReloadData() auf, wenn sich die SelectedItem geändert hat.

[assembly: ExportRenderer(typeof(ListView), typeof(MyListViewRenderer))] 
namespace App6.iOS.CustomRenderer 
{ 
    public class MyListViewRenderer : ListViewRenderer 
    { 
     protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) 
     { 
      base.OnElementPropertyChanged(sender, e); 
      if (e.PropertyName == ListView.SelectedItemProperty.PropertyName) 
      { 
       Device.BeginInvokeOnMainThread(() => Control.ReloadData()); 
      } 
     } 
    } 
} 

Ergebnis

List View with dynamic cells

+0

diese Sie geklickt haben mit nur Neuladen der Reihe durchgeführt werden kann ForceLayout() auf Ihrem Layout-Aufruf? – Jim

+0

Vielleicht. Aber "ReloadData" ist eine in iOS übliche Methode, um Datenänderungen an die 'UITableView' zu signalisieren. Deshalb habe ich diesen Ansatz gewählt. Also ich gehe davon aus, dass es irgendwie optimiert ist, wenn Performance deine Sorge ist. –

Verwandte Themen