1

My actual app is a lot more complex but this is a simpler example which can reproduce this issue.

My CupertinoScrollbar is inside a Padding widget with top padding of 300. Ideally, I want the rows in the List to scroll up the entire "padding area" before disappearing. However, as you notice, the rows disappear as soon as it goes into the padding area.

Even though I have defined clipBehavior: Clip.none, it still disappears as soon as it enters the padding area.

If I remove the clipBehavior: Clip.none, then the row is simply clipped as soon as it enters the padding area instead of entirely being removed after it goes out.

How can I make sure the rows don't get removed UNTIL they go outside the padding (in this case, the top edge of screen)?

I think the clipBehavior: Clip.none should only clip items which are outside the bounds of the Widget and should take padding into account.

On iOS, UITableView's contentInset property let me achieve this.

enter image description here

enter image description here

Here's my code:

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

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ScrollController scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.only(top: 300),
        child: CupertinoScrollbar(
          controller: scrollController,
          child: CustomScrollView(
            clipBehavior: Clip.none,
            controller: scrollController,
            slivers: [
              SliverList(
                delegate: SliverChildListDelegate(
                  List.generate(words.length, (index) {
                    return Padding(
                      padding: const EdgeInsets.only(left: 8.0, right: 8.0),
                      child: Card(
                        child: ListTile(
                          title: Text("$index. ${words[index]}"),
                          onTap: () {
                            setState(() {
                              words.removeAt(index);
                            });
                          },
                        ),
                      ),
                    );
                  }),
                ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(
          Icons.add_rounded,
          size: 35,
          color: Colors.white,
        ),
        onPressed: () {
          setState(() {
            addWords(howMany: 1);
          });
        },
      ),
    );
  }
}
  • Does it need to be a `Padding`, or do you want only to have this 300 pixels height area looking different and non-tappable? – Peter Koltai Aug 30 '22 at 05:53
  • I think Padding would be best. Workaround solutions like returning a `Padding` widget for the first index item has unfortunate side effects which I explained below to @mohammad's answer. – sudoExclaimationExclaimation Aug 30 '22 at 07:07

1 Answers1

1

You can use index to solve this problem,

remove the padding above and use like this:

List.generate(words.length, (index) {
    if (index == 0) {
        return Padding(
            padding: EdgeInsets.only(top: 300),
        );
    }
    index = index - 1; // remember to minus the index too
...
}

result

mohammad esmaili
  • 1,614
  • 2
  • 4
  • 17