Mike Wiggens 442
Mike Wiggens 442

Reputation: 109

Disable ScrollView in Xamarin Forms without disabling buttons

I have the following XAML. I want to target phones with a scrollview, and want scrolling disabled on a tablet.

 <ScrollView InputTransparent="False" Orientation="Both" >

            <ScrollView.IsEnabled>
                <OnIdiom x:TypeArguments="x:Boolean">

                    <OnIdiom.Phone>True</OnIdiom.Phone>
                    <OnIdiom.Tablet>True</OnIdiom.Tablet>
                </OnIdiom>
            </ScrollView.IsEnabled>

    <StackLayout VerticalOptions="FillAndExpand" BackgroundColor="White" >
                <StackLayout.HorizontalOptions>
                    <OnIdiom x:TypeArguments="LayoutOptions">
                        <OnIdiom.Tablet>FillAndExpand</OnIdiom.Tablet>
                        <OnIdiom.Phone>Start</OnIdiom.Phone>
                    </OnIdiom>

                </StackLayout.HorizontalOptions>

                <Grid BackgroundColor="White" HeightRequest="65" MinimumHeightRequest="65">
                    <Grid.HorizontalOptions>
                        <OnIdiom x:TypeArguments="LayoutOptions">
                            <OnIdiom.Tablet>CenterAndExpand</OnIdiom.Tablet>
                            <OnIdiom.Phone>Start</OnIdiom.Phone>
                        </OnIdiom>

                    </Grid.HorizontalOptions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition  Width="Auto"  />
                    </Grid.ColumnDefinitions>
                    <WebView x:Name="webViewBtn1" HeightRequest="65" Grid.Column="0" Grid.ColumnSpan="1"  VerticalOptions="FillAndExpand" BackgroundColor="White">
                    <WebView.HorizontalOptions>
                        <OnIdiom x:TypeArguments="LayoutOptions">
                            <OnIdiom.Tablet>CenterAndExpand</OnIdiom.Tablet>
                            <OnIdiom.Phone>Start</OnIdiom.Phone>
                        </OnIdiom>
                    </WebView.HorizontalOptions>
                        <WebView.WidthRequest>
                            <OnIdiom x:TypeArguments="x:Double">
                                <OnIdiom.Tablet>770</OnIdiom.Tablet>
                                <OnIdiom.Phone>300</OnIdiom.Phone>

                            </OnIdiom>

                        </WebView.WidthRequest>
                    </WebView>
                    <Button Grid.Column="0" Grid.ColumnSpan="1" x:Name="btn1" Clicked="btn1_Clicked" BackgroundColor="Transparent" TextColor="Transparent"  BorderColor="White" />
                </Grid>
    </StackLayout>
        </ScrollView>

the buttons no longer allow the user to click on them if I set ScrollView.IsEnabled the following way:

  <OnIdiom.Tablet>False</OnIdiom.Tablet>

My assumption that using InputTransparent was not correct. Is there a way to make the buttons clickable inside a scroll view that has scrolling disabled?

I essentially am looking for something like Orientation=None, but that is not an option.

Upvotes: 5

Views: 10522

Answers (4)

Moataz Hossam
Moataz Hossam

Reputation: 413

In the latest version of Xamarin Forms, you can set the Orientation to Neither.

scrollV.Orientation = ScrollOrientation.Neither;

Upvotes: 5

Alex Perelberg
Alex Perelberg

Reputation: 31

Cool and compact way to disable scrolling in Xamarin Forms without affecting it's children through ScrollEnabled extension method:

public static class ScrollViewEx
{
    /// <summary>
    /// Disables scrollview by modifying Scrolled Event and attaching itself to ScrollView's binding context
    /// Scrolled event sends it back to the original x,y
    /// </summary>
    public class DisabledScrollClass : IDisposable
    {
        private double ScrollX;
        private double ScrollY;
        private object OldContext;
        private ScrollView Parent;

        public DisabledScrollClass(ScrollView parent)
        {
            Parent = parent;
            ScrollX = parent.ScrollX;
            ScrollY = parent.ScrollY;
            OldContext = parent.BindingContext;
            parent.Scrolled += Scrolled;
            parent.BindingContext = this;
        }

        private void Scrolled(object sender, ScrolledEventArgs e)
        {
            (sender as ScrollView)?.ScrollToAsync(ScrollX, ScrollY, false);
        }

        public void Dispose()
        {
            Parent.Scrolled -= Scrolled;
            Parent.BindingContext = OldContext;
        }
    }

    public static ScrollView ScrollEnabled(this ScrollView scroll, bool isEnabled)
    {
        DisabledScrollClass binding = scroll.BindingContext as DisabledScrollClass;
        if (isEnabled && binding != null)
            binding.Dispose();
        if (!isEnabled && binding == null)
            _ = new DisabledScrollClass(scroll);
        return scroll;
    }
}

Upvotes: 1

Mike Wiggens 442
Mike Wiggens 442

Reputation: 109

I ended up using this approach to disable vertical scrolling on an iPad, which is my target device. Not perfect for android 7 inch tablets, but oh well:

            <ScrollView.Orientation>
                <OnPlatform x:TypeArguments="ScrollOrientation">
                    <On Platform="iOS">
                        <OnIdiom x:TypeArguments="ScrollOrientation">
                            <OnIdiom.Phone>Both</OnIdiom.Phone>
                            <OnIdiom.Tablet>Horizontal</OnIdiom.Tablet>
                        </OnIdiom>
                    </On>
                    <On Platform="Android">
                        <OnIdiom x:TypeArguments="ScrollOrientation">
                            <OnIdiom.Phone>Both</OnIdiom.Phone>
                            <OnIdiom.Tablet>Both</OnIdiom.Tablet>
                        </OnIdiom>
                    </On>
                    <On Platform="UWP">Both</On>
                </OnPlatform>
            </ScrollView.Orientation>

Upvotes: 4

Ranga
Ranga

Reputation: 1108

You need to write a CustomRenderer for disabling the scroll.

On iOS UIScrollView has a ScrollEnabled property

protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
    base.OnElementChanged(e);
    // IsScrollEnabled just a custom property
    // handled it in OnPropertyChanged too
    ScrollEnabled = Element.IsScrollEnabled;
}

Android it is a bit tricky, there is not direct property. We intercept the touch event and return without handling it.

public override bool OnInterceptTouchEvent(MotionEvent ev)
{
    if (Element.IsScrollEnabled)
    {
        return base.OnInterceptTouchEvent(ev);
    }
    else
    {
        return false;
    }
}

public override bool OnTouchEvent(MotionEvent ev)
{
    if (Element.IsScrollEnabled)
    {
        return base.OnTouchEvent(ev);
    }
    else
    {
        return false;
    }
}

Upvotes: 8

Related Questions