user8099525
user8099525

Reputation: 41

How to get a renderBox from an item element in listview in flutter

I have a ListView, and I want the first visible item to increase its size. I've been trying to set a GlobalKey for each element in the listview to get its RenderBox object and get the 'dx' property, so the element with the less 'dx' value greater than 0 is the element which I'm increasing its size.

It only works when the user scrolls the first items, but then I found out it's not possible for the next elements because their RenderBox object is null. As far as I know this is happening because of listview lazy loading, but I don't understand why is it null if I can see that item.

Is there a way to get its renderbox or another way to increase the size of the first visible element?

Upvotes: 1

Views: 1417

Answers (1)

YoBo
YoBo

Reputation: 2529

You will need to rebuild list items while scrolling in order for this to work. You can use ScrollController as animation for AnimatedBuilder.

Working example:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MyPage());
  }
}

class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  // We will use this for AnimatedBuilder and ListView
  final scrollController = ScrollController();

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        body: SafeArea(
          child: ListView.separated(
            controller: scrollController,
            itemCount: 100,
            separatorBuilder: (context, index) => SizedBox(height: 8.0),
            itemBuilder: (context, index) => ItemView(
              index: index,
              scrollController: scrollController,
            ),
          ),
        ),
      );
}

class ItemView extends StatelessWidget {
  final int index;
  final ScrollController scrollController;

  const ItemView({
    Key key,
    @required this.index,
    @required this.scrollController,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) => AnimatedBuilder(
        animation: scrollController,
        builder: (context, widget) {
          final renderObject = context.findRenderObject() as RenderBox;
          final offsetY = renderObject?.localToGlobal(Offset.zero)?.dy ?? 0;
          print('$index: $offsetY');
          // Use offsetY(or X) for your effect
          return Container(
            height: 44.0,
            color: Colors.pink[100],
            alignment: Alignment.center,
            child: Text(index.toString()),
          );
        },
      );
}

Upvotes: 2

Related Questions