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.
- Register 'window.onscroll' in to send webview's scroll position to outside of Webview widget.
- Register receiver to receive event from webview.
- If scroll is 0, change 'buttonshow' value and rebuild widget.
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),
),
);
}
}