【问题标题】:How to create Listview with accordion in xamarin form?如何使用 xamarin 形式的手风琴创建 Listview?
【发布时间】:2022-01-20 03:07:18
【问题描述】:

我正在使用 xamarin.form。 我想用展开和折叠创建 Listview。

例子:

请给我你的建议。

【问题讨论】:

    标签: android ios xamarin xamarin.forms mobile


    【解决方案1】:

    我们可以在 Xamarin.Forms 中使用子 ListView 创建一个复杂的 Expandable ListView。这个 Expandable List 允许用户通过简单的单击来展开和折叠项目。

    假设我们有一个酒店列表,每个酒店都包含一个房间列表。单击酒店将显示其房间,而双击将折叠它。

    我们可以创建以下文件夹:

    • 型号
    • 观看次数
    • 视图模型

    1.创建模型

    创建一个新类Hotel.cs

    public class Hotel
    {
        public string Name { get; set; }
    
        public List<Room> Rooms { get; set; }
    
        public bool IsVisible { get; set; } = false;
    
        public Hotel()
        {
        }
    
        public Hotel(string name, List<Room> rooms)
        {
            Name = name;
            Rooms = rooms;
        }
    }
    

    创建一个新类Room.cs

        public class Room
        {
            public string RoomName { get; set; }
            public int TypeID { get; set; }
    
            public Room()
            {
    
            }
    
            public Room(string name, int typeID)
            {
                RoomName = name;
                TypeID = typeID;
            }
        }
      }
    

    2.创建视图模型

    BaseViewModel.cs

    public class BaseViewModel: INotifyPropertyChanged
    {
        bool isBusy = false;
        public bool IsBusy
        {
            get { return isBusy; }
            set { SetProperty(ref isBusy, value); }
        }
        bool isEmpty = false;
        public bool IsEmpty
        {
            get { return isEmpty; }
            set
            {
                isEmpty = value;
                OnEmptyChanged(this, new PropertyChangedEventArgs("IsEmpty"));
            }
        }
    
        private void OnEmptyChanged(BaseViewModel baseViewModel, PropertyChangedEventArgs propertyChangedEventArgs)
        {
             CrossToastPopUp.Current.ShowToastMessage("No Data Found");
    
        }
    
        string busyText = string.Empty;
        string title = string.Empty;
    
    
    
        public string Title
        {
            get => title;
            set => SetProperty(ref title, value);
        }
    
        public string BusyText
        {
            get => busyText;
            set => SetProperty(ref busyText, value);
        }
    
        protected bool SetProperty<T>(ref T backingStore, T value,
            [CallerMemberName] string propertyName = "",
            Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;
    
            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }
    
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;
    
            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
    

    HotelsGroupViewModel.cs

    public class HotelsGroupViewModel: BaseViewModel
    {
        private HotelViewModel _oldHotel;
    
        private ObservableCollection<HotelViewModel> items;
        public ObservableCollection<HotelViewModel> Items
        {
            get => items;
    
            set => SetProperty(ref items, value);
        }
    
        public Command LoadHotelsCommand { get; set; }
        public Command<HotelViewModel> RefreshItemsCommand { get; set; }
    
        public HotelsGroupViewModel()
        {
            items = new ObservableCollection<HotelViewModel>();
            Items = new ObservableCollection<HotelViewModel>();
            LoadHotelsCommand = new Command(async () => await ExecuteLoadItemsCommandAsync());
            RefreshItemsCommand = new Command<HotelViewModel>((item) => ExecuteRefreshItemsCommand(item));
        }
    
        public bool isExpanded = false;
        private void ExecuteRefreshItemsCommand(HotelViewModel item)
        {
            if (_oldHotel == item)
            {
                // click twice on the same item will hide it
                item.Expanded = !item.Expanded;
            }
            else
            {
                if (_oldHotel != null)
                {
                    // hide previous selected item
                    _oldHotel.Expanded = false;
                }
                // show selected item
                item.Expanded = true;
            }
    
            _oldHotel = item;
        }
        async System.Threading.Tasks.Task ExecuteLoadItemsCommandAsync()
        {
            try
            {
                if (IsBusy)
                    return;
                IsBusy = true;
                Items.Clear();
                List<Room> Hotel1rooms = new List<Room>() { new Room("Jasmine", 1), new Room("Flower Suite", 2), new Room("narcissus", 1)
                };
                List<Room> Hotel2rooms = new List<Room>()
                {
                    new Room("Princess", 1), new Room("Royale", 1), new Room("Queen", 1)
                };
                List<Room> Hotel3rooms = new List<Room>()
                {
                    new Room("Marhaba", 1), new Room("Marhaba Salem", 1), new Room("Salem Royal", 1), new Room("Wedding Roome", 1), new Room("Wedding Suite", 2)
                };
                List<Hotel> items = new List<Hotel>() { new Hotel("Yasmine Hammamet", Hotel1rooms), new Hotel("El Mouradi Hammamet,", Hotel2rooms), new Hotel("Marhaba Royal Salem", Hotel3rooms) };
    
                if (items != null && items.Count > 0)
                {
                    foreach (var hotel in items)
                        Items.Add(new HotelViewModel(hotel));
                }
                else { IsEmpty = true; }
    
            }
            catch (Exception ex)
            {
                IsBusy = false;
                Debug.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }
    }
    

    HotelViewModel.cs

       public  class HotelViewModel: ObservableRangeCollection<RoomViewModel>, INotifyPropertyChanged
        {
            // It's a backup variable for storing CountryViewModel objects
            private ObservableRangeCollection<RoomViewModel> hotelRooms = new ObservableRangeCollection<RoomViewModel>();
    
            public HotelViewModel(Hotel hotel, bool expanded = false)
            {
                this.Hotel = hotel;
                this._expanded = expanded;
    
                foreach (Room room in hotel.Rooms)
                {
                    hotelRooms.Add(new RoomViewModel(room));
                }
                if (expanded)
                    this.AddRange(hotelRooms);
    
            }
    
            public HotelViewModel()
            {
            }
    
            private bool _expanded;
            public bool Expanded
            {
                get { return _expanded; }
                set
                {
                    if (_expanded != value)
                    {
                        _expanded = value;
                        OnPropertyChanged(new PropertyChangedEventArgs("Expanded"));
                        OnPropertyChanged(new PropertyChangedEventArgs("StateIcon"));
                        if (_expanded)
                        {
                            this.AddRange(hotelRooms);
                        }
                        else
                        {
                            this.Clear();
                        }
                    }
                }
            }
    
            public string StateIcon
            {
                get
                {
                    if (Expanded)
                    {
                        return "arrow_a.png";
                    }
                    else
                    { return "arrow_b.png"; }
                }
            }
            public string Name { get { return Hotel.Name; } }
            public Hotel Hotel { get; set; }
        }
    

    RoomViewModel.cs

    public class RoomViewModel
    {
        private Room _room;
    
        public RoomViewModel(Room room)
        {
            this._room = room;
        }
    
        public string RoomName { get { return _room.RoomName; } }
        public int TypeID { get { return _room.TypeID; } }
    
        public Room Room
        {
            get => _room;
        }
    }
    

    3.创建页面(酒店)

    Hotels.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:Name="currentPage"
                 xmlns:local="clr-namespace:ListViewWithSubListView.Views"
                 x:Class="ListViewWithSubListView.Views.Hotels">
        <ContentPage.Content>
            <Grid >
              
                <StackLayout x:Name="hotelStack" Padding="1,0,1,0" >
                    <ListView
                        x:Name="HotelsList"
                        BackgroundColor="White"
                        IsGroupingEnabled="True"
                        IsPullToRefreshEnabled="true"
                        IsRefreshing="{Binding IsBusy, Mode=OneWay}"
                        ItemsSource="{Binding Items}"
                        RefreshCommand="{Binding LoadHotelsCommand}"
                        >
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <ViewCell>
                                    <StackLayout Orientation="Horizontal"  VerticalOptions="Center">
                                            <Label
                                                VerticalOptions="Center"
                                                FontAttributes="Bold"
                                                FontSize="Medium"
                                                Text="{Binding RoomName}"
                                                TextColor="Black"
                                                VerticalTextAlignment="Center" />                                  
                                    </StackLayout>                                   
                                </ViewCell>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                        <ListView.GroupHeaderTemplate>
                            <DataTemplate>
                                <ViewCell>
                                   <Grid >
                                       <Label
                                                    FontAttributes="Bold"
                                                    FontSize="Small"
                                                    Text="{Binding Name}"
                                                    TextColor="Gray"
                                                    VerticalTextAlignment="Center" />
                                        <Image x:Name="ImgA" Source="{Binding StateIcon}"  Margin="0,0,5,0" HeightRequest="20" WidthRequest="20" HorizontalOptions="End"/>
                                        <Grid.GestureRecognizers>
                                            <TapGestureRecognizer Command="{Binding Source={x:Reference currentPage}, Path=BindingContext.RefreshItemsCommand}"  NumberOfTapsRequired="1" CommandParameter="{Binding .}"/>
                                        </Grid.GestureRecognizers>
                                    </Grid>                               
                                </ViewCell>
                            </DataTemplate>
                        </ListView.GroupHeaderTemplate>
                    </ListView>
                </StackLayout>
            </Grid>
        </ContentPage.Content>   
    </ContentPage>
    

    Hotels.xaml.cs

    public partial class Hotels : ContentPage
    {
    
        private HotelsGroupViewModel ViewModel
        {
            get { return (HotelsGroupViewModel)BindingContext; }
            set { BindingContext = value; }
        }
    
        private List<Hotels> ListHotel = new List<Hotels>();
    
        protected override void OnAppearing()
        {
            try
            {
                base.OnAppearing();
    
                if (ViewModel.Items.Count == 0)
                {
                    ViewModel.LoadHotelsCommand.Execute(null);
                }           
            }
            catch (Exception Ex)
            {
                Debug.WriteLine(Ex.Message);
            }
        }
    
        public Hotels(HotelsGroupViewModel viewModel)
        {
            InitializeComponent();
            this.ViewModel = viewModel;           
        }   
    }
    

    App.xaml.cs

    MainPage = new Hotels(new HotelsGroupViewModel());
    

    注意:

    参考:https://www.c-sharpcorner.com/article/xamarin-forms-expandable-listview-with-a-sub-listview-mvvm-pattern/

    【讨论】:

    • 嗨@Kirti Zare,我已经好几天没有收到你的消息了。如果有什么我可以在这里提供帮助的,请告诉我。
    【解决方案2】:
     <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Padding="20">             
            <Grid.RowDefinitions>                       
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <control:FrameView Grid.Row="0" Text="Popular Music Instrument">
                <control:FrameView.ContainerContent>
                    <StackLayout>
                        <Label Text="1. Piano/Keyboard" TextColor="Black"></Label>
                        <Label Text="2. Guitar" TextColor="Black"></Label>
                        <Label Text="3. Violin" TextColor="Black"></Label>
                        <Label Text="4. Drums" TextColor="Black"></Label>
                        <Label Text="5. Saxophone" TextColor="Black"></Label>
                    </StackLayout>
                </control:FrameView.ContainerContent>
            </control:FrameView>
            
            <control:FrameView Grid.Row="1" Text="Gender">
                <control:FrameView.ContainerContent>
                    <StackLayout>
                        <Label Text="1. Male" TextColor="Black"></Label>
                        <Label Text="2. Female" TextColor="Black"></Label>
                        <Label Text="3. Transgender" TextColor="Black"></Label>
                    </StackLayout>
                </control:FrameView.ContainerContent>
            </control:FrameView>
    
            <control:FrameView Grid.Row="2" Text="Detail">
                <control:FrameView.ContainerContent>
                    <StackLayout>
                        <Label Text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
                               Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, 
                               when an unknown printer took a galley of type and scrambled it to make a type 
                               specimen book." TextColor="Black"></Label>
                    </StackLayout>
                </control:FrameView.ContainerContent>
            </control:FrameView>
        </Grid>
    

    请查看此链接:

    https://xamarinuidesigns.blogspot.com/2021/12/accordion-ui-designs-part-1.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-12
      • 1970-01-01
      • 2019-01-01
      • 1970-01-01
      • 2016-03-28
      • 2014-07-31
      • 2014-12-18
      • 1970-01-01
      相关资源
      最近更新 更多