จะค้นหารายการในบางจุดใน ListView ใน Flutter ได้อย่างไร?

Aug 18 2020

ฉันต้องการค้นหาด้านล่างรายการจุด / ดัชนีใน ListView? เป็นไปได้หรือไม่? ListView.Builder / CustomScrollView / ...ใด เมื่อเลื่อนรายการ / ดัชนีควรอัปเดตแบบเรียลไทม์ เช่น 'Center index คือ $ index'

ตำแหน่งเส้นสีแดงนี้สามารถเปลี่ยนแปลงได้ อาจจะตรงกลางอาจจะบน / ล่าง / 0.25 / 0.75 ...

และความสูงของรายการอาจคงที่ / อาจยืดหยุ่นได้

คำตอบ

1 chunhunghan Aug 18 2020 at 14:22

คุณสามารถคัดลอกวางรันโค้ดเต็มด้านล่าง
คุณสามารถใช้แพคเกจhttps://pub.dev/packages/inview_notifier_list
ด้วยแอตทริบิวต์isInViewPortConditionและรวมรายการในInViewNotifierWidgetขนาดที่อนุญาตนี้มีความยืดหยุ่นดูการสาธิตการใช้งาน
สำหรับCustomScrollViewสามารถใช้ได้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

วิธีหนึ่งที่คุณสามารถทำเช่นนี้เป็นสิ่งที่ต้องการนี้โดยใช้และScrollControllerNotificationListener

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