Forum Xamarin.Forms

Xamarin.Forms How to check if View that in Grid that in ScrollView is visible

RedRaRedRa Member ✭✭✭

I have the issue with Grid that is in ScrollView
Some View-s in Grid is out of screen, but when I try get IsVisible for each view inside of Grid it return true ...
But really this View is out of screen ... How to get from code that this View is not visible due to ScrollView ?

Answers

  • RedRaRedRa Member ✭✭✭
  • NicoleLuNicoleLu Member, Xamarin Team Xamurai
    edited July 3

    @RedRa
    IsVisible for View is to tell whether this element is currently part of the visual tree or not. Or we can say, whether this element is actually created and rendererd in memory. For Grid, although some of the grids may be out of screen because of ScrollView, all elements in the grid layout were created at app start, so the IsVisible is always true.

    May I know why do you want to detect the grid that is out of screen? Maybe there's better options than scrollView + Grid.

  • igorkr_10igorkr_10 Member ✭✭✭✭

    @NicoleLu said:

    May I know why do you want to detect the grid that is out of screen? Maybe there's better options than scrollView + Grid.

    Don't know why author wants to do this. But I need to expand content and scroll to end if this content is not fully visible.

  • RedRaRedRa Member ✭✭✭

    @igorkr_10 said:

    @NicoleLu said:

    May I know why do you want to detect the grid that is out of screen? Maybe there's better options than scrollView + Grid.

    Don't know why author wants to do this. But I need to expand content and scroll to end if this content is not fully visible.

    Because I want to perform some animation and if I apply animation to all items even not visible it will decrease performance

  • NicoleLuNicoleLu Member, Xamarin Team Xamurai

    @igorkr_10 said:
    Don't know why author wants to do this. But I need to expand content and scroll to end if this content is not fully visible.

    Try CollectionView with snap

  • NicoleLuNicoleLu Member, Xamarin Team Xamurai

    @RedRa We can use current renderred view's position and scroll event arg to check if the view is on screen or not.

    First of all, add a method to respond to ScrollView's scroll event, and send the scroll message out with MessageCenter in the method:
    MainPage.xaml:

    <ScrollView Scrolled="ScrollView_Scrolled">
    ...
    </ScrollView>
    

    MainPage.xaml.cs:

    private void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
    {
        MessagingCenter.Send<MainPage, ScrolledEventArgs>(this, "Scroll", e);
    }
    

    Secondly, subclass the view that you want to add the animation and subscribe message with MessageCenter so that the view can check if it's on screen and if need to display annimation on its own:

    class MyBoxView: BoxView
    {
        public MyBoxView(): base()
        {
            MessagingCenter.Subscribe<MainPage, ScrolledEventArgs>(this, "Scroll", (sender, arg) =>
            {
                //this.Y is current renderred top left Y position of this BoxView, 
                //this.Height is current renderred Height of this BoxView, 
                //arg.ScrollY is current Y offset of ScrollView, 
                //You can print these values to see more and determine when you'd like to enable/disable annimation
                //There's also this.AnchorX AnchorY for View's CenterPoint
                double screenHeight = Application.Current.MainPage.Height;
                bool bottomIsHigher = (this.Y + this.Height) < arg.ScrollY;
                bool topIsLower = (this.Y) > arg.ScrollY + screenHeight;
    
                if (bottomIsHigher || topIsLower)
                {
                    //remove annimation here
                    Console.WriteLine($"MyBoxView {this.X}, {this.Y}: out of screen");
                }
                else
                {
                    //add annimation here
                    Console.WriteLine($"MyBoxView {this.X}, {this.Y}: on screen");
                }
            });
    
        }
    }
    

    Finally, use the MyBoxView in XAML:

    <ScrollView Scrolled="ScrollView_Scrolled">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="400" />
                <RowDefinition Height="400" />
                <RowDefinition Height="400" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <local:MyBoxView Color="Green" />
            <Label Text="Row 0, Column 0" HorizontalOptions="Center" VerticalOptions="Center" />
            <local:MyBoxView Grid.Column="1" Color="Blue" />
            <Label Grid.Column="1" Text="Row 0, Column 1" HorizontalOptions="Center" VerticalOptions="Center" />                                                        <local:MyBoxView Grid.Row="1"
                 Color="Teal" />
                <Label Grid.Row="1"
               Text="Row 1, Column 0"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
                <local:MyBoxView Grid.Row="1"
                 Grid.Column="1"
                 Color="Purple" />
                <Label Grid.Row="1"
               Grid.Column="1"
               Text="Row1, Column 1"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
                <local:MyBoxView Grid.Row="2"
                 Grid.ColumnSpan="2"
                 Color="Red" />
                <Label Grid.Row="2"
               Grid.ColumnSpan="2"
               Text="Row 2, Columns 0 and 1"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
            </Grid>
        </ScrollView>
    
  • CalebSkinnerCalebSkinner USMember ✭✭

    Hello there @NicoleLu ,

    How do you unsubscribe from this message?

    Thanks,

    Caleb

  • NicoleLuNicoleLu Member, Xamarin Team Xamurai

    Hi @CalebSkinner

    Unsubscribe from MyBoxView may be a bit difficult, we can just add a flag in MainPage.xaml.cs and control message sender from ScrollView_Scrolled.

    bool enableScrollMessage = true;
    //...
    private void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
    {
        if(enableScrollMessage){
            MessagingCenter.Send<MainPage, ScrolledEventArgs>(this, "Scroll", e);
        }
    }
    
  • CalebSkinnerCalebSkinner USMember ✭✭

    Hi @NicoleLu ,

    Isn't a memory leak being created then? How does the ViewBox get recycled with subscription in place?

Sign In or Register to comment.