If nothing is done on the screen, I want to print something on the screen some time after the last action. How can I do that? How can I check the screen click status?
CodePudding user response:
A naive approach could involve a Timer
with dart:async
.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: _SomeWidget(),
);
}
}
class _SomeWidget extends StatefulWidget {
const _SomeWidget();
@override
State<_SomeWidget> createState() => _SomeWidgetState();
}
class _SomeWidgetState extends State<_SomeWidget> {
late Timer _timer;
@override
void initState() {
super.initState();
// It's up to you if you want the timer to start immediately with some effects or not.
_timer = Timer(const Duration(seconds: 1), () {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
// i.e. from the first interaction and so on
_timer.cancel();
_timer = Timer(const Duration(seconds: 1), () {
if (mounted) {
// !
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Some message')),
);
}
});
},
child: const Center(child: Text('My screen contents')),
),
);
}
}
The mounted
check is very important, as Timer
introduces an async gap, which may be dangerous when using context
.
CodePudding user response:
You can add a Gesture detector at the top level and start a timer on tap and on completion you can fire an event like the following
GestureDetector(
onTap: (){
startTimer();
}
child: Column(
children:[
//all other widgets
]
)
),
Then to define the timer
late Timer _timer;
void startTimer()
{
if(_timer != null && _timer.isActive) _timer.cancel();
_timer = Timer(
const Duration(seconds: 30),
() {
print("inactive for 30 seconds");
},
);
}
here in this case each time the user taps on the screen the timer is restarted and on 30th second the print is fired.
CodePudding user response:
You can wrap Scaffold with GestureDetector
and use onPanDown
to capture the screen event, onTap
doesn't win on hit test if there are inner clickable buttons. Also use behavior: HitTestBehavior.translucent,
Another notable thing is here, it is needed to be check on every second, because the checkup unit is on second. You can create a wrapper widget from it.
class ScreenT extends StatefulWidget {
const ScreenT({Key? key}) : super(key: key);
@override
State<ScreenT> createState() => _ScreenTState();
}
class _ScreenTState extends State<ScreenT> {
@override
void dispose() {
timer?.cancel();
super.dispose();
}
Timer? timer;
int maxDelaySec = 10;
int idleScreenCounter = 0;
@override
void initState() {
super.initState();
initTimer();
}
initTimer() {
timer = Timer.periodic(Duration(seconds: 1), (timer) {
idleScreenCounter ;
setState(() {}); //
});
}
onScreenTap() {
print("tapped on Screen");
idleScreenCounter = 0;
setState(() {});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanDown: (_) => onScreenTap(),
child: Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => SizedBox(
width: constraints.maxWidth,
height: constraints.maxHeight,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (maxDelaySec - idleScreenCounter > 0)
SizedBox(
height: 200,
child: Text(
" Tap the screen within ${maxDelaySec - idleScreenCounter}"),
),
if (maxDelaySec - idleScreenCounter < 0)
Container(
height: 100,
width: 100,
color: Colors.cyanAccent,
child: Text("Tap on screen"),
),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
print("An action");
},
child: Text("A Button"),
),
ElevatedButton(
onPressed: () {
print("act");
},
child: Text("Elev"),
)
],
),
),
),
),
),
);
}
}