Scaffold.of () এমন একটি প্রসঙ্গে বলা হয়েছে যাতে স্ক্যাফোড থাকে না


183

যেমন আপনি দেখতে পাচ্ছেন আমার বোতামটি স্ক্যাফোোল্ডের দেহের ভিতরে। তবে আমি এই ব্যতিক্রম পাই:

Scaffold.of () এমন একটি প্রসঙ্গে বলা হয়েছে যাতে স্ক্যাফোড থাকে না।

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SnackBar Playground'),
      ),
      body: Center(
        child: RaisedButton(
          color: Colors.pink,
          textColor: Colors.white,
          onPressed: _displaySnackBar(context),
          child: Text('Display SnackBar'),
        ),
      ),
    );
  }
}

_displaySnackBar(BuildContext context) {
  final snackBar = SnackBar(content: Text('Are you talkin\' to me?'));
  Scaffold.of(context).showSnackBar(snackBar);
}

সম্পাদনা করুন:

আমি এই সমস্যার আর একটি সমাধান খুঁজে পেয়েছি। যদি আমরা স্ক্যাফোল্ডকে এমন কী দিয়ে থাকি যা গ্লোবালকি হয় তবে আমরা স্নাকবারকে বিল্ডার উইজেট দিয়ে আমাদের দেহটি মোড়ানোর প্রয়োজন ছাড়াই নিম্নলিখিত হিসাবে প্রদর্শিত করতে পারি। স্ক্যাফোর্ডটি যে উইজেটটি ফেরত দেয় তা স্টেটফুল উইজেট হওয়া উচিত:

 _scaffoldKey.currentState.showSnackBar(snackbar); 

আমি একটি খুব ভাল টিউটোরিয়াল পেয়েছি যেখানে তিনি একটি মোড়ক তৈরি করেছিলেন যাতে সহজেই পুরো অ্যাপ্লিকেশনের প্রেক্ষাপটটি পরিবর্তন বা নিয়ন্ত্রণ করতে পারে: noobieprogrammer.blogspot.com/2020/06/…
doppelgunner

উত্তর:


245

এই ব্যতিক্রম ঘটায় কারণ আপনি contextতাত্ক্ষণিকভাবে যে উইজেটটি ব্যবহার করছেন Scaffoldcontextসন্তানের নয় Scaffold

আপনি কেবল একটি ভিন্ন প্রসঙ্গ ব্যবহার করে এটি সমাধান করতে পারেন:

Scaffold(
    appBar: AppBar(
        title: Text('SnackBar Playground'),
    ),
    body: Builder(
        builder: (context) => 
            Center(
            child: RaisedButton(
            color: Colors.pink,
            textColor: Colors.white,
            onPressed: () => _displaySnackBar(context),
            child: Text('Display SnackBar'),
            ),
        ),
    ),
);

মনে রাখবেন যে আমরা Builderএখানে ব্যবহার করার সময় , কোনও আলাদা পাওয়ার একমাত্র উপায় এটি নয় BuildContext

সাবট্রিটি আলাদা Widget(সাধারণত extract widgetরিফ্যাক্টর ব্যবহার করে ) এর মাধ্যমে সাবট্রিটি বের করাও সম্ভব


আমি এটির সাথে এই ব্যতিক্রমটি পাই: সেটস্টেট () বা মার্কনিডস বিল্ড () বিল্ড চলাকালীন কল করা হয়। আই / ফ্লটার (21754): এই স্ক্যাফোল্ড উইজেটটি নির্মাণের প্রয়োজন হিসাবে চিহ্নিত করা যায় না কারণ কাঠামোটি ইতিমধ্যে আই / ফ্লটারে রয়েছে (21754): উইজেট তৈরির প্রক্রিয়া।
ফিজেন গঙ্গার

1
onPressedআপনি প্রেরণ RaisedButtonএকটি ফাংশন নয়। এটিকে পরিবর্তন করুন() => _displaySnackBar(context)
রামি রসসলেট

গোছা: অনপ্রেসড: () d _ডিসপ্লেস্প্যাকবার (প্রসঙ্গ);}, ধন্যবাদ =)
ফিজেন গঙ্গার

1
আমি .of (প্রসঙ্গে) দিয়ে ভেবেছিলাম যে উইজেট শ্রেণিবদ্ধতাকে প্রদত্ত কোনও ধরণের মুখোমুখি না হওয়া অবধি ভ্রমণ করা উচিত, এক্ষেত্রে স্ক্যাফোোল্ড, এটি "উইজেট বিল্ড (..") এ পৌঁছানোর আগেই এটির মুখোমুখি হওয়া উচিত। এটি কি কাজ করে না? এইভাবে?
কোডগ্রু

@ রুমিআরসলেট, বিড়বিড় করে প্রকারের কত প্রকার? আপনি যেমন উইজেটের প্রসঙ্গ বলেছেন, স্ক্যাফোর্ডের কোনও সন্তানের প্রসঙ্গ।
কপসঅনরোড করুন

121

আপনি একটি ব্যবহার করতে পারেন GlobalKey। একমাত্র ক্ষতি হ'ল গ্লোবালকে ব্যবহার করা এটির সবচেয়ে কার্যকর উপায় নাও হতে পারে।

এ সম্পর্কে একটি ভাল বিষয় হ'ল আপনি এই কীটি অন্য কাস্টম উইজেট শ্রেণিতেও দিতে পারেন যাতে কোনও স্ক্যাফোড থাকে না। দেখুন ( এখানে )

class HomePage extends StatelessWidget {
  final _scaffoldKey = GlobalKey<ScaffoldState>(); \\ new line
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,                           \\ new line
      appBar: AppBar(
        title: Text('SnackBar Playground'),
      ),
      body: Center(
        child: RaisedButton(
          color: Colors.pink,
          textColor: Colors.white,
          onPressed: _displaySnackBar(context),
          child: Text('Display SnackBar'),
        ),
      ),
    );
  }
  _displaySnackBar(BuildContext context) {
    final snackBar = SnackBar(content: Text('Are you talkin\' to me?'));
    _scaffoldKey.currentState.showSnackBar(snackBar);   \\ edited line
  }
}

ধন্যবাদ লেবোহ্যাং মবেলে
বিকাশকারী

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

1
আমার নিজের প্রশ্নের জবাব দিতে: একটি GlobalKey<ScaffoldState>সম্পত্তি দিয়ে একটি সিঙ্গলটন ক্লাস তৈরি করুন , সিঙ্গলটনের মূল সম্পত্তি সেট করার জন্য স্ক্যাফোল্ডের সাহায্যে উইজেটের কনস্ট্রাক্টরকে সম্পাদনা করুন, তারপরে শিশু উইজেটের গাছে আমরা এমন কিছু কল করতে পারি mySingleton.instance.key.currentState.showSnackBar()...
এক্সেক্টাবক্স

কেন এই অদক্ষতা?
ব্যবহারকারীর 23233706

@ user2233706 এটি এখানে গ্লোবালকির ডকুমেন্টেশনে উল্লেখ করা হয়েছে । এছাড়াও এই পোস্টে আরও আলো ফেলতে পারে।
লেবোহাং মেবেলে

43

এই সমস্যা সমাধানের দুটি উপায়

1) বিল্ডার উইজেট ব্যবহার করে

Scaffold(
    appBar: AppBar(
        title: Text('My Profile'),
    ),
    body: Builder(
        builder: (ctx) => RaisedButton(
            textColor: Colors.red,
            child: Text('Submit'),
            onPressed: () {
                 Scaffold.of(ctx).showSnackBar(SnackBar(content: Text('Profile Save'),),);
            }               
        ),
    ),
);

2) গ্লোবালকি ব্যবহার করে

class HomePage extends StatelessWidget {

  final globalKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
     return Scaffold(
       key: globalKey,
       appBar: AppBar(
          title: Text('My Profile'),
       ),
       body:  RaisedButton(
          textColor: Colors.red,
          child: Text('Submit'),
          onPressed: (){
               final snackBar = SnackBar(content: Text('Profile saved'));
               globalKey.currentState.showSnackBar(snackBar);
          },
        ),
     );
   }
}

16

পদ্ধতির ডকুমেন্টেশন থেকে এটি পরীক্ষা করুন:

স্ক্যাফোর্ডটি আসলে একই বিল্ড ফাংশনে তৈরি করা হয়, তখন বিল্ড ফাংশনটির প্রসঙ্গে যুক্তিটি স্ক্যাফোোল্ডটি খুঁজে পেতে ব্যবহার করা যায় না (যেহেতু এটি উইজেটটি "উপরে" দেওয়া হয়)। এই ধরনের ক্ষেত্রে, একটি বিল্ডারের সাথে নিম্নলিখিত কৌশলটি স্কেলফোল্ডের "অধীনে" একটি বিল্ডকন্টেক্সট সহ একটি নতুন সুযোগ প্রদান করতে ব্যবহার করা যেতে পারে:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Demo')
    ),
    body: Builder(
      // Create an inner BuildContext so that the onPressed methods
      // can refer to the Scaffold with Scaffold.of().
      builder: (BuildContext context) {
        return Center(
          child: RaisedButton(
            child: Text('SHOW A SNACKBAR'),
            onPressed: () {
              Scaffold.of(context).showSnackBar(SnackBar(
                content: Text('Hello!'),
              ));
            },
          ),
        );
      },
    ),
  );
}

আপনি পদ্ধতি নথির বিবরণ থেকে বিবরণটি পরীক্ষা করতে পারেন


13

এই সমস্যাটি সমাধানের সহজ উপায়টি নীচের কোড সহ আপনার ফাইনালের মতো এই স্কোলফোর্ডের জন্য একটি কী তৈরি করবে:

প্রথম: GlobalKey<ScaffoldState>() _scaffoldKey = GlobalKey<ScaffoldState> ();

Scecond: আপনার স্ক্যাফোর্ডে কী বরাদ্দ করুন key: _scaffoldKey

তৃতীয়: স্ন্যাকবারকে কল করে কল করুন _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Welcome")));


3

আপনি যে আচরণটি খুব সহ্য করছেন তা ফ্লিট ডকুমেন্টেশনে একটি "কৃপণ মামলা" হিসাবেও উল্লেখ করা হয় ।

কিভাবে ঠিক করবো

আপনি এখানে পোস্ট করা অন্যান্য উত্তরগুলি থেকে দেখতে পাওয়ায় সমস্যাটি বিভিন্নভাবে সংশোধন করা হয়েছে। উদাহরণস্বরূপ, ডকুমেন্টেশনের অংশটি আমি উল্লেখ করি Builderযা তৈরি করে এটি ব্যবহার করে সমস্যার সমাধান করে

ইনার BuildContextযাতে onPressedপদ্ধতি উল্লেখ করতে পারেন Scaffoldসঙ্গে Scaffold.of()

এইভাবে স্ক্যাফোডshowSnackBar থেকে কল করার কোনও উপায় হবে

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('Demo')),
    body: Builder(
      builder: (BuildContext innerContext) {
        return FlatButton(
          child: Text('BUTTON'),
          onPressed: () {
            Scaffold.of(innerContext).showSnackBar(SnackBar(
              content: Text('Hello.')
            ));
          }
        );
      }
    )
  );
}

কৌতূহলী পাঠকের জন্য এখন কিছু বিশদ

আমি নিজেই ( অ্যান্ড্রয়েড স্টুডিও ) কোডের কোনও টুকরোতে কার্সার সেট করে ( ফ্লার্ট ক্লাস, পদ্ধতি ইত্যাদি) এবং সেই নির্দিষ্ট অংশটির জন্য ডকুমেন্টেশন দেখানোর জন্য সিআরটিএল + বি টিপুন দিয়ে ফ্লার্ট ডকুমেন্টেশন অন্বেষণ করতে বেশ শিক্ষণীয় পেয়েছি ।

আপনি যে বিশেষ সমস্যার মুখোমুখি হচ্ছেন তা বিল্ডকন্টেক্সটেক্সের নথিতে উল্লেখ করা হয়েছে , যেখানে পড়া যায়

প্রতিটি উইজেটের নিজস্ব বিল্ডকন্টেক্সট থাকে , যা [...] বিল্ড ফাংশন দ্বারা ফিরিয়ে দেওয়া উইজেটের পিতামাতার হয়ে ওঠে।

সুতরাং, এর অর্থ হ'ল আমাদের ক্ষেত্রে প্রসঙ্গটি যখন আমাদের স্ক্যাফোल्ड উইজেট তৈরি হবে ( তখন ) তখন সেটির পিতামাতা হবেন । আরও, Scaffold.of এর জন্য দস্তাবেজটি বলে যে এটি ফিরে আসে

এই শ্রেণীর নিকটতম [ স্ক্যাফোর্ড ] উদাহরণ থেকে রাষ্ট্র যা প্রদত্ত প্রসঙ্গটি আবদ্ধ করে।

তবে আমাদের ক্ষেত্রে, প্রসঙ্গে একটি স্ক্যাফোল্ড (এখনও এটি নির্মিত হয়নি) enc সেখানে নির্মাতা কর্মে আসে!

আবারও ডকুমেন্ট আমাদের আলোকিত করে। সেখানে আমরা পড়তে পারি

[বিল্ডার ক্লাসটি সহজভাবে] একটি প্লাটোনিক উইজেট যা তার শিশু উইজেট পাওয়ার জন্য একটি ক্লোজারকে ডাকে।

আরে, এক মুহুর্ত অপেক্ষা কর, কি !? ঠিক আছে, আমি স্বীকার করি: এটি খুব একটা সহায়তা করছে না ... তবে এটি ( অন্য এসও থ্রেড অনুসরণ করে ) যথেষ্ট বলা যথেষ্ট

বিল্ডার শ্রেণীর উদ্দেশ্য কেবলমাত্র শিশু উইজেটগুলি তৈরি এবং ফিরিয়ে আনা।

তো এখন সব পরিষ্কার হয়ে গেল! কল করে নির্মাতা ভিতরে ভারা আমরা অনুক্রমে এর নিজস্ব প্রসঙ্গের প্রাপ্ত পাবে ফাঁসির মঞ্চ নির্মাণ করা হয়, এবং সশস্ত্র সঙ্গে যে innerContext পরিশেষে আমরা কল করতে পারেন (innerContext) Scaffold.of

উপরের কোডটির একটি এনোটোটেড সংস্করণ নীচে অনুসরণ করা হয়েছে

@override
Widget build(BuildContext context) {
  // here, Scaffold.of(context) returns null
  return Scaffold(
    appBar: AppBar(title: Text('Demo')),
    body: Builder(
      builder: (BuildContext innerContext) {
        return FlatButton(
          child: Text('BUTTON'),
          onPressed: () {
            // here, Scaffold.of(innerContext) returns the locally created Scaffold
            Scaffold.of(innerContext).showSnackBar(SnackBar(
              content: Text('Hello.')
            ));
          }
        );
      }
    )
  );
}

1

আমি ডিফল্ট স্নাকবার ব্যবহার করে বিরক্ত করব না, কারণ আপনি ফ্লাশবার প্যাকেজটি আমদানি করতে পারেন, যা বৃহত্তর অনুকূলিতকরণকে সক্ষম করে:

https://pub.dev/packages/flushbar

উদাহরণ স্বরূপ:

Flushbar(
                  title:  "Hey Ninja",
                  message:  "Lorem Ipsum is simply dummy text of the printing and typesetting industry",
                  duration:  Duration(seconds: 3),              
                )..show(context);

0

আরও কার্যকর সমাধান হ'ল আপনার বিল্ড ফাংশনটিকে কয়েকটি উইজেটে বিভক্ত করা। এটি একটি 'নতুন প্রসঙ্গ' উপস্থাপন করে, যা থেকে আপনি স্ক্যাফোড পেতে পারেন

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Scaffold.of example.')),
        body: MyScaffoldBody(),
      ),
    );
  }
}

class MyScaffoldBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
          child: Text('Show a snackBar'),
          onPressed: () {
            Scaffold.of(context).showSnackBar(
              SnackBar(
                content: Text('Have a Snack'),
              ),
            );
          }),
    );
  }
}

0

আপনার বোতামের উইজেটটি এক্সট্রাক্ট করুন যা স্নাকবার প্রদর্শন করবে।

class UsellesslyNestedButton extends StatelessWidget {
  const UsellesslyNestedButton({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: (){
        showDefaultSnackbar(context);
                    },
                    color: Colors.blue,
                    child: Text('Show about'),
                  );
  }
}

আপনার দৃষ্টিভঙ্গি কীভাবে বিদ্যমান উত্তরের সাথে তুলনা করে? এই পন্থাটি গ্রহণের উত্তরটি বেছে নেওয়ার কোনও কারণ আছে কি?
জেরেমি কেনে

0

এখানে আমরা অন্য উইজেটে মোড়াতে একটি বিল্ডার ব্যবহার করি যেখানে আমাদের স্নাকবার প্রয়োজন

Builder(builder: (context) => GestureDetector(
    onTap: () {
        Scaffold.of(context).showSnackBar(SnackBar(
            content: Text('Your Services have been successfully created Snackbar'),
        ));
        
    },
    child: Container(...)))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.