Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Last active January 27, 2021 00:28
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save slightfoot/9ab7a861468780b9c155d941bf71c8f7 to your computer and use it in GitHub Desktop.
Save slightfoot/9ab7a861468780b9c155d941bf71c8f7 to your computer and use it in GitHub Desktop.
Ever wanted to scroll down to a widget in a scroll view? Now you can, Anchor Scroll to the rescue! - by Simon Lightfoot - 15/11/2019
// MIT License
//
// Copyright (c) 2019 Simon Lightfoot
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import 'package:flutter/material.dart';
/// Example: context.anchorScroll(Key('test'));
extension AnchorScrollContext on BuildContext {
Future<void> anchorScroll(
Key anchorKey, {
duration = const Duration(milliseconds: 350),
curve = Curves.easeOutExpo,
}) =>
scrollToAnchor(this, anchorKey, duration: duration, curve: curve);
}
Future<void> scrollToAnchor(
BuildContext context,
Key anchorKey, {
duration = const Duration(milliseconds: 350),
curve = Curves.easeOutExpo,
}) {
Element? found;
void visitElement(Element el) {
if (el.widget.key == anchorKey) {
found = el;
return;
}
el.visitChildren(visitElement);
}
context.visitChildElements(visitElement);
if (found == null) {
throw StateError('No widget with key found');
}
final scrollable = Scrollable.of(context);
if (scrollable == null) {
throw StateError('Widget not in scrollable context');
}
final scrollableBox = scrollable.context.findRenderObject();
final anchorBox = found!.findRenderObject() as RenderBox?;
if (anchorBox == null || scrollableBox == null) {
throw StateError('Widget not laid out. Try SingleChildScrollView.');
}
final anchorOffset = anchorBox.localToGlobal(
Offset.zero,
ancestor: scrollableBox,
);
return scrollable.position.animateTo(
scrollable.position.pixels + anchorOffset.dy,
duration: duration,
curve: curve,
);
}
@SergioEric
Copy link

Hi Simon, i tried this:

body:ListView(
    children: List.generate(500, (index) {
      return ListTile(
        key: Key("$index"),
        title: Text(
          "Index $index",
        ),
      );
    }).toList(),
  ),
floatingActionButton: FloatingActionButton(
    child: Text("~"),
    onPressed: () {
      context.anchorScroll(Key("499"));
    },
),

but i got Bad state: No widget with key found
Could you helping me by providing a simple example ?

@slightfoot
Copy link
Author

@SergioEric use a SingleChildScrollView

@zahidshaikh08
Copy link

zahidshaikh08 commented Jan 16, 2021

body: SingleChildScrollView(
        child: Column(
          children: List.generate(500, (index) {
            return ListTile(
              key: Key("$index"),
              title: Text(
                "Index $index",
              ),
            );
          }).toList(),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          context.anchorScroll(Key(Random().nextInt(499).toString()));
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),

context.anchorScroll(Key(Random().nextInt(499).toString()));

Same thing goes for listview.builder can you please share example...??

Screenshot_1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment