¿Cómo encontrar un elemento en algún punto en ListView en Flutter?

Aug 18 2020

¿Necesito encontrar debajo del elemento/índice de puntos en ListView? ¿Es posible conseguirlo? cualquiera ListView.Builder / CustomScrollView / ..._ cuando el elemento/índice de desplazamiento debe actualizarse en tiempo real. ej: 'El índice central es $índice'

esta posición de la línea roja puede cambiar. tal vez centro, tal vez arriba/abajo/0.25/0.75...

y también la altura del artículo puede ser fija/tal vez flexible

Respuestas

1 chunhunghan Aug 18 2020 at 14:22

Puede copiar y pegar ejecutar el código completo a continuación
Puede usar el paquetehttps://pub.dev/packages/inview_notifier_list
Con el atributo isInViewPortConditiony envolver el elemento InViewNotifierWidget, este tamaño permitido es flexible, vea la demostración de trabajo
Para CustomScrollViewpoder usar InViewNotifierCustomScrollView, el ejemplo está aquíhttps://github.com/rvamsikrishna/inview_notifier_list/blob/master/example/lib/csv_example.dart
fragmento de código

isInViewPortCondition:
          (double deltaTop, double deltaBottom, double viewPortDimension) {
        return deltaTop < (0.5 * viewPortDimension) &&
            deltaBottom > (0.5 * viewPortDimension);
      },
...
InViewNotifierWidget(
        id: '$index',
        builder:
            (BuildContext context, bool isInView, Widget child) {
          if (isInView) {
            inviewIndex = index.toString();
            callback();
          }
          return Container(
              height: index.isEven? 50 : 150 ,
              width: double.infinity,
              color: Colors.blue,
              child: Text("$index ${isInView.toString()}"));
        },
      );

código completo

import 'package:flutter/material.dart';
import 'package:inview_notifier_list/inview_notifier_list.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(
        title: "test",
      ),
    );
  }
}

String inviewIndex = "";

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  refresh() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {});
    });
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text("Center index is $inviewIndex"),
            Expanded(
                child: ImageList(
              callback: refresh,
            ))
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ImageList extends StatelessWidget {
  VoidCallback callback;
  ImageList({this.callback});

  @override
  Widget build(BuildContext context) {
    return Stack(
      fit: StackFit.expand,
      children: <Widget>[
        InViewNotifierList(
          scrollDirection: Axis.vertical,
          initialInViewIds: ['0'],
          isInViewPortCondition:
              (double deltaTop, double deltaBottom, double viewPortDimension) {
            return deltaTop < (0.5 * viewPortDimension) &&
                deltaBottom > (0.5 * viewPortDimension);
          },
          itemCount: 10,
          builder: (BuildContext context, int index) {
            return Container(
              width: double.infinity,
              height: 100.0,
              alignment: Alignment.center,
              margin: EdgeInsets.symmetric(vertical: 50.0),
              child: LayoutBuilder(
                builder: (BuildContext context, BoxConstraints constraints) {
                  return InViewNotifierWidget(
                    id: '$index',
                    builder:
                        (BuildContext context, bool isInView, Widget child) {
                      if (isInView) {
                        inviewIndex = index.toString();
                        callback();
                      }
                      return Container(
                          height: index.isEven? 50 : 150 ,
                          width: double.infinity,
                          color: Colors.blue,
                          child: Text("$index ${isInView.toString()}"));
                    },
                  );
                },
              ),
            );
          },
        ),
        Align(
          alignment: Alignment.center,
          child: Container(
            height: 1.0,
            color: Colors.redAccent,
          ),
        )
      ],
    );
  }
}
2 JigarPatel Aug 18 2020 at 13:06

Una forma de hacerlo es algo como esto usando ScrollControllery NotificationListener.

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  ScrollController sc = ScrollController();
  int centerItemIndex;
  double screenHeight;

  @override
  Widget build(BuildContext context) {
    
    screenHeight = MediaQuery.of(context).size.height;
    if(centerItemIndex == null){
      centerItemIndex = ((screenHeight/2)/50).floor();    //50 is the height of 1 item
      print('center item = $centerItemIndex');
    }
    
    return Stack(
      children: [
        NotificationListener(
          child: ListView.builder(
            controller: sc,
            itemCount: 50,
            itemBuilder: (ctx, index) {
              return Container(
                height: 50,
                color: Colors.green,
                child: Center(child: Text('$index')),
              );
            },
          ),
          onNotification: (_) {
            int calculatedIndex = ((sc.position.pixels + screenHeight/2)/50).floor();
            if(calculatedIndex != centerItemIndex){
              centerItemIndex = calculatedIndex;
              print('center item = $centerItemIndex');
            }
            return true;
          },
        ),
        Center(
          child: Container(
            height: 2,
            color: Colors.red,
          ),
        ),
      ],
    );
  }
}
1 MAlkhatib Aug 18 2020 at 14:00

La solución está aquíhttps://github.com/google/flutter.widgets

intente usar: scrollable_positioned_list