Bagaimana cara menonaktifkan atau menimpa tombol "KEMBALI" Android, di Flutter?

112

Adakah cara untuk menonaktifkan tombol kembali Android saat berada di halaman tertentu?

class WakeUpApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "Time To Wake Up ?",
      home: new WakeUpHome(),
      routes: <String, WidgetBuilder>{
        '/pageOne': (BuildContext context) => new pageOne(),
        '/pageTwo': (BuildContext context) => new pageTwo(),
      },
    );
  }
}

Di halamanSatu saya memiliki tombol untuk pergi ke halamanDua:

new FloatingActionButton(
  onPressed: () {    
    Navigator.of(context).pushNamed('/pageTwo');
  },
)

Masalah saya adalah jika saya menekan panah Kembali di bagian bawah layar android, saya kembali ke pageOne. Saya ingin tombol ini tidak muncul sama sekali. Idealnya, saya tidak ingin ada jalan keluar yang mungkin dari layar ini kecuali pengguna terus menekan jarinya di layar selama 5 detik. (Saya mencoba menulis Aplikasi untuk balita, dan hanya ingin orang tua yang dapat menavigasi keluar dari layar tertentu).

Jackpap
sumber

Jawaban:

202

Jawabannya adalah WillPopScope. Ini akan mencegah halaman dimunculkan oleh sistem. Anda masih bisa menggunakanNavigator.of(context).pop()

@override
Widget build(BuildContext context) {
  return new WillPopScope(
    onWillPop: () async => false,
    child: new Scaffold(
      appBar: new AppBar(
        title: new Text("data"),
        leading: new IconButton(
          icon: new Icon(Icons.ac_unit),
          onPressed: () => Navigator.of(context).pop(),
        ),
      ),
    ),
  );
}
Rémi Rousselet
sumber
1
Bagi mereka yang ingin menghalangi sembulan Formulir, lebih mudah menggunakan onWillPopproperti Formulir . Ini memiliki akses ke status formulir dan pertama-tama dapat memeriksa untuk melihat apakah ada status yang mungkin tidak ingin hilang dari pengguna.
Joe Lapp
Hai @ RémiRousselet, Bisakah Anda membantu saya dalam mengelola tumpukan belakang seperti saya memiliki tumpukan layar A, B, C, D dan saya ingin menavigasi dari D-> B ATAU D-> A, lalu bagaimana saya akan mengelola Itu. Bisakah Anda membimbing saya tentang itu
Ravindra Kushwaha
Saya tahu jawaban ini mungkin sudah tua. Tapi adalah GEM! Pikirkan tentang memperluas penjelasan. Ini bekerja dengan sangat baik. Terima kasih.
Val
1
Untuk seseorang yang ingin melakukan sesuatu sebelum pop (), dapat menggunakan inionWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Menara Huy
24

Seperti yang ditunjukkan Rémi Rousselet, WillPopScopebiasanya cara yang harus ditempuh. Namun, jika Anda mengembangkan widget stateful yang harus bereaksi langsung ke tombol kembali, Anda dapat menggunakan ini:

https://pub.dartlang.org/packages/back_button_interceptor

Catatan: Saya adalah pembuat paket ini.

MarcG
sumber
Dengan penuh hormat, bukankah menurut Anda ini lebih cocok sebagai komentar?
CopsOnRoad
25
@CopsOnRoad Tidak, karena ini bukan komentar untuk jawaban lain, melainkan cara yang sama sekali berbeda untuk menyelesaikan masalah yang sama.
MarcG
Ini alternatif yang bagus dan bisa diabaikan jika itu adalah bagian dari komentar.
abhijat_saxena
17

Meskipun jawaban Remi benar, biasanya Anda tidak ingin memblokir tombol kembali tetapi ingin pengguna mengonfirmasi jalan keluar.

Anda dapat melakukannya dengan cara yang sama dengan mendapatkan jawaban dari dialog konfirmasi, karena onWillPopini adalah masa depan.

@override
Widget build(BuildContext context) {
  return WillPopScope(
    child: Scaffold(...),
    onWillPop: () => showDialog<bool>(
      context: context,
      builder: (c) => AlertDialog(
        title: Text('Warning'),
        content: Text('Do you really want to exit'),
        actions: [
          FlatButton(
            child: Text('Yes'),
            onPressed: () => Navigator.pop(c, true),
          ),
          FlatButton(
            child: Text('No'),
            onPressed: () => Navigator.pop(c, false),
          ),
        ],
      ),
    ),
  );
}
Airon Tark
sumber
Mengapa jawaban ini mendapat suara negatif? Apakah ada yang menerapkan ini dan memiliki pengalaman buruk?
SamiAzar
Saya ingin pergi ke layar sebelumnya daripada pergi ke layar pertama setelah menekan tombol kembali dari perangkat. Saya tidak membutuhkan kotak dialog seperti ini. Apa yang harus saya lakukan
LakshmiYogeshwaran
4

Saya memposting ini di sini jika ada orang di luar sana yang menemukan ini dan berharap mereka akan menemukan contoh sederhana https://gist.github.com/b-cancel/0ca372017a25f0c120b14dfca3591aa5

import 'package:flutter/material.dart';

import 'dart:async';

void main() => runApp(new BackButtonOverrideDemoWidget());

class BackButtonOverrideDemoWidget extends StatefulWidget{
  @override
  _BackButtonOverrideDemoWidgetState createState() => new _BackButtonOverrideDemoWidgetState();
}

class _BackButtonOverrideDemoWidgetState extends State<BackButtonOverrideDemoWidget> with WidgetsBindingObserver{

  //-------------------------Test Variable

  bool isBackButtonActivated = false;

  //-------------------------Required For WidgetsBindingObserver

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  //-------------------------Function That Triggers when you hit the back key

  @override
  didPopRoute(){
    bool override;
    if(isBackButtonActivated)
      override = false;
    else
      override = true;
    return new Future<bool>.value(override);
  }

  //-------------------------Build Method

  @override
  Widget build(BuildContext context) {
    return new Directionality(
      textDirection: TextDirection.ltr,
      child: new Container(
          color: (isBackButtonActivated) ? Colors.green : Colors.red,
          child: new Center(
              child: new FlatButton(
                color: Colors.white,
                onPressed: () {
                  isBackButtonActivated = !isBackButtonActivated;
                  setState(() {});
                },
                child: (isBackButtonActivated) ?
                new Text("DeActive the Back Button") : new Text("Activate the Back Button"),
              )
          )
      ),
    );
  }
}
Bryan Batal
sumber
Saya benar-benar menggunakannya sendiri kemarin. Perlu diingat bahwa ini hanya untuk Android, Apple tidak memiliki tombol kembali. Meskipun bisakah Anda memberi tahu saya apa yang salah sehingga saya dapat memperbaikinya, atau mungkin itu hanya berfungsi pada emulator khusus saya. Saya belum memperbarui flutter saya dalam beberapa minggu, jadi mungkin itulah masalahnya. Beri tahu saya
Bryan Batal
@BryanCancel Jawaban Anda hanya berfungsi jika Anda belum memiliki rute yang didorong. Lihat metode WidgetsBinding.handlePopRoute (). Ini memberi tahu pengamat dalam urutan pendaftaran, dan berhenti segera setelah menerima true. Ketika ada rute yang didorong, navigator mengembalikan nilai true terlebih dahulu, dan kemudian pengamat Anda tidak pernah benar-benar dipanggil. Dengan kata lain, kode Anda hanya berfungsi untuk mencegah aplikasi agar tidak mati saat pengguna mengklik tombol kembali, saat tidak ada rute lagi yang tersisa.
MarcG
3

Anda dapat menggunakan Future.value(bool)untuk menangani tombol kembali.

bool _allow = true;

@override
Widget build(BuildContext context) {
  return WillPopScope(
    child: Scaffold(appBar: AppBar(title: Text("Back"))),
    onWillPop: () {
      return Future.value(_allow); // if true allow back else block it
    },
  );
}
CopsOnRoad
sumber
FYI, ini setara dengan onWillPop: () async => _allow.
Lynn
@Lynn ya saya tahu itu. Saya hanya ingin berbagi Future.value()panggilan.
CopsOnRoad
3

Saya menggunakan widget mixin dan WillPopScope hanya tidak bisa menyelesaikan pekerjaan untuk saya. Ini adalah pendekatan terbaik yang saya temukan, jauh lebih baik daripada WillPopScope menurut saya.
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
Digunakan seperti ini di dalam appbar:

leading: ModalRoute.of(context)?.canPop ?? false
    ? IconButton(
        onPressed: () {
          Navigator.pop(context);
        },
        icon: (Platform.isAndroid)
            ? const Icon(Icons.arrow_back)
            : const Icon(Icons.arrow_back_ios),
      )
    : Container(),
Djordje Komazec
sumber
2

Jawabannya mungkin Anda tahu itu menggunakan WillPopScope , tetapi sayangnya di iOS Anda tidak dapat menggeser ke belakang halaman sebelumnya, jadi mari sesuaikan MaterialPageRoute Anda:

class CustomMaterialPageRoute<T> extends MaterialPageRoute<T> {
  @protected
  bool get hasScopedWillPopCallback {
    return false;
  }
  CustomMaterialPageRoute({
    @required WidgetBuilder builder,
    RouteSettings settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
  }) : super( 
          builder: builder,
          settings: settings,
          maintainState: maintainState,
          fullscreenDialog: fullscreenDialog,
        );
}

Sekarang Anda dapat menggunakan WillPopScope dan geser ke belakang akan berfungsi di iOS. Jawaban detailnya ada di sini: https://github.com/flutter/flutter/issues/14203#issuecomment-540663717

Nhật Trần
sumber
1

Cukup tambahkan wadah di depan Appbar yang menyembunyikan tombol kembali.

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
Niroop Nife
sumber