简体   繁体   中英

ScrollView with animation xamarin forms

I would like to know how to do the following horizontal scrollview with animation : so the button closer to screen center so is bigger.

And I also would like to know how to position the button like in the picture.

带按钮的水平滚动视图

Thanks :)

Query 1:

If I understand you correctly, you want all the visible views inside the scrollview to change their scale according to their position.

This can be achieved by using a custom view and binding the scrollview's Width and ScrollX to it to change the view's Scale.

My solution working gif

Created CustomView derived from ContentView . Added three BindableProperties each for ScrollX , Width of ScrollView and Position of the view in the scrollview.

For all three BindableProperty's PropertyChanged bound a single method OnScaleFactorsChange and calculated the scale of the view accordingly.

Bindable properties in CustomView

    /// <summary>
    /// Gets or sets ScrolledPosition
    /// </summary>
    public double ScrolledPosition
    {
        get { return (double)GetValue(ScrolledPositionProperty); }
        set
        {
            SetValue(ScrolledPositionProperty, value);
        }
    }

    /// <summary>
    /// Identifies the <see cref="ScrolledPosition"/> bindable property.
    /// </summary>
    public static readonly BindableProperty ScrolledPositionProperty = BindableProperty.Create("ScrolledPosition", typeof(double), typeof(CustomView), 0d, BindingMode.TwoWay, null, OnScaleFactorsChange);

    /// <summary>
    /// Gets or sets Position
    /// </summary>
    public double Position
    {
        get { return (double)GetValue(PositionProperty); }
        set
        {
            SetValue(PositionProperty, value);
        }
    }

    /// <summary>
    /// Identifies the <see cref="Position"/> bindable property.
    /// </summary>
    public static readonly BindableProperty PositionProperty = BindableProperty.Create("Position", typeof(double), typeof(CustomView), 0d, BindingMode.TwoWay, null, OnScaleFactorsChange);

    /// <summary>
    /// Gets or sets ScrollViewWidth
    /// </summary>
    public double ScrollViewWidth
    {
        get { return (double)GetValue(ScrollViewWidthProperty); }
        set
        {
            SetValue(ScrollViewWidthProperty, value);
        }
    }

    /// <summary>
    /// Identifies the <see cref="ScrollViewWidth"/> bindable property.
    /// </summary>
    public static readonly BindableProperty ScrollViewWidthProperty = BindableProperty.Create("ScrollViewWidth", typeof(double), typeof(CustomView), 0d, BindingMode.TwoWay, null, OnScaleFactorsChange);

OnScaleFactorsChange method

 private static void OnScaleFactorsChange(BindableObject bindable, object oldvalue, object newValue)
        {
            (bindable as CustomView).ChangeScale();
        }

        private void ChangeScale()
        {
            var itemWd = this.Width;

            var itemPresent = this.ScrollViewWidth / this.Width;
            double ratio = 0;

            var scrolledItems = this.ScrolledPosition / this.Width;

            double totalRatio = ((this.Position - 0.5 - scrolledItems) / (itemPresent / 2));

            if (totalRatio > 0 && totalRatio < 2)
            {
                ratio = totalRatio > 1 ? 2 - totalRatio : totalRatio;
            }

            // Minimum scale 0.75 , maximum scale 1(0.75 + 0.25)
            this.Scale = 0.75 + 0.25 * ratio;
        }

Also call the scale changing method in SizeChanged event

        public CustomView()
        {
            InitializeComponent();
            this.SizeChanged += CustomView_SizeChanged;
        }

        private void CustomScrollView_SizeChanged(object sender, EventArgs e)
        {
            ChangeScale();
        }

Finally use it inside ScrollView 's BindableLayout 's ItemTemplate and bind the properties.

Sample page XAML

The Position is given in the Model of the Item.

<ScrollView
    Grid.Row="1"
    Orientation="Horizontal"
    x:Name="scrollview">
    <StackLayout
        Padding="0"
        Spacing="0"
        Orientation="Horizontal"
    BindableLayout.ItemsSource="{Binding CustomItems}">
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <local:CustomView
                WidthRequest="50"
                Padding="20"
                BackgroundColor="#aaff0000"
                Position="{Binding Position}"
                ScrolledPosition="{Binding Source={x:Reference scrollview}, Path=ScrollX}"
                ScrollViewWidth="{Binding Source={x:Reference scrollview}, Path=Width}">
                    <Grid Padding="20" BackgroundColor="#aaf000aa">
                        <Label Text="{Binding Position}"/>
                    </Grid>
                </local:CustomView>
        </DataTemplate>
    </BindableLayout.ItemTemplate>
        </StackLayout>
</ScrollView>

This might be a long way around but this is the only way I was able to achieve this.

Please do ask if any clarification is required.

Query 2

The button position can be achieved by many ways. I have listed a few below.

1:Using Grid column

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button
            Grid.Column="1"
            BackgroundColor="LightCoral"
            Text="Hi there"/>
</Grid>

2:Using Vertical and Horizontal option

    <Grid>
            <Button
                BackgroundColor="LightCoral"
                VerticalOptions="Center"
                HorizontalOptions="Center"
                Text="Hi there"/>
        </Grid>

3:Using AbsoluteLayout

<AbsoluteLayout>
                <Button
                    BackgroundColor="LightCoral"
                    AbsoluteLayout.LayoutFlags="All"
                    AbsoluteLayout.LayoutBounds="0.5,0.5,0.2,0.2"
                    Text="Hi there">
                </Button>
            </AbsoluteLayout>

Tried to achieve it in the simple binding but later found that a custom view could to be to achieve it easier hence posted this.

Hope this could help you.

You could use CardsView to do that.

CardsView : https://github.com/AndreiMisiukevich/CardView

Download the sample code from the GitHub. In CoverFlowSampleXamlView , the sample use the custom control PanCardView . The part of CoverFlowView could do the horizontal scrollview. In the sample code, it use the image, you could change it to the ImageButton .

CoverFlowSampleXamlView.xaml

Change:

<ffimage:CachedImage Source="{Binding Source}" Aspect="AspectFill"/>

To:

<ImageButton Source="{Binding Source}"></ImageButton>

CardsSampleViewModel.cs

Change the source. I add five images in the Resources/drawable folder.

Items = new ObservableCollection<object>
                 {
            new { Source = "a.jpg" },
            new { Source = "b.jpg" },
            new { Source = "dog.jpg" },
            new { Source = "c.jpg" },
            new { Source = "d.jpg" }
        };

Result:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM