Home > Software engineering >  Flutter || Scroll back to top button
Flutter || Scroll back to top button

Time:03-07

In my flutter project I made a floating button that help to auto scroll to the top of the page with one click, and when it reach the top it disappear. It work perfectly. But my problem is that I need to double click in it so it can disappear I want it to automatically disappear if it reach the top. Any help is highly appreciated.

     void scrollToTop(){
    _controller.runJavascript("window.scrollTo({top: 0, behavior: 'smooth'});");
    floatingButtonVisibility();
  }

  void floatingButtonVisibility() async {
    int y = await  _controller.getScrollY();
    if(y>50){
      setState(() {
        buttonshow = true;
      });
    }else {
      setState(() {
        buttonshow = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
      ),
      body:  WebView(
          initialUrl: 'https://flutter.dev',
          javascriptMode: JavascriptMode.unrestricted,
          onWebViewCreated: (WebViewController webViewController) {
            _controller = webViewController;
          },
          gestureRecognizers: Set()
            ..add(
                Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer()
                  ..onDown = (tap) {
                    floatingButtonVisibility();
                  }))

      ),
      floatingActionButton: Visibility(
        visible: buttonshow,
        child: FloatingActionButton(
          onPressed: () {
            scrollToTop();
          },
          backgroundColor: Colors.blue,
          child: const Icon(Icons.navigation),
        ),
      ),
    );
  }
}

CodePudding user response:

Here is my solution.

  1. Register 'window.onscroll' in to send webview's scroll position to outside of Webview widget.
  2. Register receiver to receive event from webview.
  3. If scroll is 0, change 'buttonshow' value and rebuild widget.

enter image description here

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.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: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  WebViewController _controller;
  bool buttonshow = false;

  @override
  void initState() {
    super.initState();
  }

  void scrollToTop() {
    _controller.evaluateJavascript(
        "window.onscroll = function () {scrollEventChannel.postMessage(window.scrollY)};");
    _controller
        .evaluateJavascript("window.scrollTo({top: 0, behavior: 'smooth'});");
    floatingButtonVisibility();
  }

  void floatingButtonVisibility() async {
    int y = await _controller.getScrollY();
    if (y > 50) {
      setState(() {
        buttonshow = true;
      });
    } else {
      setState(() {
        buttonshow = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
      ),
      body: WebView(
          initialUrl: 'https://flutter.dev',
          javascriptMode: JavascriptMode.unrestricted,
          onWebViewCreated: (WebViewController webViewController) {
            _controller = webViewController;
          },
          javascriptChannels: {
            JavascriptChannel(
                name: 'scrollEventChannel',
                onMessageReceived: (JavascriptMessage message) {
                  print('>>>>: ${message.message}');
                  if (message.message == '0') {
                    setState(() {
                      buttonshow = false;
                    });
                  }
                }),
          },
          gestureRecognizers: Set()
            ..add(Factory<VerticalDragGestureRecognizer>(
                () => VerticalDragGestureRecognizer()
                  ..onDown = (tap) {
                    floatingButtonVisibility();
                  }))),
      floatingActionButton: Visibility(
        visible: buttonshow,
        child: FloatingActionButton(
          onPressed: () {
            scrollToTop();
          },
          backgroundColor: Colors.blue,
          child: const Icon(Icons.navigation),
        ),
      ),
    );
  }
}

I changed button show trigger from gestureRecognizers to postion event.

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.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: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  WebViewController _controller;
  bool buttonshow = false;

  @override
  void initState() {
    super.initState();
  }

  void scrollToTop() {
    _controller
        .evaluateJavascript("window.scrollTo({top: 0, behavior: 'smooth'});");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
      ),
      body: WebView(
        initialUrl: 'https://flutter.dev',
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
          _controller = webViewController;
        },
        onPageFinished: (String url) async {
          _controller.evaluateJavascript(
              "window.onscroll = function () {scrollEventChannel.postMessage(window.scrollY)};");
        },
        javascriptChannels: {
          JavascriptChannel(
              name: 'scrollEventChannel',
              onMessageReceived: (JavascriptMessage message) {
                print('>>>>: ${message.message}');

                int position = int.parse(message.message);
                if (position == 0) {
                  setState(() {
                    buttonshow = false;
                  });
                } else if (position > 60) {
                  setState(() {
                    buttonshow = true;
                  });
                }
              }),
        },
      ),
      floatingActionButton: Visibility(
        visible: buttonshow,
        child: FloatingActionButton(
          onPressed: () {
            scrollToTop();
          },
          backgroundColor: Colors.blue,
          child: const Icon(Icons.navigation),
        ),
      ),
    );
  }
}

CodePudding user response:

Here is the code that helped me:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
  // this variable determnines whether the back-to-top button is shown or not
  bool _showBackToTopButton = false;

  // scroll controller
  late ScrollController _scrollController;

  @override
  void initState() {
    _scrollController = ScrollController()
      ..addListener(() {
        setState(() {
          if (_scrollController.offset >= 400) {
            _showBackToTopButton = true; // show the back-to-top button
          } else {
            _showBackToTopButton = false; // hide the back-to-top button
          }
        });
      });

    super.initState();
  }

  @override
  void dispose() {
    _scrollController.dispose(); // dispose the controller
    super.dispose();
  }

  // This function is triggered when the user presses the back-to-top button
  void _scrollToTop() {
    _scrollController.animateTo(0,
        duration: const Duration(seconds: 3), curve: Curves.linear);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Kindacode.com'),
      ),
      body: SingleChildScrollView(
        controller: _scrollController,
        child: Column(
          children: [
            // add a bunch of containers to make the screen longer
            Container(
              height: 600,
              color: Colors.amber,
            ),
            Container(
              height: 600,
              color: Colors.blue[100],
            ),
            Container(
              height: 600,
              color: Colors.red[200],
            ),
            Container(
              height: 600,
              color: Colors.orange,
            ),
            Container(
              height: 600,
              color: Colors.yellow,
            ),
            Container(
              height: 1200,
              color: Colors.lightGreen,
            ),
          ],
        ),
      ),
      // This is our back-to-top button
      floatingActionButton: _showBackToTopButton == false
          ? null
          : FloatingActionButton(
              onPressed: _scrollToTop,
              child: const Icon(Icons.arrow_upward),
            ),
    );
  }
}
  • Related