Làm cách nào để hủy kích hoạt hoặc ghi đè nút “QUAY LẠI” của Android trong Flutter?


102

Có cách nào để tắt nút quay lại của Android khi ở trên một trang cụ thể không?

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(),
      },
    );
  }
}

Trên trang Một tôi có một nút để chuyển đến trang Hai:

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

Vấn đề của tôi là nếu tôi nhấn vào mũi tên Quay lại ở cuối màn hình Android, tôi sẽ quay lại pageOne. Tôi muốn nút này không hiển thị chút nào. Tốt nhất, tôi không muốn thoát khỏi màn hình này trừ khi người dùng giữ ngón tay của mình trên màn hình trong 5 giây. (Tôi đang cố gắng viết một Ứng dụng cho trẻ mới biết đi và chỉ muốn các bậc cha mẹ có thể điều hướng ra khỏi màn hình cụ thể).

Câu trả lời:


188

Câu trả lời là WillPopScope. Nó sẽ ngăn trang bị hệ thống bật lên. Bạn vẫn có thể sử dụngNavigator.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(),
        ),
      ),
    ),
  );
}

1
Đối với những người muốn chặn cửa sổ bật lên của Biểu mẫu, sẽ thuận tiện hơn khi sử dụng thuộc tính của Biểu mẫu onWillPop. Nó có quyền truy cập vào trạng thái biểu mẫu và trước tiên có thể kiểm tra xem có trạng thái nào mà người dùng có thể không muốn mất hay không.
Joe Lapp

Chào @ RémiRousselet, Bạn vui lòng giúp mình quản lý ngăn xếp phía sau giống như mình có một ngăn xếp màn hình A, B, C, D và mình muốn điều hướng từ D-> B HOẶC D-> A thì mình sẽ quản lý như thế nào nó. Bạn có thể vui lòng hướng dẫn tôi về nó không
Ravindra Kushwaha

Tôi biết câu trả lời này có thể cũ. Nhưng là một GEM! Suy nghĩ về việc mở rộng lời giải thích. Nó hoạt động tuyệt vời. Cảm ơn bạn.
Val

1
Đối với một người nào đó muốn làm điều gì đó trước khi pop (), có thể sử dụngonWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tháp

21

Như Rémi Rousselet đã chỉ ra, WillPopScopethường là con đường để đi. Tuy nhiên, nếu bạn đang phát triển một tiện ích trạng thái sẽ phản ứng trực tiếp với nút quay lại, bạn có thể sử dụng điều này:

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


Với sự tôn trọng đầy đủ, bạn không nghĩ điều này phù hợp hơn như một nhận xét sao?
CopsOnRoad

21
@CopsOnRoad Không, vì đây không phải là một nhận xét cho một câu trả lời khác, mà là một cách hoàn toàn khác để giải quyết cùng một vấn đề.
MarcG

Đó là một sự thay thế tốt và nó có thể bị bỏ qua nếu nó là một phần của một bình luận.
abhijat_saxena

16

Mặc dù câu trả lời của Remi là đúng, nhưng thông thường bạn không muốn chỉ chặn nút quay lại mà muốn người dùng xác nhận việc thoát.

Bạn có thể làm điều đó theo cách tương tự bằng cách nhận câu trả lời từ hộp thoại xác nhận, vì đó onWillPoplà tương lai.

@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),
          ),
        ],
      ),
    ),
  );
}

Tại sao câu trả lời này nhận được một phản đối? Có ai thực hiện điều này và có kinh nghiệm xấu?
SamiAzar

Tôi muốn chuyển đến màn hình trước đó thay vì chuyển đến màn hình đầu tiên sau khi nhấn nút quay lại từ thiết bị. Tôi không cần một hộp thoại như thế này. Tôi nên làm gì
LakshmiYogeshwaran

4

Tôi đăng bài này ở đây để phòng trường hợp có ai đó tìm thấy điều này và muốn họ tìm thấy một ví dụ đơn giản 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"),
              )
          )
      ),
    );
  }
}

Tôi thực sự đã sử dụng nó ngày hôm qua. Hãy nhớ rằng nó chỉ dành cho Android, Apple không có nút quay lại. Mặc dù bạn có thể cho tôi biết điều gì xảy ra để tôi có thể sửa chữa nó, hoặc có lẽ nó chỉ hoạt động trên trình giả lập cụ thể của tôi. Tôi đã không cập nhật sự rung động của mình trong một vài tuần nên có lẽ đó là vấn đề. Hãy cho tôi biết
Bryan Hủy

@BryanCancel Câu trả lời của bạn chỉ hoạt động nếu bạn chưa có bất kỳ lộ trình được đẩy nào. Xem phương thức WidgetsBinding.handlePopRoute (). Nó thông báo cho những người quan sát theo thứ tự đăng ký, và dừng ngay khi nhận được true. Khi có các tuyến đường được đẩy, trình điều hướng sẽ trả về true trước tiên và sau đó trình quan sát của bạn thực sự không bao giờ được gọi. Nói cách khác, mã của bạn chỉ hoạt động để ngăn ứng dụng tắt khi người dùng nhấp vào nút quay lại, khi không còn tuyến nào nữa.
MarcG

3

Bạn có thể sử dụng Future.value(bool)để xử lý nút quay lại.

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
    },
  );
}

FYI, điều này tương đương với onWillPop: () async => _allow.
Lynn

@Lynn vâng, tôi biết điều đó. Tôi chỉ muốn chia sẻ Future.value()cuộc gọi.
CopsOnRoad

3

Tôi đã sử dụng mixin và tiện ích WillPopScope nhưng không thể hoàn thành công việc cho tôi. Đây là cách tiếp cận tốt nhất mà tôi tìm thấy, tốt hơn nhiều so với WillPopScope theo quan điểm của tôi.
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
Đã sử dụng nó như thế này bên trong thanh ứng dụng:

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(),

2

Câu trả lời có thể bạn đã biết đó là sử dụng WillPopScope , nhưng rất tiếc trên IOS, bạn không thể vuốt để quay lại trang trước, vì vậy hãy tùy chỉnh MaterialPageRoute của bạn:

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,
        );
}

Bây giờ bạn có thể sử dụng WillPopScope và vuốt để quay lại sẽ hoạt động trên IOS. Câu trả lời chi tiết có ở đây: https://github.com/flutter/flutter/issues/14203#issuecomment-540663717


1

Chỉ cần thêm một vùng chứa ở đầu Thanh ứng dụng, nơi ẩn nút quay lại.

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.