পপিংয়ের সময় ফ্লটার ন্যাভিগেটরকে অবস্থা পুনরায় লোড করতে বাধ্য করুন


96

আমার StatefulWidgetসাথে একটি বোতামে বোতাম রয়েছে, যা আমাকে StatefulWidgetব্যবহার করে অন্যটিতে নেভিগেট করে Navigator.push()। দ্বিতীয় উইজেটে আমি বিশ্বব্যাপী রাষ্ট্র পরিবর্তন করছি (কিছু ব্যবহারকারীর পছন্দ)। আমি যখন দ্বিতীয় উইজেট থেকে প্রথমটিতে ফিরে যাই, Navigator.pop()প্রথম উইজেটটি ব্যবহার করা পুরানো অবস্থায় রয়েছে, তবে আমি এটি পুনরায় লোড করতে বাধ্য করতে চাই। কোন ধারণা কিভাবে এই কাজ করতে? আমার একটি ধারণা আছে তবে এটি দেখতে কুৎসিত:

  1. দ্বিতীয় উইজেট অপসারণ করতে পপ (বর্তমান একটি)
  2. প্রথম উইজেট অপসারণ করতে আবার পপ করুন (পূর্ববর্তীটি)
  3. প্রথম উইজেট টিপুন (এটি পুনরায় আঁকতে বাধ্য করা উচিত)

4
কোনও উত্তর নেই, কেবল একটি সাধারণ মন্তব্য: আমার ক্ষেত্রে, কী কী আমাকে এখানে এনেছে তা কেবলমাত্র ভাগ করা_পরিচয়গুলির জন্য একটি সিঙ্ক পদ্ধতিতে সমাধান করা হবে যেখানে আমি একটি আপডেট প্রেফ ফিরে পাওয়ার নিশ্চয়তা পেয়েছি যা আমি কিছুক্ষণ আগে অন্য পৃষ্ঠায় লিখেছিলাম । : \ এমনকি ব্যবহার করা। তারপর (...) সর্বদা আমাকে মুলতুবি-লেখার আপডেটের ডেটা পাবে না।
ক্রিসএইচ

পপে নতুন পৃষ্ঠা থেকে সবেমাত্র একটি মান ফিরিয়ে দিয়েছে, আমার সমস্যাটি সমাধান করেছে। পড়ুন flutter.dev/docs/cookbook/navigation/returning-data
জো এম

: এই দেখুন করা আবশ্যক stackoverflow.com/a/64006691/10563627
পরেশ Mangukiya

উত্তর:


77

আপনি এখানে করতে পারেন বেশ কয়েকটি জিনিস আছে। @ মাহির উত্তর সঠিক হওয়ার পরে কিছুটা বেশি সংহত হতে পারে এবং ওপি যেমন জিজ্ঞাসা করছে ঠিক তেমন ডায়ালগের পরিবর্তে পুশ ব্যবহার করতে পারে। এটি ব্যবহার করে এমন একটি উদাহরণ Navigator.push:

import 'package:flutter/material.dart';

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      color: Colors.green,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
            onPressed: () => Navigator.pop(context),
            child: new Text("back"),
          ),
        ],
      ),
    );
  }
}

class FirstPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new FirstPageState();
}

class FirstPageState extends State<FirstPage> {

  Color color = Colors.white;

  @override
  Widget build(BuildContext context) {
    return new Container(
      color: color,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
              child: new Text("next"),
              onPressed: () {
                Navigator
                    .push(
                  context,
                  new MaterialPageRoute(builder: (context) => new SecondPage()),
                )
                    .then((value) {
                  setState(() {
                    color = color == Colors.white ? Colors.grey : Colors.white;
                  });
                });
              }),
        ],
      ),
    );
  }
}

void main() => runApp(
      new MaterialApp(
        builder: (context, child) => new SafeArea(child: child),
        home: new FirstPage(),
      ),
    );

তবে এটি করার আরও একটি উপায় রয়েছে যা আপনার ব্যবহারের ক্ষেত্রে ভালভাবে ফিট করতে পারে। যদি আপনি globalএমন কিছু হিসাবে ব্যবহার করছেন যা আপনার প্রথম পৃষ্ঠার নির্মাণকে প্রভাবিত করে, আপনি আপনার বিশ্বব্যাপী ব্যবহারকারীর পছন্দগুলি সংজ্ঞায়িত করতে একটি ইনহরাইটড উইজেট ব্যবহার করতে পারেন এবং প্রতিবার সেগুলি পরিবর্তন করা হলে আপনার ফার্স্টপেজটি পুনর্নির্মাণ করবে। এটি নীচে দেখানো হিসাবে একটি স্টেটহীন উইজেটের মধ্যেও কাজ করে (তবে পাশাপাশি রাষ্ট্রীয় উইজেটেও কাজ করা উচিত)।

এলোমেলোভাবে উইজেটের উদাহরণ হ'ল অ্যাপটির থিম, যদিও তারা এটিকে এখানে যেমন আছে ঠিক তেমনিভাবে তৈরি করার পরিবর্তে একটি উইজেটের মধ্যেই এটি সংজ্ঞায়িত করে।

import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      color: Colors.green,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
            onPressed: () {
              ColorDefinition.of(context).toggleColor();
              Navigator.pop(context);
            },
            child: new Text("back"),
          ),
        ],
      ),
    );
  }
}

class ColorDefinition extends InheritedWidget {
  ColorDefinition({
    Key key,
    @required Widget child,
  }): super(key: key, child: child);

  Color color = Colors.white;

  static ColorDefinition of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(ColorDefinition);
  }

  void toggleColor() {
    color = color == Colors.white ? Colors.grey : Colors.white;
    print("color set to $color");
  }

  @override
  bool updateShouldNotify(ColorDefinition oldWidget) =>
      color != oldWidget.color;
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var color = ColorDefinition.of(context).color;

    return new Container(
      color: color,
      child: new Column(
        children: <Widget>[
          new RaisedButton(
              child: new Text("next"),
              onPressed: () {
                Navigator.push(
                  context,
                  new MaterialPageRoute(builder: (context) => new SecondPage()),
                );
              }),
        ],
      ),
    );
  }
}

void main() => runApp(
      new MaterialApp(
        builder: (context, child) => new SafeArea(
              child: new ColorDefinition(child: child),
            ),
        home: new FirstPage(),
      ),
    );

যদি আপনি উত্তরাধিকারসূত্রে প্রাপ্ত উইজেট ব্যবহার করেন তবে আপনাকে যে পৃষ্ঠার ধাক্কা দেওয়া হয়েছে তার পপটি দেখার জন্য আপনার চিন্তা করতে হবে না, যা বেসিক ব্যবহারের ক্ষেত্রে কাজ করবে তবে আরও জটিল পরিস্থিতিতে সমস্যা হতে পারে।


দুর্দান্ত, প্রথম কেসটি আমার জন্য নিখুঁতভাবে কাজ করেছে (দ্বিতীয়টি আরও জটিল পরিস্থিতির জন্য নিখুঁত)। দ্বিতীয় পৃষ্ঠা থেকে অনউইলপপআপ ব্যবহার করা আমার কাছে পরিষ্কার ছিল না; এমনকি কিছুতেই কাজও করেনি।
সিডিএসেনজ

আরে, আমি যদি আমার তালিকা আইটেম আপডেট করতে চান। ধরা যাক আমার প্রথম পৃষ্ঠায় তালিকার আইটেম রয়েছে এবং দ্বিতীয় পৃষ্ঠায় আইটেমের বিশদ রয়েছে। আমি আইটেমটির মান আপডেট করছি এবং তালিকা আইটেমগুলিতে এটি আবার আপডেট হওয়া চাই। কীভাবে অর্জন করব?
অণাল মেহতা

@ অ্যানালমেহটা আমি আপনাকে একটি দ্রুত প্রস্তাব দিতে পারি - হয় উভয় পৃষ্ঠাগুলি থেকে ব্যবহৃত ব্যাকএন্ড স্টোর (যেমন স্কফ্লাইট টেবিল বা ইন-মেমরি তালিকার) আছে এবং .তখন আপনি আপনার উইজেটকে কিছুটা রিফ্রেশ করতে বাধ্য করতে পারেন (আমি ব্যক্তিগতভাবে আমি আগে সেটস্টেটে পরিবর্তিত একটি বাড়ানো কাউন্টার ব্যবহার করেছি - এটি সবচেয়ে পরিষ্কার সমাধান নয় তবে এটি কাজ করে) ... অথবা, আপনি পরিবর্তনগুলি মূল পৃষ্ঠায় ফিরে যেতে পারতেন। ততক্ষণে, আপনার তালিকায় পরিবর্তন আনুন এবং তারপরে পুনর্নির্মাণ করুন (তবে নোট করুন যে তালিকায় পরিবর্তন করা একটি রিফ্রেশকে ট্রিগার করে না, তাই আবার একবার ইনক্রিমেন্টিং কাউন্টার ব্যবহার করুন)।
rmtmckenzie

@ অ্যানালমেহতা তবে এটি যদি সহায়তা না করে তবে আমি আপনাকে আরও প্রাসঙ্গিক কিছু উত্তর সন্ধানের পরামর্শ দিচ্ছি (আমি নিশ্চিত যে আমি তালিকা ইত্যাদির বিষয়ে কয়েকটি দেখেছি), অথবা একটি নতুন প্রশ্ন জিজ্ঞাসা করব।
rmtmckenzie

@rmtmckenzie আসলে আমি উপরের একটি সমাধান চেষ্টা করেছি। আমি চ্যান gesগুলিতে প্রয়োগ করেছি। তবে এটি প্রতিফলিত হবে না। আমার ধারণা এখন আমার কাছে সরবরাহকারীদের ব্যবহারের একমাত্র বিকল্প রয়েছে have যাইহোক, আপনার সহায়তার জন্য আপনাকে অনেক ধন্যবাদ।
Aanal মেহতা

18

2 টি জিনিস রয়েছে, যা থেকে ডেটা পাস করছে

  • 1 ম পৃষ্ঠা থেকে দ্বিতীয়

    1 ম পৃষ্ঠায় এটি ব্যবহার করুন

    // sending "Foo" from 1st
    Navigator.push(context, MaterialPageRoute(builder: (_) => Page2("Foo")));
    

    এটি ২ য় পৃষ্ঠায় ব্যবহার করুন।

    class Page2 extends StatelessWidget {
      final String string;
    
      Page2(this.string); // receiving "Foo" in 2nd
    
      ...
    }
    

  • ২ য় পৃষ্ঠা থেকে 1st ম পর্যন্ত

    এটি ২ য় পৃষ্ঠায় ব্যবহার করুন

    // sending "Bar" from 2nd
    Navigator.pop(context, "Bar");
    

    এটি 1 ম পৃষ্ঠায় ব্যবহার করুন, এটি একই যা আগে ব্যবহৃত হয়েছিল তবে সামান্য পরিবর্তন দিয়ে।

    // receiving "Bar" in 1st
    String received = await Navigator.push(context, MaterialPageRoute(builder: (_) => Page2("Foo")));
    

নেভিগেটর.পপ ইউন্টিলেট পদ্ধতিটি ব্যবহার করে রুট সি থেকে পপিং করার সময় আমি কীভাবে রুট এ পুনরায় লোড করতে পারি।
বিনোথ ভিনো

4
@ উইনোথভিনো এখন পর্যন্ত এটি করার সরাসরি কোনও উপায় নেই, আপনাকে কিছুটা কাজ করতে হবে।
পুলিশঅনরোড করুন

10

আপনি পুশ-রিপ্লেসমেন্ট ব্যবহার করতে পারেন এবং নতুন রুটটি নির্দিষ্ট করতে পারেন


তবে আপনি ন্যাভিগেটর স্ট্যাকটি হারাচ্ছেন। আপনি যদি অ্যান্ড্রয়েড ব্যাক বোতামটি ব্যবহার করে স্ক্রিনটি পপ করেন?
encubos

10

সহজ কৌশলের ব্যবহার করা Navigator.pushReplacement পদ্ধতি

পৃষ্ঠা 1

Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => Page2(),
  ),
);

পৃষ্ঠা ২

Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => Page1(),
  ),
);

এইভাবে আপনি নেভিগেটর স্ট্যাকটি হারাচ্ছেন। পিছনের বোতামটি দিয়ে পর্দা পপিংয়ের কী হবে?
encubos

5

এই কাজটি সত্যিই ভাল, আমি এই ডকটি থেকে পেচানো পাতা থেকে পেয়েছি: ফ্লুর ডক

আমি প্রথম পৃষ্ঠা থেকে নেভিগেশন নিয়ন্ত্রণ করার পদ্ধতিটি সংজ্ঞায়িত করেছি।

_navigateAndDisplaySelection(BuildContext context) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => AddDirectionPage()),
    );

    //below you can get your result and update the view with setState
    //changing the value if you want, i just wanted know if i have to  
    //update, and if is true, reload state

    if (result) {
      setState(() {});
    }
  }

সুতরাং, আমি এটি একটি ইনকওয়েল থেকে অ্যাকশন পদ্ধতিতে বলি, তবে এটি একটি বোতাম থেকেও কল করা যেতে পারে:

onTap: () {
   _navigateAndDisplaySelection(context);
},

এবং অবশেষে দ্বিতীয় পৃষ্ঠায়, কিছু ফেরত দিতে (আমি একটি বিল ফিরিয়ে দিয়েছি, আপনি যা খুশি ফিরে আসতে পারেন):

onTap: () {
  Navigator.pop(context, true);
}

4
আপনি এমনকি await Navigator....এবং পপ ফলাফল ফলাফল বাদ দিতে পারেন ।
0

4

আপনি যেখানে দ্বিতীয় স্ক্রিনে চাপ দিচ্ছেন এটি রাখুন (একটি অ্যাসিঙ্ক ফাংশনের অভ্যন্তরে)

Function f;
f= await Navigator.pushNamed(context, 'ScreenName');
f();

যেখানে আপনি পপিং করছেন সেখানে রাখুন

Navigator.pop(context, () {
 setState(() {});
});

setStateভিতরে বলা হয় popঅবসান তথ্য আপডেট করতে।


4
আপনি setStateযুক্তি হিসাবে ঠিক কোথায় পাস ? আপনি মূলত setStateএকটি বন্ধের ভিতরে কল করছেন । তর্ক হিসাবে এটি পাস না।
ভোলকান গাভেন

এটি আমি সঠিক উত্তরটি খুঁজছিলাম। আমি মূলত এর জন্য একটি সমাপ্তি হ্যান্ডলার চেয়েছিলাম Navigator.pop
ডেভিড চপিন

2

আমার সমাধানটি সেকেন্ডপেজে একটি ফাংশন প্যারামিটার যুক্ত করে চলে গেছে, তারপরে পুনরায় লোডিং ফাংশনটি পেয়েছে যা ফার্স্টপেজ থেকে করা হচ্ছে, তারপরে ন্যাভিগেটর.পপ (প্রসঙ্গ) লাইনের আগে ফাংশনটি সম্পাদন করে।

প্রথম পৃষ্ঠা

refresh() {
setState(() {
//all the reload processes
});
}

তারপরে পরবর্তী পৃষ্ঠায় ঠেলাঠেলি ...

Navigator.push(context, new MaterialPageRoute(builder: (context) => new SecondPage(refresh)),);

দ্বিতীয় পাতা

final Function refresh;
SecondPage(this.refresh); //constructor

তারপর নেভিগেটর পপ লাইনের আগে,

widget.refresh(); // just refresh() if its statelesswidget
Navigator.pop(context);

পূর্ববর্তী পৃষ্ঠা থেকে পুনরায় লোড করা দরকার এমন সমস্ত কিছু পপের পরে আপডেট করা উচিত।


1

আপনি dynamic resultযখন প্রসঙ্গটি পপ করছেন তখন আপনি আবার পাস করতে পারেন এবং তারপরে setState((){})যখন মানটি trueঅন্যথায় হয় ঠিক তখনই রাজ্যটি যেমন রেখে যান ততক্ষণ কল করতে পারেন।

আমি আপনার রেফারেন্সের জন্য কিছু কোড স্নিপেট পেস্ট করেছি।

handleClear() async {
    try {
      var delete = await deleteLoanWarning(
        context,
        'Clear Notifications?',
        'Are you sure you want to clear notifications. This action cannot be undone',
      );
      if (delete.toString() == 'true') {
        //call setState here to rebuild your state.

      }
    } catch (error) {
      print('error clearing notifications' + error.toString());
             }
  }



Future<bool> deleteLoanWarning(BuildContext context, String title, String msg) async {

  return await showDialog<bool>(
        context: context,
        child: new AlertDialog(
          title: new Text(
            title,
            style: new TextStyle(fontWeight: fontWeight, color: CustomColors.continueButton),
            textAlign: TextAlign.center,
          ),
          content: new Text(
            msg,
            textAlign: TextAlign.justify,
          ),
          actions: <Widget>[
            new Container(
              decoration: boxDecoration(),
              child: new MaterialButton(
                child: new Text('NO',),
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
              ),
            ),
            new Container(
              decoration: boxDecoration(),
              child: new MaterialButton(
                child: new Text('YES', ),
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
              ),
            ),
          ],
        ),
      ) ??
      false;
}

শুভেচ্ছা, মাহি


আমি নিশ্চিত না যে আমি দ্বিতীয় অংশটি কীভাবে করব তা বুঝতে পেরেছি। প্রথম ঠিক Navigator.pop(context, true), ঠিক আছে? তবে আমি কীভাবে এই trueমূল্য অর্জন করতে পারি ? ব্যবহার করছেন BuildContext?
বারটেকটার্টানুস

আমার জন্য কাজ করছে না। আমি ফলাফলটি ধাক্কা দিয়ে ব্যবহার করেছি, সেটস্টেট নামে পরিচিত এবং পেয়েছিsetState() called after dispose(): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. ....
বারটেকটার্টানুস

হুঁ, আপনি if(!mounted) return;প্রতিটি কল করার আগে setState((){});আপনি কীভাবে এইভাবে ব্যবহার করেছিলেন আপনি ডিসপোজড উইজেট বা উইজেটগুলি আর সক্রিয় নয় এমন আপডেটগুলি এড়াতে পারবেন।
মাহি 20

কোনও ত্রুটি নয় তবে এটি আমার পূর্বাভাস হিসাবে কাজ করছে না;)
বারটেকটার্টানুস

আমার কাছে @ বার্তেক্টার্টানাসের মতো একই সমস্যা রয়েছে। আমি যদি যোগ করি! সেটস্টেটের আগে মাউন্ট করা থাকলে, আমার রাজ্য কখনই সেট করা হবে না। এটি সহজ বলে মনে হচ্ছে তবে কয়েক ঘন্টা পরে আমি এটি বের করতে পারি নি।
সুইফট

1

আমার স্টেটলেস উইজেটগুলির একটি পুনঃনির্মাণ করার জন্য জোর করা দরকার। স্টেটফুল ব্যবহার করতে চান না। এই সমাধান নিয়ে এসেছেন:

await Navigator.of(context).pushNamed(...);
ModalRoute.of(enclosingWidgetContext);

নোট করুন যে প্রসঙ্গ এবং এনকোলেসিং উইজেটকন্টেক্সট একই বা বিভিন্ন প্রসঙ্গ হতে পারে। উদাহরণস্বরূপ, আপনি যদি স্ট্রিমবিল্ডারের ভিতরে থেকে চাপ দেন তবে সেগুলি আলাদা।

আমরা এখানে মডেলরউটে কিছু করি না। একাই সাবস্ক্রাইব করার কাজটি পুনর্নির্মাণের জন্য যথেষ্ট।


1

আপনি যদি সতর্কতা ডায়ালগ ব্যবহার করেন তবে আপনি এমন ফিউচার ব্যবহার করতে পারেন যা ডায়ালগটি বাতিল হয়ে গেলে সম্পূর্ণ হয়। ভবিষ্যতের সমাপ্তির পরে আপনি উইজেটটিকে রাষ্ট্র পুনরায় লোড করতে বাধ্য করতে পারেন।

প্রথম পৃষ্ঠা

onPressed: () async {
    await showDialog(
       context: context,
       builder: (BuildContext context) {
            return AlertDialog(
                 ....
            );
       }
    );
    setState(() {});
}

সতর্কতা সংলাপে

Navigator.of(context).pop();

0

আজ আমি একই পরিস্থিতির মুখোমুখি হয়েছি তবে আমি এটিকে আরও সহজ উপায়ে সমাধান করতে পেরেছি, আমি কেবলমাত্র একটি বিশ্বব্যাপী পরিবর্তনশীল সংজ্ঞায়িত করেছি যা প্রথম রাষ্ট্রীয় শ্রেণিতে ব্যবহৃত হয়েছিল, এবং যখন আমি দ্বিতীয় রাষ্ট্রীয় উইজেটে নেভিগেট করি তখন আমি এটিকে গ্লোবালের মান আপডেট করতে দিয়েছি পরিবর্তনশীল যা স্বয়ংক্রিয়ভাবে প্রথম উইজেটকে আপডেট করতে বাধ্য করে। এখানে একটি উদাহরণ রয়েছে (আমি তাড়াহুড়ো করে লিখেছি যাতে আমি কোনও ভাস্কর্য বা কোনও উপাদান অ্যাপ রাখি না, আমি কেবল আমার বক্তব্যটিই বর্ণনা করতে চেয়েছিলাম):

import 'package:flutter/material.dart';
int count = 0 ;

class FirstPage extends StatefulWidget {
FirstPage({Key key}) : super(key: key);

@override
_FirstPageState createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
@override
Widget build(BuildContext context) {
return InkWell(
onTap(){
Navigator.of(context).push(MaterialPageRoute(builder: (context) =>
                  new SecondPage());
},
child: Text('First', style : TextStyle(fontSize: count == 0 ? 20.0 : 12.0)),
),

}


class SecondPage extends StatefulWidget {
SecondPage({Key key}) : super(key: key);

@override
_SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
@override
Widget build(BuildContext context) {
return IconButton(
         icon: new Icon(Icons.add),
         color: Colors.amber,
         iconSize: 15.0,
         onPressed: (){
         count++ ;
         },
       ),
     }

4
ভেরিয়েবল পরিবর্তন করা স্বয়ংক্রিয়ভাবে উইজেটটি পুনরায় তৈরি করবে না। এরপরে Navigator.pop()এটি রাষ্ট্রকে ধরে রাখবে Navigator.push()যতক্ষণ না setStateআবার ফোন করা হয়, এই কোডটিতে কী ঘটে না। আমি কিছু অনুপস্থিত করছি?
রিকার্ডো বিআরজিওয়েব

0

এই সরল কোডটি আমার কাছে রুটে যেতে এবং রাষ্ট্রটি পুনরায় লোড করার জন্য কাজ করেছিল:

    ...
    onPressed: () {
         Navigator.of(context).pushNamedAndRemoveUntil('/', ModalRoute.withName('/'));
                },
    ...
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.