Xamarin.Forms.CarouselView doesn't work on iOS

2019-06-05 09:14发布

问题:

I have tried to implement Xamarin.Forms.CarouselView for use on both iOS and Android using Xamarin.Forms in Visual Studio. It works perfectly in Android, but it doesn't work on iOS. On iOS it shows the first slide, but it doesn't allow me to swipe right or left to change the current slide. I have installed the NuGet package in both the iOS and Android projects. The XAML looks like this:

    <cv:CarouselView ItemsSource="{Binding Slider}" x:Name="CarouselSlider">
        <cv:CarouselView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <!--<RowDefinition Height="Auto"/>-->
                    </Grid.RowDefinitions>
                    <Image Grid.RowSpan="1" Aspect="AspectFill" Source="{Binding ImageUrl}" />
                    <StackLayout BackgroundColor="#7F000000" Padding="12" VerticalOptions="Center" TranslationY="100">
                        <Label TextColor="White" Text="{Binding Title}" FontSize="26" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"/>
                        <Label TextColor="White" Text="{Binding TextBody}" FontSize="16" HorizontalOptions="Center" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand"/>
                    </StackLayout>
                </Grid>
            </DataTemplate>
        </cv:CarouselView.ItemTemplate>
    </cv:CarouselView>

And the backend looks like this:

public partial class MainPage : ContentPage
{
    public System.Collections.ObjectModel.ObservableCollection<SliderContent> Slider { get; set; }

    public MainPage()
    {
        InitializeComponent();
        NavigationPage.SetHasNavigationBar(this, false);

        Slider = new System.Collections.ObjectModel.ObservableCollection<SliderContent>
        {
            new SliderContent
            {
                Id = 1,
                ImageUrl = "https://thumb9.shutterstock.com/display_pic_with_logo/1975943/561919966/stock-photo-brutal-strong-athletic-men-pumping-up-muscles-workout-bodybuilding-concept-background-muscular-561919966.jpg",
                Title = "Aliquam et neque arcu",
                TextBody = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc porttitor erat arcu, vitae accumsan odio iaculis et."
            },
                new SliderContent
            {
                Id = 2,
                ImageUrl = "https://ifitlife.files.wordpress.com/2014/06/20140604-155437-57277345.jpg",
                Title = "Donec lobortis sodales dui",
                TextBody = "Morbi congue scelerisque vulputate. Vestibulum sit amet hendrerit justo. Nulla facilisi."
                },
            new SliderContent
            {
                Id = 3,
                ImageUrl = "https://uproxx.files.wordpress.com/2013/05/dmx-black.jpg?quality=100&w=650",
                Title = "Vestibulum arcu elit",
                TextBody = "Aliquam in maximus ante. Suspendisse facilisis posuere nulla quis hendrerit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas."
            }
        };

        Grid dotsGrid = DotsIndicator;
        dotsGrid.HorizontalOptions = LayoutOptions.CenterAndExpand;

        dotsGrid.ColumnDefinitions = new ColumnDefinitionCollection
        {
            new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
            new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
            new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }
        };

        dotsGrid.RowDefinitions = new RowDefinitionCollection
        {
            new RowDefinition { Height = new GridLength(6, GridUnitType.Star) },
            new RowDefinition { Height = new GridLength(2, GridUnitType.Star) },
            new RowDefinition { Height = new GridLength(6, GridUnitType.Star) }
        };

        int counter = 0;

        foreach (var i in Slider)
        {
            Button label = new Button();
            if (Slider.First() == i)
            {
                label = new Button
                {
                    BackgroundColor = Color.White,
                    BindingContext = i,
                    VerticalOptions = LayoutOptions.Fill,
                    WidthRequest = 20,
                    HeightRequest = 20,
                    BorderRadius = 30
                };
            }
            else
            {
                label = new Button
                {
                    BackgroundColor = Color.Gray,
                    BindingContext = i,
                    VerticalOptions = LayoutOptions.Fill,
                    WidthRequest = 20,
                    HeightRequest = 20,
                    BorderRadius = 30
                };
            }

            dotsGrid.Children.Add(label, counter, 1);
            counter++;
        }

        DotsIndicator = dotsGrid;
        this.BindingContext = this;
        CarouselSlider.ItemSelected += CarouselSlider_ItemSelected;
    }

    private void CarouselSlider_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        var item = e.SelectedItem as SliderContent;
        foreach (var i in DotsIndicator.Children)
        {
            i.BackgroundColor = Color.Gray;
            if (i.BindingContext == item)
            {
                i.BackgroundColor = Color.White;
            }
        }

        return;
    }
}

Are there any known issues using Xamarin.Forms.CarouselView on iOS or am I missing something?

回答1:

I have used Xamarin.Forms CarouselView for various iOS projects, it works fine. Below is my sample code, and please see my blog for further details. Hope it helps.

Install CarouselView Nuget package to your all projects (PCL, Android, iOS and Windows) - As the CarouselView is in a separate assembly, add CarouselView's namespace in root of your Xaml page and use it in your page like this;

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XYZ.Mobile.App.Controls.ValidationControls.Confirmation"
             xmlns:valueconverters="clr-namespace:XYZ.Mobile.App.ValueConverters"
             xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView">

  <StackLayout Grid.Row="1"
                 Orientation="Vertical">

      <cv:CarouselView x:Name="ConfirmationQuestionsCarousel"
                       ItemsSource="{Binding ConfirmationQuestions}">
        <cv:CarouselView.ItemTemplate>
          <DataTemplate>
          <!--You can now add other Xamarin controls in to your CarouselView-->
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition/>
                <RowDefinition Height="50"/>
              </Grid.RowDefinitions>

              <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
              </Grid.ColumnDefinitions>

              <Label Grid.Row="0"
                     Grid.ColumnSpan="2"
                     Text="SOME TEXT"
                     FontAttributes="Bold" />
              <Label Grid.Row="1"
                     Grid.ColumnSpan="2"
                     Text="{Binding Question}"/>

              <Button Grid.Row="2"
                      Grid.Column="0"
                      Text="No"
                      StyleId="No"
                      CommandParameter="false"
                      Command="{Binding ToggleAgree}"
                      Clicked="OnQuestionAnswered"
                      BackgroundColor="{Binding Agreed, Converter={StaticResource BoolToToggleButtonColorConverter}, ConverterParameter='Invert'}"/>
              <Button Grid.Row="2"
                      Grid.Column="1"
                      Text="Yes"
                      StyleId="Yes"
                      CommandParameter="true"
                      Command="{Binding ToggleAgree}"
                      Clicked="OnQuestionAnswered"
                      BackgroundColor="{Binding Agreed, Converter={StaticResource BoolToToggleButtonColorConverter}}"/>

            </Grid>
          </DataTemplate>
        </cv:CarouselView.ItemTemplate>
      </cv:CarouselView>
    </StackLayout>
</ContentView>

Furthermore; When I used Xamarin.Forms's CarouselView for the first time, I experienced some problems while getting the Count of the CarouselView item. I needed this count information in order to swipe to the next item correctly. Whenever I tried to get the ConfirmationQuestionsCarousel.Count info, I got "Unknown Member" error, so I eventually used the following code in order to get the count information.

 private void OnQuestionAnswered(object sender, EventArgs args)
        {
            var buttonClicked = sender as Button;
            var buttonClickedAnswer = buttonClicked.StyleId;

            // Ugly way to get the count
            //var s = new List<object>(ConfirmationQuestionsCarousel.ItemsSource.Cast<object>()).Count;
            // Better way to get the count
            int count = 0;

            foreach (var item in ConfirmationQuestionsCarousel.ItemsSource)
            {
                count++;
            }

            // This is to set the Carosel's Position - this is unfinished code, I put it here only as an example
            ConfirmationQuestionsCarousel.Position = 3;
        }


回答2:

I got your code and was able to compile and run it and the CarouselView worked in both iOS and Android.

Here's showing the transition between two views:

Make sure you:

  • Have the latest version of the library 2.3.0-pre2.
  • Install the library in your 3 projects (Forms, iOS and Android)

Note: I used the latest version of Xamarin Forms (2.3.4.247)

Also a good way for you to find out if there's any known problem with a library is visiting the project github.



回答3:

I solved the issue by putting a StackLayout tag around the CarouselView.