Flutter에서 Android '뒤로'버튼을 비활성화하거나 재정의하는 방법은 무엇입니까?


111

특정 페이지에서 Android 뒤로 버튼을 비활성화하는 방법이 있습니까?

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

pageOne에는 pageTwo로 이동하는 버튼이 있습니다.

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

내 문제는 안드로이드 화면 하단의 뒤로 화살표를 누르면 pageOne으로 돌아 간다는 것입니다. 이 버튼이 전혀 표시되지 않게하고 싶습니다. 이상적으로는 사용자가 화면에서 손가락을 5 초 동안 누르고 있지 않는 한이 화면에서 나갈 수있는 방법이 없습니다. (저는 유아용 앱을 작성하려고하는데 부모 만 특정 화면에서 이동할 수 있기를 바랍니다.)

답변:


199

대답은 WillPopScope입니다. 시스템에서 페이지가 팝업되는 것을 방지합니다. 계속 사용할 수 있습니다.Navigator.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
Form의 팝을 가로 채고 자하는 사람들에게는 Form의 onWillPop속성 을 사용하는 것이 더 편리 합니다. 양식 상태에 액세스 할 수 있으며 사용자가 잃고 싶지 않은 상태가 있는지 먼저 확인할 수 있습니다.
Joe Lapp의

안녕하세요 @ RémiRousselet, A, B, C, D 화면 스택이 있고 D-> B 또는 D-> A에서 탐색하고 싶은 것처럼 백 스택 관리를 도와 주시겠습니까? 그것. 저를 안내해 주 시겠어요
Ravindra Kushwaha

이 대답은 아마도 오래되었을 것입니다. 그러나 GEM입니다! 설명 확장을 고려하십시오. 그것은 훌륭하게 작동합니다. 감사합니다.
Val

1
누군가 pop () 전에 무언가를하고 싶다면 이것을 사용할 수 있습니다onWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tower

24

Rémi Rousselet이 지적했듯이 WillPopScope일반적으로 갈 길입니다. 그러나 뒤로 버튼에 직접 반응해야하는 상태 저장 위젯을 개발하는 경우 다음을 사용할 수 있습니다.

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

참고 :이 패키지의 작성자입니다.


정중히 여기가 댓글로 더 적합하다고 생각하지 않습니까?
CopsOnRoad

25
@CopsOnRoad 아니요, 다른 답변에 대한 의견이 아니라 동일한 문제를 해결하는 완전히 다른 방법이기 때문입니다.
MarcG

좋은 대안이며 댓글의 일부인 경우 무시할 수 있습니다.
abhijat_saxena

16

Remi의 대답은 옳지 만 일반적으로 단순히 뒤로 버튼을 차단하는 것이 아니라 사용자가 종료를 확인하기를 원합니다.

onWillPop미래 이기 때문에 확인 대화 상자에서 답변을 받아 비슷한 방식으로 할 수 있습니다 .

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

이 답변이 반대표를받는 이유는 무엇입니까? 누구든지 이것을 구현하고 나쁜 경험이 있습니까?
SamiAzar

기기에서 뒤로 가기 버튼을 누른 후 첫 화면으로 이동하는 대신 이전 화면으로 이동하고 싶습니다. 이와 같은 대화 상자가 필요하지 않습니다. 어떻게해야합니까
LakshmiYogeshwaran

4

나는 누군가가 이것을 발견하고 그들이 간단한 예를 찾길 바라는 경우에 이것을 여기에 게시하고 있습니다 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"),
              )
          )
      ),
    );
  }
}

어제 직접 사용했습니다. Android 전용이며 Apple에는 뒤로 버튼이 없습니다. 내가 그것을 고칠 수 있도록 무엇이 잘못되었는지 말해 줄 수 있거나 아마도 내 특정 에뮬레이터에서만 작동합니다. 나는 몇 주 동안 내 플러터를 업데이트하지 않았으므로 아마도 그것이 문제 일 것입니다. 알려주세요
Bryan Cancel

@BryanCancel 귀하의 답변은 아직 푸시 된 경로가없는 경우에만 작동합니다. WidgetsBinding.handlePopRoute () 메서드를 참조하세요. 옵저버에게 등록순으로 알리고 참을 받으면 바로 멈 춥니 다. 푸시 된 경로가 있으면 탐색기가 먼저 true를 반환 한 다음 관찰자가 실제로 호출되지 않습니다. 즉, 코드는 더 이상 남은 경로가 없을 때 사용자가 뒤로 버튼을 클릭 할 때 애플리케이션이 종료되는 것을 방지하기 위해서만 작동합니다.
MarcG

3

Future.value(bool)뒤로 버튼을 처리하는 데 사용할 수 있습니다 .

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

참고로 이것은 onWillPop: () async => _allow.
Lynn

@Lynn 네, 알아요. Future.value()통화 를 공유하고 싶었습니다 .
CopsOnRoad

3

나는 mixin을 사용했고 WillPopScope 위젯은 나를 위해 일을 할 수 없었습니다. 이것은 내가 찾은 최선의 접근 방식이며 내 의견으로는 WillPopScope보다 훨씬 낫습니다.
final bool canPop = ModalRoute.of(context)?.canPop ?? false;
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(),

2

대답은 WillPopScope를 사용하고 있다는 것을 알았을 수도 있지만 불행히도 IOS 에서는 스 와이프 하여 이전 페이지 로 돌아갈 수 없으므로 MaterialPageRoute를 사용자 지정해 보겠습니다.

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

이제 WillPopScope을 사용할 수 있으며 위로 스 와이프하여 IOS에서 작동합니다. 자세한 답변은 다음과 같습니다 : https://github.com/flutter/flutter/issues/14203#issuecomment-540663717


1

뒤로 버튼을 숨기는 Appbar의 선두에 컨테이너를 추가하기 만하면됩니다.

AppBar(
        title: new Text('Page Title'),
        leading: new Container(),
      ),
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.