CollectionView dentro de un ScrollView en Xamarin.Forms

Contenido

Aprende como utilizar el CollectionView dentro de un ScrollView en Xamarin.Forms. En algunas ocasiones queremos desarrollar algunas funcionalidades que necesitan que se muestren diferentes contextos de datos dentro de la misma pagina y esto se puede lograr con un TemplateSelector si la fuente de datos es la misma, pero si no es la misma ¿como lo hacemos?.

En este articulo compartiré contigo un control personalizado del CollectionView que puedes utilizar directamente en tus proyectos o simplemente adaptarlo a tus necesidades si es lo que quieres.

🚨 Nota: Este articulo y todas las informaciones aquí presentados son con motivos educativos. No es recomendable utilizar un CollectionView o ListView dentro de un ScrollView con las técnicas que comparto en este post.

Mas información aquí.

Este articulo pertenece a los calendarios de adviento Xamarin y C#. Te recomiendo que veas todos los artículos que se han publicado.

CollectionView dentro de un ScrollView

Antes de mostrarte el control y como funciona necesito que entiendas que no siempre es muy recomendable poner un CollectionView dentro de un ScrollView sencillamente porque ambos controles tienen scroll y al utilizarlos juntos puedes tener Experiencias de Usuarios (UX) no deseadas.

A continuación te muestro un ejemplo de como se comporta un CollectionView dentro de un ScrollView:

CollectionView dentro de un ScrollVIew.
Nota: El header mostrado no pertenece al CollectionView.

Si te fijas bien, hasta que el CollectionView no llega hasta el fondo de la lista de items que maneja, el ScrollView no hace Scroll al menos que hagas scroll desde el header el cual no pertenece al CollectionView.

¿Por qué utilizar un CollectionView dentro de un ScrollView?

Les mostrare un caso particular y muy popular para que puedan entender. Este es la pagina de usuario de Instagram. Vamos a verla:

Si se fijan, debajo de las historias, están los TabsView que nos permiten visualizar diferentes tipos de datos y contextos.

💡 Nota: Anteriormente, Instagram mostraba en los TabsView el tipo de vista que querías ver en la pagina ya sea Grid o Lista. Este comportamiento en Xamarin.Forms puede ser logrado con un TemplateSelector siempre y cuando el contexto de datos sea el mismo.

Aquí el desafío es que el CollectionView no es muy extensible que digamos, y no permite lograr esta funcionalidad de una manera natural, por lo menos en lo que puede investigar.

Es por ello que decidí crear el siguiente control.

Custom CollectionView

Realmente el control es algo muy simple pero que aplica algunos conceptos poderosos. Lo que haremos sera deshabilitar el scroll del CollectionView con el objetivo de utilizar solamente el scroll del ScrollView. Para esto solo tenemos que calcular el alto total de todos los items y definir ese alto al CollectionView.

Para lograr esto hemos definido algunos parámetros por defecto como:

  • ScrollView, de tipo ScroolView, recibe la instancia del ScrollView padre y tiene un valor por defecto de null.
  • RowHeigt, de tipo int, recibe el alto predefinido de las filas que estra utilizando el control, valor por defecto 0.


Con estos parámetros podemos tener un CustomCollactionView de la siguiente manera:

    public class CustomCollectionView : CollectionView
    {
...
        [TypeConverter(typeof(ReferenceTypeConverter))]
        public ScrollView ScrollView
        {
            set
            {
                _scrollView = value;
                _scrollView.Scrolled += _scrollView_Scrolled;
            }
        }
...
        private void _scrollView_Scrolled(object sender, ScrolledEventArgs e)
        {
            double scrollingSpace = _scrollView.ContentSize.Height - _scrollView.Height;
            if (scrollingSpace <= e.ScrollY)
            {
                // Touched bottom view
                RemainingItemsThresholdReachedCommand?.Execute(RemainingItemsThresholdReachedCommandParameter);
            }
        }

        private void UpdateHeight()
        {
            if(_columns  == 0)
            {
                if (ItemsLayout is GridItemsLayout layout)                
                    _columns = layout.Span;
                else
                    _columns = 1;
            }

            if (_rowHeigt > 0)            
                HeightRequest = (_rowHeigt * _rowCount) / _columns;
        }

        protected override void OnChildAdded(Element child)
        {
            base.OnChildAdded(child);
            UpdateHeight();
        }
        
        protected override void OnChildRemoved(Element child, int oldLogicalIndex)
        {
            base.OnChildRemoved(child, oldLogicalIndex);
            UpdateHeight();
        }
    }

Cada vez que se agregue, o se elimine, un item se actualizara el alto del CollectionView. De igual manera, si tocamos el fondo del ScrollView ejecutaremos el RemainingItemsThresholdReachedCommand del CollectinView para asegurarnos de que el comportamiento sea igual en todos los sentidos.

Una vez tenemos el control, lo podemos utilizar en nuestros proyectos de Xamarin Forms. Aquí un ejemplo en XAML:

...
    <ScrollView x:Name="myScrollView">
        <StackLayout>

            <!-- YOURS CONTROLS GOES HERE -->

            <ctrls:CustomCollectionView
                ItemSizingStrategy="MeasureFirstItem"
                ItemsLayout="VerticalGrid, 3"
                ItemsSource="{Binding Items}"
                RowHeigt="120"
                ScrollView="myScrollView">

                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        ...
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </ctrls:CustomCollectionView>

        </StackLayout>
    </ScrollView>
...

Con esto podemos obtener un comportamiento similar al de la pagina de perfil de Instagram. Veamos un ejemplo:

CollectionView dentro de un ScrollVIew.
Nota: El header mostrado no pertenece al CollectionView.

Conclusión

Como pueden ver este es un control muy simple pero poderoso, que apuesto que a mas de uno puede ayudar. La implementación es bastante simple, y muy sencillo de entender.

Nota: Hay una limitante. El control no funciona con filas que tienen alturas dinámicas, porque estamos calculando campos predefinidos.

Espero que este articulo de sea de utilidad, y nada déjenme saber en las redes que realmente les gusta este tipo de artículos y yo hare lo posible por darles lo mejor de lo mejor.

Ayuda a crecer nuestra comunidad y desbloquea el contenido debajo para acceder al repo de ejemplo. ⬇⬇⬇

Sin nada mas que agregar, ¡Nos vemos en la próxima!

¿Qué opinas de este contenido?
 
Luis Matos

Luis Matos

I help professionals and companies to create value solutions. I am a Systems Engineer, blockchain executive, and international mobile application speaker. Founder of the Malla Consulting Agency and several international technology communities.
Suscribirte
Notificar de
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x

Buscar en el sitio