Flutter의 ListView에서 항목을 찾는 방법은 무엇입니까?

Aug 18 2020

ListView에서 포인트 항목 / 색인 아래를 찾아야합니까? 그것을 얻을 수 있습니까? 모든 ListView.Builder / CustomScrollView / .... 스크롤 할 때 항목 / 색인이 실시간으로 업데이트되어야합니다. 예 : 'Center index is $ index'

이 빨간 선 위치는 바뀔 수 있습니다. 아마도 중앙, 아마도 위 / 아래 /0.25/0.75 ...

항목 높이도 고정 / 유연 할 수 있습니다.

답변

1 chunhunghan Aug 18 2020 at 14:22

아래에 붙여 넣기 실행 전체 코드를 복사
할 수 있습니다.https://pub.dev/packages/inview_notifier_list
속성 isInViewPortCondition및 래핑 항목을 InViewNotifierWidget사용하면 크기가 유연합니다. 작업 데모
를 참조하십시오. CustomScrollViewcan use InViewNotifierCustomScrollView에 대한 예는 여기에 있습니다.https://github.com/rvamsikrishna/inview_notifier_list/blob/master/example/lib/csv_example.dart
코드 조각

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()}"));
        },
      );

전체 코드

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

이 작업을 수행 할 수있는 한 가지 방법은 ScrollController및을 사용하는 것과 같습니다 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

해결책은 여기 https://github.com/google/flutter.widgets

사용해보십시오 : scrollable_positioned_list