Xamarin is a powerful cross-platform framework with wide abilities. And I will prove it to you!
You can create a beautiful parallax effect using CarouselView and CarouselViewBehaviour. In addition, I'll show you how to create your own complex views effortlessly.
![](https://static.wixstatic.com/media/83bfb1_77e0e1da05b64a87a5e77d5658c6cadc~mv2.gif/v1/fill/w_250,h_500,al_c,pstr/83bfb1_77e0e1da05b64a87a5e77d5658c6cadc~mv2.gif)
Parallax
CarouselView has a Behaviors property, which means you can create custom behaviors for your CarouselView. I'm leaving some of the code from the gif example.
<CarouselView
ItemsSource="{Binding MKCharacters}"
CurrentItem="{Binding CurrentMKCharacter}"
IsScrollAnimated="False"
HorizontalScrollBarVisibility="Never">
<CarouselView.Behaviors>
<behaviors:ParallaxCarouselViewBehavior ParallaxOffset="500" />
</CarouselView.Behaviors>
<CarouselView.ItemsLayout>
<LinearItemsLayout
Orientation="Horizontal"
SnapPointsAlignment="Center"
SnapPointsType="Mandatory" />
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate x:DataType="models:MKCharacter">
<mkDemo:MKDemoCell Character="{Binding .}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
As you can see, this CarouselView has a ParallaxCarouselViewBehavior. The parallax behavior is created by the following code.
public class ParallaxCarouselViewBehavior : Behavior<CarouselView>
{
#region ParallaxOffset Property
public static readonly BindableProperty ParallaxOffsetProperty = BindableProperty.Create(
nameof(ParallaxOffset),
typeof(double),
typeof(ParallaxCarouselViewBehavior),
500d,
BindingMode.TwoWay);
public double ParallaxOffset
{
get => (double) GetValue(ParallaxOffsetProperty);
set => SetValue(ParallaxOffsetProperty, value);
}
#endregion ParallaxOffset Property
protected override void OnAttachedTo(CarouselView bindable)
{
base.OnAttachedTo(bindable);
bindable.Scrolled += OnScrolled;
}
protected override void OnDetachingFrom(CarouselView bindable)
{
base.OnDetachingFrom(bindable);
bindable.Scrolled -= OnScrolled;
}
private void OnScrolled(object sender, ItemsViewScrolledEventArgs e)
{
if (!(sender is CarouselView carouselView) || !(carouselView.ItemsLayout is ItemsLayout itemsLayout))
{
return;
}
var carouselItems = carouselView.ItemsSource.Cast<BaseParallaxCarouselItem>().ToList();
var centerItemIndex = e.CenterItemIndex;
var lastItemIndex = e.LastVisibleItemIndex;
switch (itemsLayout.Orientation)
{
case ItemsLayoutOrientation.Horizontal:
{
var carouselWidth = carouselView.Width;
var offset = carouselWidth * (centerItemIndex + 1) - e.HorizontalOffset;
var position = offset * ParallaxOffset / carouselWidth - ParallaxOffset;
var lastItem = carouselItems[lastItemIndex];
lastItem.ParallaxTranslation = position + ParallaxOffset;
var currentItem = carouselItems[centerItemIndex];
currentItem.ParallaxTranslation = position;
break;
}
case ItemsLayoutOrientation.Vertical:
{
var carouselHeight = carouselView.Height;
var offset = carouselHeight * (centerItemIndex + 1) - e.VerticalOffset;
var position = offset * ParallaxOffset / carouselHeight - ParallaxOffset;
var lastItem = carouselItems[lastItemIndex];
lastItem.ParallaxTranslation = position + ParallaxOffset;
var currentItem = carouselItems[centerItemIndex];
currentItem.ParallaxTranslation = position;
break;
}
default:
throw new ArgumentOutOfRangeException();
}
}
}
The ParallaxOffset bindable property was used to set the view speed when scrolling the CarouselView.
For use, I suggest you create some kind of BaseParallaxCarouselItem.
public abstract class BaseParallaxCarouselItem : INotifyPropertyChanged
{
public double ParallaxTranslation { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
How to use:
<Label
Text="{Binding Source={x:Reference Cell}, Path=Character.Name}"
TextColor="White"
FontFamily="{x:Static helpers:Constants+EmbeddedFonts.MKTitle}"
FontSize="40"
MaxLines="1"
TranslationX="{Binding Source={x:Reference Cell},
Path=Character.ParallaxTranslation,
Converter={StaticResource DivisionByNumberConverter},
ConverterParameter=3}" />
<Image
Source="{Binding Source={x:Reference Cell}, Path=Character.Image}"
Aspect="AspectFit"
TranslationX="{Binding Source={x:Reference Cell},
Path=Character.ParallaxTranslation}" />
The Character model implements BaseParallaxCarouselItem.
As you can see, you can use a different speed for all views.
In this part of the code, the Label will move 3 times slower than the Image.
Clip views
![](https://static.wixstatic.com/media/83bfb1_52ee29b213eb4539b4e9a1e64d27df51~mv2.png/v1/fill/w_281,h_500,al_c,q_85,enc_avif,quality_auto/83bfb1_52ee29b213eb4539b4e9a1e64d27df51~mv2.png)
I want to suggest that you use the Clip property to create a nice and complex control without any NuGet packages or renderers. For example, you can see the use of the Clip property in the gif or image (Back and Select buttons). In this example, I am using SVG paths to create these views, and I found several online tools to create SVG paths (e.g. https://mavo.io/demos/svgpath/).
Back Button code
<Grid
WidthRequest="115"
HeightRequest="40">
<BoxView
Style="{StaticResource MKBorderBoxViewStyle}"
WidthRequest="115"
HeightRequest="40"
HorizontalOptions="Start"
VerticalOptions="Center">
<BoxView.Clip>
<PathGeometry
Figures="m 15 0 h 100 a 35 35 0 0 1 -15 20 a 35 35 0 0 1 15 20 h -100 a 35 35 0 0 0 -15 -20 a 35 35 0 0 0 15 -20 z" />
</BoxView.Clip>
</BoxView>
<Button
Style="{StaticResource MKButtonStyle}"
Command="{Binding GoBackCommand}"
Text="{x:Static helpers:Constants+Texts.Back}"
WidthRequest="115"
HeightRequest="40"
HorizontalOptions="Start"
VerticalOptions="Center">
<Button.Clip>
<PathGeometry
Figures="m 17 2 h 95 a 35 35 0 0 1 -15 18 a 35 35 0 0 1 15 18 h -95 a 35 35 0 0 0 -15 -18 a 35 35 0 0 0 15 -18 z" />
</Button.Clip>
</Button>
</Grid>
I hope you find something important in this article. Improve your development skills and create cool apps with Xamarin.Forms (MAUI).
Can you share repo code please