จะปิดใช้งานหรือแทนที่ปุ่ม "ย้อนกลับ" ของ Android ใน Flutter ได้อย่างไร


128

มีวิธีปิดใช้งานปุ่มย้อนกลับของ 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(),
      },
    );
  }
}

ในหน้าหนึ่งฉันมีปุ่มเพื่อไปที่ pageTwo:

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

ปัญหาของฉันคือถ้าฉันกดลูกศรย้อนกลับที่ด้านล่างของหน้าจอ Android ฉันจะกลับไปที่ pageOne ฉันต้องการให้ปุ่มนี้ไม่ปรากฏขึ้นเลย ตามหลักการแล้วฉันไม่ต้องการให้ออกจากหน้าจอนี้เว้นแต่ผู้ใช้จะกดนิ้วค้างไว้บนหน้าจอเป็นเวลา 5 วินาที (ฉันกำลังพยายามเขียนแอพสำหรับเด็กเล็กและต้องการให้เฉพาะผู้ปกครองเท่านั้นที่สามารถออกจากหน้าจอนั้นได้)

คำตอบ:


225

คำตอบคือ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(),
        ),
      ),
    ),
  );
}

2
สำหรับผู้ที่ต้องการสกัดกั้นป๊อปของฟอร์มจะสะดวกกว่าในการใช้onWillPopคุณสมบัติของแบบฟอร์ม มีการเข้าถึงสถานะแบบฟอร์มและขั้นแรกสามารถตรวจสอบเพื่อดูว่ามีสถานะใดที่ผู้ใช้อาจไม่ต้องการสูญเสีย
Joe Lapp

สวัสดี @ RémiRousseletคุณช่วยฉันจัดการกองหลังได้ไหมเช่นฉันมีหน้าจอ A, B, C, D และฉันต้องการนำทางจาก D-> B หรือ D-> A แล้วฉันจะจัดการอย่างไร มัน. คุณช่วยแนะนำฉันได้ไหม
Ravindra Kushwaha

1
ฉันรู้ว่าคำตอบนี้อาจจะเก่า แต่เป็น GEM! ลองคิดขยายคำอธิบาย มันทำงานได้ยอดเยี่ยม ขอขอบคุณ.
วัล

2
สำหรับคนที่อยากทำอะไรก่อนป๊อป () สามารถใช้สิ่งนี้onWillPop: () async { onBack(); // "DO YOUR FUNCTION IS HERE WHEN POP" return false; }
Huy Tower

25

ตามที่Rémi Rousselet ชี้ให้เห็นWillPopScopeมักจะเป็นหนทางที่จะไป อย่างไรก็ตามหากคุณกำลังพัฒนาวิดเจ็ตที่มีสถานะซึ่งควรตอบสนองต่อปุ่มย้อนกลับโดยตรงคุณสามารถใช้สิ่งนี้:

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

หมายเหตุ: ฉันเป็นผู้เขียนแพ็คเกจนี้


ด้วยความเคารพอย่างเต็มที่คุณไม่คิดว่าสิ่งนี้เหมาะกว่าเป็นความคิดเห็นหรือไม่?
CopsOnRoad

28
@CopsOnRoad ไม่เนื่องจากไม่ใช่ความคิดเห็นสำหรับคำตอบอื่น แต่เป็นวิธีที่แตกต่างกันโดยสิ้นเชิงในการแก้ปัญหาเดียวกัน
MarcG

1
เป็นทางเลือกที่ดีและอาจถูกเพิกเฉยหากเป็นส่วนหนึ่งของความคิดเห็น
abhijat_saxena

20

แม้ว่าคำตอบของ 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

5

ฉันโพสต์สิ่งนี้ไว้ที่นี่เผื่อมีใครพบสิ่งนี้และหวังว่าพวกเขาจะพบตัวอย่างง่ายๆ 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 ไม่มีปุ่มย้อนกลับ แม้ว่าคุณจะบอกฉันได้ว่ามีอะไรผิดพลาดเพื่อที่ฉันจะได้ซ่อมมันหรือบางทีมันใช้งานได้กับโปรแกรมจำลองเฉพาะของฉันเท่านั้น ฉันไม่ได้อัปเดตการกระพือปีกภายในสองสามสัปดาห์นั่นอาจเป็นปัญหาได้ แจ้งให้เราทราบ
ไบรอันยกเลิก

@BryanCancel คำตอบของคุณใช้ได้ก็ต่อเมื่อคุณยังไม่มีเส้นทางผลักดัน ดูวิธีการ WidgetsBinding.handlePopRoute () จะแจ้งผู้สังเกตการณ์ตามลำดับการลงทะเบียนและหยุดทันทีที่ได้รับจริง เมื่อมีเส้นทางที่พุชเนวิเกเตอร์จะส่งกลับค่าจริงก่อนจากนั้นผู้สังเกตการณ์ของคุณจะไม่ถูกเรียกจริงๆ กล่าวอีกนัยหนึ่งรหัสของคุณจะใช้งานได้เพื่อป้องกันไม่ให้แอปพลิเคชันปิดตัวลงเมื่อผู้ใช้คลิกปุ่มย้อนกลับเมื่อไม่มีเส้นทางเหลือ
MarcG

4

คุณสามารถใช้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
    },
  );
}

FYI นี่เทียบเท่ากับonWillPop: () async => _allow.
Lynn

@ Lynn ใช่ฉันรู้ว่า ฉันแค่อยากจะแบ่งปันการFuture.value()โทร
CopsOnRoad

@CopsOnRoad return SafeArea () กำหนดไว้แล้วว่าจะจัดการกับการกดกลับในการกระพือปีกได้อย่างไร
sj

@CopsOnRoad สวัสดีในรหัสคลาสของฉัน Widget build (บริบท BuildContext) {return SafeArea (child: Stack (children: <idget>> [..... ดังนั้นที่นี่ส่งคืน WillPopScope (); ไม่สามารถกำหนดคำสั่ง return สองคำสั่งแล้วจะเริ่มต้น backpressed ได้อย่างไร in flutter
sj

1
@sj ห่อSafeAreaวิดเจ็ตของคุณเป็นWillPopScope.
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


0

เพียงเพิ่มคอนเทนเนอร์ที่ด้านบนของ Appbar ซึ่งซ่อนปุ่มย้อนกลับ

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

ผู้ใช้กำลังถามเกี่ยวกับปุ่มย้อนกลับของ Android ไม่ใช่เกี่ยวกับปุ่มย้อนกลับบนแถบแอป
Himmet Yelekin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.