Mahmudul Hasan
Mahmudul Hasan

Reputation: 828

.NET MAUI CarouselView changing position is not working without swiping at least once

I am trying to create an onboarding view with CarouselView. I have a position indicator and a button to change the carousel view item. When I press the button, it should display the next item. Alternatively, if I click on the indicator, it should change the item too!

The problem is, without swiping the view at least once or setting the position to zero from the UI (by going to an arbitrary position and pressing the first index from the indicator.), I can't control its position. (Demo in the gif below).

enter image description here

Here is my CaouselView XAML

 <Grid RowDefinitions="*,Auto">
        <CarouselView x:Name="OnBoardingCarouselView"
                      HorizontalOptions="FillAndExpand"
                      VerticalOptions="FillAndExpand"
                      IsBounceEnabled="False"
                      Loop="False" ItemsSource="{Binding IntroScreens}"
                      PositionChangedCommand="{Binding HandlePositionChangedCommand}"
                      PositionChangedCommandParameter="{Binding Source={RelativeSource Self}, Path=Position}"
                      IndicatorView="CarouselIndicator"
                      Position="{Binding CarouselPosition, Mode=TwoWay}">
            <CarouselView.ItemTemplate>
                <DataTemplate x:DataType="models:IntroScreen">
                    <Grid RowDefinitions="60*,40*">
                        <Image Source="{Binding Image}" HeightRequest="200"></Image>
                        <VerticalStackLayout Grid.Row="1">
                            <Label Text="{Binding IntroTitle}"
                                   FontSize="Title"></Label>
                            <Label Text="{Binding IntroDescription}"
                                   FontSize="Body"></Label>
                        </VerticalStackLayout>
                    </Grid>
                </DataTemplate>
            </CarouselView.ItemTemplate>
        </CarouselView>
        <Grid Grid.Row="1" ColumnDefinitions="*,Auto">
            <IndicatorView x:Name="CarouselIndicator" Grid.Column="0"
                           IndicatorsShape="Circle"
                           IndicatorSize="12"
                           IndicatorColor="{StaticResource Secondary}"
                           SelectedIndicatorColor="{StaticResource Primary}"
                           VerticalOptions="Center"></IndicatorView>
            <StackLayout Grid.Column="1">
                <Button x:Name="NextButton" Text="Next" 
                        Command="{Binding HandleNextButtonClickCommand}"
                        IsVisible="{Binding NextButtonVisibility}"></Button>
                <Button x:Name="EnterButton" Text="Enter" 
                        Command="{Binding HandleEnterButtonClickCommand}"
                        IsVisible="{Binding EnterButtonVisibility}"></Button>
            </StackLayout>
        </Grid>

I have tried to set starting position like this, and it is not working -

    public IntroScreenView()
    {
        InitializeComponent();

        // Check if the position preset is working
        OnBoardingCarouselView.Position = 1;
    }

Here is my corresponding view model -

[ObservableObject]
    public partial class IntroScreenViewModel
    {
        [ObservableProperty]
        private int carouselPosition;
        [ObservableProperty]
        private bool nextButtonVisibility;
        [ObservableProperty]
        private bool enterButtonVisibility;
        [ObservableProperty]
        private ObservableCollection<IntroScreen> introScreens;

        public IntroScreenViewModel()
        {
            EnterButtonVisibility = false;
            NextButtonVisibility = true;
            IntroScreens = new ObservableCollection<IntroScreen>
            {
                new()
                {
                    IntroTitle = "Intro Title One",
                    IntroDescription = "Lorem is some time ipsum but ipsum can't be lorem.",
                    Image = "cr_1.svg"
                },
                new()
                {
                    IntroTitle = "Intro Title Two",
                    IntroDescription = "Lorem is some time ipsum but ipsum can't be lorem.",
                    Image = "cr_2.svg"
                },
                new()
                {
                    IntroTitle = "Intro Title Three",
                    IntroDescription = "Lorem is some time ipsum but ipsum can't be lorem.",
                    Image = "cr_3.svg"
                }
            };
            // commenting the following line or setting to any position 
            // does not affect anything
            CarouselPosition = 0;
        }
        [RelayCommand]
        public void HandlePositionChanged(int position)
        {
            // here position variable always gets the correct position
            if (position == IntroScreens.Count - 1)
            {
                EnterButtonVisibility = true;
                NextButtonVisibility = false;
            }
            else
            {
                EnterButtonVisibility = false;
                NextButtonVisibility = true;
            }
        }
        [RelayCommand]
        public void HandleNextButtonClick()
        {
            if (CarouselPosition + 1 < introScreens.Count)
                CarouselPosition++;
        }

        [RelayCommand]
        public void HandleEnterButtonClick()
        {
            Application.Current!.MainPage = new LoginPageView();
        }
    }

Full source code is here https://github.com/MahmudX/Binimoy

Upvotes: 3

Views: 3439

Answers (2)

Martin Novak
Martin Novak

Reputation: 51

@doss-bilure The answer is correct and solves this problem.

Just a little note: if you edit collection CarouselView, it automatically changes Position, so it matches the previously selected item. If you want to add an item without this change, you have to edit both Position and CurrentItem

Upvotes: 2

Doss Bilure
Doss Bilure

Reputation: 51

I also encountered this problem. After several hours of experiments, I realized that problem is in Loop property.

Setting Loop="True" in CarouselView resolves this problem.

Anyway, it's MAUI bug.

Upvotes: 5

Related Questions