<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های رضا اسفندیاری</title>
        <link>https://virgool.io/feed/@resfandiari</link>
        <description>توسعه دهنده موبایل و وب . همیشه دنبال بهتر شدن (ادرس کانالم  : t.me/resfandiari)</description>
        <language>fa</language>
        <pubDate>2026-06-07 00:48:46</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/6214/avatar/Sr9hFB.png?height=120&amp;width=120</url>
            <title>رضا اسفندیاری</title>
            <link>https://virgool.io/@resfandiari</link>
        </image>

                    <item>
                <title>پکیج پرداخت و ارتباط با کافه بازار برای فلاتر</title>
                <link>https://virgool.io/flutter-community/%D9%BE%DA%A9%DB%8C%D8%AC-%D9%BE%D8%B1%D8%AF%D8%A7%D8%AE%D8%AA-%D9%88-%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D8%A8%D8%A7-%DA%A9%D8%A7%D9%81%D9%87-%D8%A8%D8%A7%D8%B2%D8%A7%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-ngxpnjck9q7n</link>
                <description>سلام و درود دوستان امیدوارم که حالتون خوب باشهچند روز پیش برای پیاده سازی سیستم پرداخت درون برنامه ای کافه بازار توی اپلیکشن فلاتر دنبال یک پکیج بودم که متوجه شدم خود کافه بازار متاسفانه چیزی ارائه نداده و نمیدونم چرا (امیدوارم هر چه سریعتر این کار رو انجام بدن).حالا به هر صورت باید با استفاده از پکیج موجود برای نسخه نیتیو اندروید و با استفاده از Method Channel پیاده سازی میکردم پرداخت رو و یا دنبال پکیج های غیر رسمی میگشتم.که من راه دوم رو انتخاب کردم و یک پکیج پیدا کردمپکیج cafebazaar_flutterخوب اولش تشکر کنم از بچه های خوب وب سایت flutterfarsi.ir  برای این پکیج اما ضعف هایی داشت که بیخیالش شدم  و به دلیل حجم بالای تغییرات از دادن PR هم صرف نظر کردم :بزرگترین مشکلش این بود طبق release قبلی Flutter Plugin بود.در صورت باز بودن  اپ ما اگر در هر صورتی ارتباط با اپ کافه بازار قطع میشد (یعنی کاربر اپ رو میبست یا سیستم به هر دلیلی به سرویس کافه بازار خاتمه میداد) اپ ما هم کرش میکرد.مشکل شایع پلاگین های فلاتر  رو داشت یعنی همون (java.lang.IllegalStateException: Reply already submitted) که باز هم اپ کرش میکرد.بخش چک کردن اپدیت برنامه پیاده سازی نشده بود.خوب در هر صورت مجبور شدم یه پکیج بنویسم که مشکلات بالا رفع شده باشن و همه امکانات کافه بازار رو داشته باشه از جمله:رفتن به صفحه اپلیکیشنگذاشتن کامنت و امتیاز دادن به برنامهرفتن به صفحه برنامه نویسرفتن به صفحه ورود کافه بازاربررسی اپدیت بودن برنامه در صورت موجود بودن نسخه جدیدو از همه مهم تر بخش پرداخت کافه بازارادرس پکیجcafebazaar_marketو در اخر هم اگر در حین استفادتون مشکلی داشت شما مثل من نباشید PR بدید خوشحال میشم :))موفق باشید.</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Mon, 29 Jun 2020 18:18:12 +0430</pubDate>
            </item>
                    <item>
                <title>میانبرهای سریع در فلاتر</title>
                <link>https://virgool.io/flutter-community/%D9%85%DB%8C%D8%A7%D9%86%D8%A8%D8%B1%D9%87%D8%A7%DB%8C-%D8%B3%D8%B1%DB%8C%D8%B9-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-j9einlrfcq0w</link>
                <description>حتما شده تا حالا وقتی توی صفحه اصلی دیوایستون دستتون رو روی ایکون یک اپلیکیشن نگه میدارید یه سری امکانات بهتون میده که بتونید موقع باز شدن اپ مستقیما به محل مورد نظرتون برید ، اینها میانبرهایی هستن که باید توی اپتون تعریف کنید.به این میانبرهای توی فلاتر Quick actions میگن که البته در iOS معروف هست به eponymous conceptو در اندروید معروف به App Shortcuts هستن. نحوه استفاده مثل همیشه اول پروژتون رو استارت کنید.وارد فایل pubspec.yaml بشید و اخرین نسخه این پلاگین رو به اپتون اضافه کنید.name: quick_action
description: A new Flutter application which demonstrates use of quick actions.

version: 1.0.0+1

environment:
  sdk: &amp;quot&gt;=2.1.0 &lt;3.0.0&amp;quot

dependencies:
  quick_actions: ^0.3.0+1
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true3.وارد فایل main.dart بشید و این رفرنس رو اضافه کنید:import ‘package:quick_actions/quick_actions.dart’;4.توی initState باید Initialize کنید لایبرری رو که با این کار در واقع شما یه callback قرار میدن و هر وقت اپلیکیشن به وسیله quick action فراخوانی شد میتونید اونو هندل کنید.@override
  void initState() {
    super.initState();

  final QuickActions quickActions = const QuickActions();
    quickActions.initialize((String shortcutType) {
      if (shortcutType == &#039;action_decrement&#039;) {
        print(&#039;The user tapped on the &amp;quotdecrement&amp;quot action.&#039;);
      } else {
        print(&#039;The user tapped on the &amp;quotincrement&amp;quot action.&#039;);
      }
    });
  }5. و در نهایت باید مدیریت کنیم میانبرهایی که قراره برای اپ ما نشون داده بشه @override
  void initState() {
    super.initState();
/**
* previous code
**/

quickActions.setShortcutItems(&lt;ShortcutItem&gt;[
      const ShortcutItem(
          type: &#039;action_decrement&#039;, localizedTitle: &#039;decrement&#039;, icon: &#039;minus&#039;),
      const ShortcutItem(
          type: &#039;action_increment&#039;, localizedTitle: &#039;increment&#039;, icon: &#039;plus&#039;)
    ]);
  }لطفا توجه کنید که حتما شناسه type  باید یکتا  باشه یعنی هر کدوم از میانبرهای شما باید شناسه type منحصر به فرد خودش رو داشته باشه.و این چیزیه که شما در نهایت دارید.امیدوارم به کارتون بیاد موفق باشید.کانال من : رضا اسفندیاری</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Mon, 30 Mar 2020 11:50:33 +0430</pubDate>
            </item>
                    <item>
                <title>ارتباط بین ویجت ها با استفاده از انواع callback در فلاتر</title>
                <link>https://virgool.io/flutter-community/%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D8%A8%DB%8C%D9%86-%D9%88%DB%8C%D8%AC%D8%AA-%D9%87%D8%A7-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%A7%D9%86%D9%88%D8%A7%D8%B9-callback-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-kju3pxjch2sf</link>
                <description>چرا این بحث مهمه؟ چون به ما اجازه میده که ویجت هامون رو به قسمت های کوچک تری تبدیل کنیم که به راحتی قابل تست و ویرایش باشن و بتونن با بخش اصلی به راحتی سازگار بشن.ساختن یک پروژه جدیدمثل همیشه با راه اندازی یک پروژه جدید شروع میکنیم :# New Flutter project
$ flutter create widget_communication# Open this up inside of VS Code
$ cd widget_communication &amp;&amp; code . حالا  پروژه رو توی VS Code یا Android studio باز میکنیم.اماده کردن بیس پروژهاول باید بیس پروژمون رو  خیلی ساده ایجاد کنیم. برای این کار وارد main.dart میشیم و این فایل رو اپدیت میکنیم به وسیله دادن رفرنس به CounterPage که جلوتر میسازیمشimport &#039;package:flutter/material.dart&#039;;
import &#039;package:widget_communication/counter_page.dart&#039;;void main() =&gt; runApp(MyApp());class MyApp extends StatelessWidget {  @override
    Widget build(BuildContext context) {    return MaterialApp(
        title: &#039;Widget Communication&#039;,
            home: CounterPage(),
                );
    }
 }صفحه CounterPage ما یه StatefulWidget ساده هست :// counter_page.dart
import &#039;package:flutter/material.dart&#039;;
import &#039;package:widget_communication/count.dart&#039;;

class CounterPage extends StatefulWidget {
  _CounterPageState createState() =&gt; _CounterPageState();
}

class _CounterPageState extends State&lt;CounterPage&gt; {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(&amp;quotWidget Communication&amp;quot)),
      body: Center(
        child: Count(count),
      ),
    );
  }
}اگر توجه کنید داخل این ویجت ما یه متغیر count  داریم که برابر با 0 هست و پاسش دادیم به یه ویجت تحت عنوان Count  به صورت  property . حالا میریم سراغ ویجت Count :// count.dart
import &#039;package:flutter/material.dart&#039;;

class Count extends StatelessWidget {
  final int count;

  Count(this.count);

  @override
  Widget build(BuildContext context) {
    return Text(&amp;quot$count&amp;quot);
  }
}این چیزیه که تا حالا ساختیم
شروع با VoidCallbackبرای این مثال متغیر count رو داخل داخل یه دکمه میزاریم و بهش میگیم هر وقت روت کلیک شد  باید کلاس پدرت که CounterPage هست رو صدا بزنی.ما اینجا هیچ مقداری رو نمیخوایم بفرستیم، پس شروع میکنیم به راه اندازی VoidCallback و اسمش رو onCountSelected میزاریم :// count.dart
class Count extends StatelessWidget {
  final int count;
  final VoidCallback onCountSelected;

  Count({@required this.count, this.onCountSelected});

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      child: Text(&amp;quot$count&amp;quot),
      onPressed: () =&gt; onCountSelected(),
    );
  }
}حالا باید اپدیت کنیم CounterPage رو تا گوش بده به کال بک onCountSelected: // counter_page.dart
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text(&amp;quotWidget Communication&amp;quot)),
    body: Center(
      child: Count(
        count: count,
        onCountSelected: () {
          print(&amp;quotCount was selected.&amp;quot);
        },
      ),
    ),
  );
}حالا هر وقت ما روی counter کلیک کنیم باید Count was selected رو توی کنسول ببینیم.ادامه دادن با (Function(xهمینجوری که دیدید VoidCallback میتونه عالی باشه وقتی که قرار نباشه مقداری برگردونده بشه، اما اگر ما بخوایم مقدار برگردونیم چی؟اینجاست که (Function(x وارد میشه:// counter_page.dart
import &#039;package:flutter/material.dart&#039;;

class Count extends StatelessWidget {
  final int count;
  final VoidCallback onCountSelected;

  final Function(int) onCountChange;

  Count({
    @required this.count,
    @required this.onCountChange,
    this.onCountSelected,
  });

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: &lt;Widget&gt;[
        IconButton(
          icon: Icon(Icons.add),
          onPressed: () {
            onCountChange(1);
          },
        ),
        FlatButton(
          child: Text(&amp;quot$count&amp;quot),
          onPressed: () =&gt; onCountSelected(),
        ),
        IconButton(
          icon: Icon(Icons.remove),
          onPressed: () {
            onCountChange(-1);
          },
        ),
      ],
    );
  }
}اینجا ما دو تا دکمه اظافه کردیم همراه با یه (Function(int  به نام onCountChange که وقتی ما صداش بزنیم یک مقدار رو به ویجت پدرش برمیگردونه.توی ویجت پدر هم ما شروع به گوش دادن میکنیم هر وقت مقداری اومد count رو اپدیت میکنیم.class _CounterPageState extends State&lt;CounterPage&gt; {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(&amp;quotWidget Communication&amp;quot)),
      body: Center(
        child: Count(
          count: count,
          onCountSelected: () {
            print(&amp;quotCount was selected.&amp;quot);
          },
          onCountChange: (int val) {
            setState(() =&gt; count += val);
          },
        ),
      ),
    );
  }
}نتیجه نهایی:امیدوارم که درست شیوه کار کال بک ها رو یاد گرفته باشید. موفق باشید.</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Thu, 02 Jan 2020 12:11:47 +0330</pubDate>
            </item>
                    <item>
                <title>تبدیل عدد به حروف فارسی در فلاتر</title>
                <link>https://virgool.io/@resfandiari/%D8%AA%D8%A8%D8%AF%DB%8C%D9%84-%D8%B9%D8%AF%D8%AF-%D8%A8%D9%87-%D8%AD%D8%B1%D9%88%D9%81-%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-amstfmxmkfoj</link>
                <description>چند روز پیش برای یک پروژه مجبور بودم قیمت ورودی رو به صورت حروف  مثل چیزی که توی اپلیکیشن دیوار هست نشون بدم  همینجور که توی عکس پایین می بینید اعداد خودشون میمونن و فقط بخش ارزش اعداد(اگه درست گفته باشم) هست که به صورت حروف نوشته میشهتبدیل عدد به حروف در دیوار بعد از نوشتن پروژه دیدم هیچی بهتر از این نیست که به صورت یک پکیج قرارش بدم که همه بتونید استفاده کنید البته چند ویژگی دیگه هم بهش اضافه کردم .امیدوارم که به کارتون بیاد.موفق باشید/.ادرس پکیج (لایک یادتون نره ??)ادرس گیت هاب پکیج(ستاره یادتون نره ??)</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Sat, 28 Dec 2019 17:13:34 +0330</pubDate>
            </item>
                    <item>
                <title>Multiple Navigators and Keeping State with BottomNavigationBar in flutter</title>
                <link>https://virgool.io/@resfandiari/multiple-navigators-and-keeping-state-with-bottomnavigationbar-in-flutter-k4pgwylqz9j2</link>
                <description>سلام رضا اسفندیاری هستم .توی این پست قصدی برای توضیح دادن جزئیات کار ندارم و فقط میخوام بگم اهدافم از انجام این پروژه چی بود و ادرس پروژه رو روی گیت هابم بدم البته کاملا سعی کردم پروژه رو به ساده ترین شکل ممکن بنویسم که هر کسی با توجه به نیازش به راحتی بتونه  این روش رو اجرا کنه.البته حتما در اینده یک پست مفصل در این مورد مینویسم.اهداف من در این پروژهاین پروژه در مورد جابجایی بین صفحات مختلف در اپلیکیشن به وسیله BottomNavigationBar هست و من سعی کردم navigator اختصاصی فلاتر رو جوری کاستومایز کنم که بتونم به اهداف زیر برسم. هر Tab توی BottomNavigationBar یه Stack مخصوص به خودش رو داشته باشه.بشه مدیرت کاملی رو هر کدوم از  Stack  ها داشت. وضعیت هر صفحه ای چه Main_Page ها و چه  Sub_Page ها به طور کامل حفظ بشه. جابجایی بین صفحات  خیلی راحت و بدون هیچ درد سری انجام بشه.با دابل تپ روی هر Tab تمامی Sub_Page های اون Tab بسته بشن.ادرس پروژه روی گیتهاب</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Thu, 07 Nov 2019 00:45:36 +0330</pubDate>
            </item>
                    <item>
                <title>تجزیه فایل لوکال Json در فلاتر به صورت asynchronous</title>
                <link>https://virgool.io/flutter-community/%D8%AA%D8%AC%D8%B2%DB%8C%D9%87-%D9%81%D8%A7%DB%8C%D9%84-%D9%84%D9%88%DA%A9%D8%A7%D9%84-json-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-%D8%A8%D9%87-%D8%B5%D9%88%D8%B1%D8%AA-asynchronous-a4zeetiuhdew</link>
                <description>برای ساختن و توسعه دادن اپ های بزرگ موبایل ما احتیاج داریم که با استفاده از API داده های رو به صورت JSON  از سرور دریافت کنیم.کلمه JSON سرنام واژگان JavaScript Object Notation یک استاندارد سبک، باز ، متنی و خوانا برای انسان جهت انتقال داده و جایگزینی برای xml است. خوب خیلی کتابی شد ? چون کپی بود ادامشم اینجاست.در نهایت ما این داده ها رو میتونیم  به صورت لیستی از اشیاء(objects) نشون بدیم.اما گاهی وقت ها ممکنه ما این داده ها رو به صورت یک فایل json  در اپلیکیشن ذخیره کرده باشیم به جای اینکه از سرور بگیریم .این فایل رو ما میتونیم در هرجایی از دایرکتوری اپلیکیشن ذخیره کنیم طبق دستور العمل فلاتر ما این رو در پوشه assets ذخیره میکنیم و در زمان اجرا (runtime) بهش دسترسی پیدا میکنیم و از اون استفاده میکنیم.در این پست من یک اپلیکیشن فلاتر ایجاد میکنم و یک فایل json رو به صورت لوکال در اپ قرار میدم و از اون استفاده میکنم.ساخت پروژه جدیدیک پروژه جدید فلاتر رو توسط IDE محبوبتون ایجاد کنید.یه پوشه به نام assets در روت پروژتون ایجاد کنید و این فایل  country.json داخل پوشه کپی کنید.برای اینکه داخل پروژه بتونید به فایل دسترسی پیدا کنید باید اون رو pubspecs.yaml در  تعریف کنیم به این شکل:3. یه فایل به نام  list.dart ایجاد میکنیم . در این فایل ما لیستی از کشور ها رو به صورت array دریافت میکنیم و با استفاده از listview اونها رو نمایش میدیم.import &#039;package:flutter/foundation.dart&#039;;
import &#039;package:flutter/material.dart&#039;;
import &#039;package:flutter_load_local_json/country.dart&#039;;

class CountyList extends StatelessWidget {
  final List&lt;Country&gt; country;
  CountyList({Key key, this.country}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new ListView.builder(
        itemCount: country == null ? 0 : country.length,
        itemBuilder: (BuildContext context, int index) {
          return
                new Card(
                  child: new Container(
                    child: new Center(
                        child: new Column(
                      // Stretch the cards in horizontal axis
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: &lt;Widget&gt;[

                        new Text(
                          // Read the name field value and set it in the Text widget
                          country[index].name,
                          // set some style to text
                          style: new TextStyle(
                              fontSize: 20.0, color: Colors.lightBlueAccent),
                        ),
                        new Text(
                          // Read the name field value and set it in the Text widget
                          &amp;quotCapital:- &amp;quot + country[index].capital,
                          // set some style to text
                          style: new TextStyle(
                              fontSize: 20.0, color: Colors.amber),
                        ),
                      ],
                    )),
                    padding: const EdgeInsets.all(15.0),
                  ),
             );
        });
    }
}4.حالا فایل country.dart رو ایجاد میکنیم که حاوی مدل PODO فایل json ما هست و به وسیله این کلاس ما میتونم فایل json خودمون رو تجزیه (parse) کنیم.class Country {
  final String name;
  final String flag;
  final String capital;

  Country({this.name, this.flag, this.capital});

  factory Country.fromJson(Map&lt;String, dynamic&gt; json) {
    return new Country(
      name: json[&#039;name&#039;] as String,
      flag: json[&#039;flag&#039;] as String,
      capital: json[&#039;capital&#039;] as String,
    );
  }
}5. در پایان ما وارد فایل main.dart میشیم و و نحوه دریافت فایل و تجزیش رو مینویسم.برای انجام این کار ما از ویجت FutureBuilder استفاده میکنیم.همینجور که پایین میبینید من برای دریافت فایل json از پوشه assets از ویجت DefaultAssetBundle استفاده کردم و این فایل رو به پارامتر future ویجت FutureBuilder پاس دادم.future: DefaultAssetBundle.of(context)
                    .loadString(&#039;assets/country.json&#039;),زمانی که فایل به صورت کامل دریافت بشه ما محتویات فایل رو  از پارامتر builder  به صورت  snapshot.data.toString() دریافت میکنیم و ما اون رو به متد parseJson()  پاس میدیم تا تجزیش کنیم.List&lt;Country&gt; countries =
                      parseJson(snapshot.data.toString());متد parseJson()  برای ما لیستی از کشورها رو می سازه.List&lt;Country&gt; parseJosn(String response) {
    if(response==null){
      return [];
    }
    final parsed =
        json.decode(response.toString()).cast&lt;Map&lt;String, dynamic&gt;&gt;();
    return parsed.map&lt;Country&gt;((json) =&gt; new Country.fromJson(json)).toList();
  }در اینجا شما فایل main.dart به صورت کامل میبینید. حالا پروژه رو run کنید.import &#039;dart:convert&#039;;
import &#039;package:flutter/material.dart&#039;;
import &#039;package:flutter_load_local_json/country.dart&#039;;
import &#039;package:flutter_load_local_json/list.dart&#039;;

void main() {
  runApp(new MaterialApp(
    debugShowCheckedModeBanner: false,
    theme: new ThemeData(
      primaryColor: const Color(0xFF02BB9F),
      primaryColorDark: const Color(0xFF167F67),
      accentColor: const Color(0xFF167F67),
    ),
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() =&gt; new MyAppState();
}

class MyAppState extends State&lt;MyApp&gt; {
  List data;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text(&amp;quotLoad local JSON file&amp;quot,
            style: new TextStyle(color: Colors.white),),
        ),
        body: new Container(
          child: new Center(
            // Use future builder and DefaultAssetBundle to load the local JSON file
            child: new FutureBuilder(
                future: DefaultAssetBundle.of(context)
                    .loadString(&#039;assets/country.json&#039;),
                builder: (BuildContext context, AsyncSnapshot&lt;String&gt; snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                      return Text(&#039;Press button to start.&#039;);
                    case ConnectionState.active:
                    case ConnectionState.waiting:
                      return new Center(child: new CircularProgressIndicator());
                    case ConnectionState.done:
                      if (snapshot.hasError){
                        return Text(&#039;Error: ${snapshot.error}&#039;);
                      }else{
                        List&lt;Country&gt; countries =
                        parseJosn(snapshot.data.toString());
                        return !countries.isEmpty
                            ? new CountyList(country: countries)
                            : new Text(&amp;quotfile is empty&amp;quot);
                      }

                  }
                  return null; // unreachable
                },
          ),
        )));
  }

  List&lt;Country&gt; parseJosn(String response) {
    if(response==null){
      return [];
    }
    final parsed =
    json.decode(response.toString()).cast&lt;Map&lt;String, dynamic&gt;&gt;();
    return parsed.map&lt;Country&gt;((json) =&gt; new Country.fromJson(json)).toList();
  }
}اگر شما تمام کارهای بالا رو انجام داده باشید میبیند که اپلیکیشن کاملا روان بدون هیچ لاگی فایل رو دریافت میکنه و لیستی از کشور ها رو نمایش میده. اگر سوالی داشتید بپرسید. موفق باشیدادرس گیت هاب پروژهمن چیزهای زیاد از فلاتر توی کانالم میزارم میتونید من رو از اونجا دنبال کنید.کانال من</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Thu, 26 Sep 2019 16:43:28 +0330</pubDate>
            </item>
                    <item>
                <title>تبدیل استایل CSS به فلاتر استایل</title>
                <link>https://virgool.io/@resfandiari/%D8%AA%D8%A8%D8%AF%DB%8C%D9%84-%D8%A7%D8%B3%D8%AA%D8%A7%DB%8C%D9%84-css-%D8%A8%D9%87-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-%D8%A7%D8%B3%D8%AA%D8%A7%DB%8C%D9%84-qcxsgp6txixw</link>
                <description>اگر وب دولوپر باشید و به تازگی شروع به استفاده از فریم ورک فلاتر کرده باشید احتمالا در  فهمیدن کد های فلاتر مشکل دارید این وب سایت که به تازگی راه اندازی شده کد های CSS شما رو به معادل فلاترشون تبدیل میکنه و باعث میشه درک صحیحی از کدهای فلاتر پیدا کنید.https://flutterkit.github.io/c2f/موفق باشید.من چیزهای زیاد از فلاتر توی کانالم میزارم میتونید من رو از اونجا دنبال کنید.کانال من</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Wed, 18 Sep 2019 14:44:33 +0430</pubDate>
            </item>
                    <item>
                <title>ایجاد نسخه Web app  از اپلیکیشن های فلاتر</title>
                <link>https://virgool.io/@resfandiari/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D9%86%D8%B3%D8%AE%D9%87-web-app-%D8%A7%D8%B2-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-kruyptvtbxkj</link>
                <description>سلام دوستان امیدوارم حالتون خوب باشهکاری که من میخوام انجام بدم ایجاد یک نسخه وب از پروژه فعلی فلاترتون هست پس همین اولش برای اینکه نگران نشید قرار نیست کدتون تغییر کنه و همینجور قرار نیست نسخه موبایلتون از بین بره فقط میخوایم یک نسخه وب از اپلیکیشنتونو تولید کنیم.همینجور که میدونید به تازگی فلاتر اپدیت شد به نسخه 1.9 و همینجور  دارت هم به نسخه 2.5 و کلی ویژگی هم به این فریم ورک محبوب اظافه شد که خیلی جذاب ترش میکنه? به نظرم وقتشه این عکسو اپلود کنم??خوب شوخی کردم به قول شاعر هر کسی را (ما این جا میگیم هر چیزی را) بهر کاری ساختند.اما توی اپدیت اتفاقی که افتاد این بود که Flutter_web_repository منسوخ شد و ترکیب شد توی flutter repository که این معنیش اینه از این به بعد موبایل و وب هر دو از یک پکیج استفاده میکنناما بریم روی کار خودمون ؛ اگر نمیخواید این دستور العمل ها روی یه پروژه واقعی پیاده کنید پس قدم به قدم با من پیش بیایید اگر هم نه که مطلب رو از بخش تولید نسخه وب دنبال کنید.ایجادیک پروژه جدید فلاتر برای موبایل$ flutter create [project_name]اجرای پروژه روی شبیه ساز اندروید$ cd [project_name]
project_name$ flutter run -d [your_simulator]لیست شبیه ساز هاتون رو با این دستور میتونید ببینیدflutter devicesتولید نسخه وبخوب میرسیم به بخش جذاب موضوع این دستور رو توی دایرکتوری روت پروژتون وارد کنیدproject_name$ flutter create --web .این دستور یک دایرکتوری با نام webتوی پوشه پروژتون ایجاد میکنه اگر برای شما ایجاد نشده نگران نباشید شما باید دو چیز رو چک کنید:برنچ masterبرنامه نویسای گوگل فلاتر روی 4 برنچ stable/master/beta/dev دارن توسعه میدن این ویژگی مورد نظر ما در حال حاضر فقط روی  master  ارائه میشه پس اگر شما روی stable هستید باید master رو ست کنید.با این دستورproject_name$ flutter channel masterاین عملیات چند دقیقه ای با توجه به سرعت اینترنت شما طول میکشه.2. ابزار پیکربندی وبدر حالت پیش فرض ابزار فلاتر برای نسخه وب پیکر بندی نشدن پس شما باید خودتون این کار رو انجام بدید با این دستورproject_name$ flutter config --enable-webخوب حالا  شما باید لیست دیوایس هاتون رو چک کنید و مرورگرتون باید در لیست دیوایس هاتون باشهproject_name$ flutter devices&gt; Chrome • chrome • web-javascript • Google Chrome 75.0.3770.80حالا از دوباره دستور ساخت نسخه وب رو توی دایرکتوری روت پروژتون وارد کنید و اگه دستورات بالا رو درست انجام داده باشید بدون هیچ مشکلی دایرکتوری web توی پوشه پروژتون ایجاد میشه.حالا میتونید پروژتون رو روی مرورگر اجرا کنیدflutter run -d webامیدوارم این مقاله به کارتون بیاد. موفق باشید.من چیزهای زیاد از فلاتر توی کانالم میزارم میتونید من رو از اونجا دنبال کنید.کانال من</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Sat, 14 Sep 2019 17:09:09 +0430</pubDate>
            </item>
                    <item>
                <title>نوار ابزار متحرک یا Collapsing Toolbar در فلاتر (Flutter)</title>
                <link>https://virgool.io/@resfandiari/%D9%86%D9%88%D8%A7%D8%B1-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1-%D9%85%D8%AA%D8%AD%D8%B1%DA%A9-%DB%8C%D8%A7-collapsing-toolbar-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-flutter-hsuao43hjxuv</link>
                <description>سلام به همه . چند وقتی هست با فلاتر اشنا شدم و سعی دارم توی این فریم ورک بهتر بشم و هدفم این هست با توجه به کم بودن منابع فارسی ، توی این مسیر به هر مشکلی که برخوردم راه حلشو به اشتراک بزارم.خوب اگر توسعه دهنده اندروید باشید میدونید که طراحی لایه های واکنش پذیر نسبت به اسکرول کار خیلی اسونیه و به راحتی میشه با استفاده از لیوت هایی که اونجا موجود هست انجامش داد ولی توی فلتر طراحی چنین چیزی یه مقداری پیچیده تره (برعکس تمام چیزاش که به نسبت راحت تره ?).نتیجه کاری که من انجام میدم این میشهبه طور کامل لایه اصلی توی فلتر برای چنین کاری NestedScrollView هست و تمام لایه ها برای واکنش پذیر  نسبت به اسکرول باید درون همین طراحی بشن .این ویجت یک SliverAppBar دریافت میکنه و اون لایه میانی بین Toolbar و Tabbar یعنی دقیقا همون لایه واکنش پذیر توی همین قرار داده میشه var flexibleSpaceWidget = new SliverAppBar(
      expandedHeight: 200.0,
      pinned: true,
      flexibleSpace: FlexibleSpaceBar(
          centerTitle: true,
          title: Text(&amp;quotDeveloper Libs&amp;quot,
              style: TextStyle(
                color: Colors.white,
                fontSize: 16.0,
              )),
          background: Image.asset(
            &amp;quotassets/logo.png&amp;quot,
          )),
      actions: &lt;Widget&gt;[
        new Padding(
          padding: EdgeInsets.all(5.0),
          child: _buildActions(),
        ),
      ],
    );همینجور که میبنید این Appbar یک اکشن دریافت میکنه این دقیقا همون دکمه دایره شکل (FAB ) هست که وقتی Tabbar به سمت بالا اسکرول میشه ظاهر میشهWidget _buildActions() {
    Widget profile = new GestureDetector(
      onTap: () =&gt; showProfile&#40;&#41;,
      child: new Container(
        height: 30.0,
        width: 45.0,
        decoration: new BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.grey,
          image: new DecorationImage(
            image: new ExactAssetImage(&amp;quotassets/logo.png&amp;quot),
            fit: BoxFit.cover,
          ),
          border: Border.all(color: Colors.black, width: 2.0),
        ),
      ),
    );

    double scale;
    if (scrollController.hasClients) {
      scale = scrollController.offset / 300;
      scale = scale * 2;
      if (scale &gt; 1) {
        scale = 1.0;
      }
    } else {
      scale = 0.0;
    }

    return new Transform(
      transform: new Matrix4.identity()..scale(scale, scale),
      alignment: Alignment.center,
      child: profile,
    );
 }خوب حالا برای اینکه بتونیم tab رو هم به قسمت واکنش پذیرمون اظافه کنیم باید از پارامتر delegate در sliver header استفاده کنیم و کار تمومه .من تمام کد رو اینجا میزارم import &#039;package:flutter/material.dart&#039;;
import &#039;package:flutter_collapsing_toolbar/tab_screen.dart&#039;;

class CollapsingTab extends StatefulWidget {
  @override
  _CollapsingTabState createState() =&gt; new _CollapsingTabState();
}

class _CollapsingTabState extends State&lt;CollapsingTab&gt; {
  ScrollController scrollController;

  Widget _buildActions() {
    Widget profile = new GestureDetector(
      onTap: () =&gt; showProfile&#40;&#41;,
      child: new Container(
        height: 30.0,
        width: 45.0,
        decoration: new BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.grey,
          image: new DecorationImage(
            image: new ExactAssetImage(&amp;quotassets/logo.png&amp;quot),
            fit: BoxFit.cover,
          ),
          border: Border.all(color: Colors.black, width: 2.0),
        ),
      ),
    );

    double scale;
    if (scrollController.hasClients) {
      scale = scrollController.offset / 300;
      scale = scale * 2;
      if (scale &gt; 1) {
        scale = 1.0;
      }
    } else {
      scale = 0.0;
    }

    return new Transform(
      transform: new Matrix4.identity()..scale(scale, scale),
      alignment: Alignment.center,
      child: profile,
    );
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    scrollController = new ScrollController();
    scrollController.addListener(() =&gt; setState(() {}));
  }

  @override
  Widget build(BuildContext context) {

    var flexibleSpaceWidget = new SliverAppBar(
      expandedHeight: 200.0,
      pinned: true,
      flexibleSpace: FlexibleSpaceBar(
          centerTitle: true,
          title: Text(&amp;quotDeveloper Libs&amp;quot,
              style: TextStyle(
                color: Colors.white,
                fontSize: 16.0,
              )),
          background: Image.asset(
            &amp;quotassets/logo.png&amp;quot,
          )),
      actions: &lt;Widget&gt;[
        new Padding(
          padding: EdgeInsets.all(5.0),
          child: _buildActions(),
        ),
      ],
    );

    return Scaffold(
      body: new DefaultTabController(
        length: 3,
        child: NestedScrollView(
          controller: scrollController,
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return &lt;Widget&gt;[
              flexibleSpaceWidget,
              SliverPersistentHeader(
                delegate: _SliverAppBarDelegate(
                  TabBar(
                    labelColor: Colors.black87,
                    unselectedLabelColor: Colors.black26,
                    tabs: [
                      Tab(
                        icon: Icon(Icons.account_box),
                        text: &amp;quotDetail&amp;quot,
                      ),
                      Tab(icon: Icon(Icons.add_location), text: &amp;quotAddress&amp;quot),
                      Tab(icon: Icon(Icons.monetization_on), text: &amp;quotEarning&amp;quot),
                    ],
                  ),
                ),
                pinned: true,
              ),
            ];
          },
          body: new TabBarView(
            children: &lt;Widget&gt;[
              new TabScreen(&amp;quotDetail&amp;quot),
              new TabScreen(&amp;quotAddress&amp;quot),
              new TabScreen(&amp;quotEarning&amp;quot),
            ],
          ),
        ),
      ),
    );
  }

  showProfile&#40;&#41; {
    Navigator.pushNamed(context, &#039;/profile&#039;);
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  final TabBar _tabBar;

  _SliverAppBarDelegate(this._tabBar);

  @override
  double get minExtent =&gt; _tabBar.preferredSize.height;

  @override
  double get maxExtent =&gt; _tabBar.preferredSize.height;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new Container(
      child: _tabBar,
    );
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
  }
}خوب امیدوارم کارتون راه افتاده باشه :) بدرودمن چیزهای زیاد از فلاتر توی کانالم میزارم میتونید من رو از اونجا دنبال کنید.کانال من</description>
                <category>رضا اسفندیاری</category>
                <author>رضا اسفندیاری</author>
                <pubDate>Mon, 19 Aug 2019 14:10:08 +0430</pubDate>
            </item>
            </channel>
</rss>