<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های Hossein Sohan</title><link>https://virgool.ir/feed/@hossein.sohan</link><description></description><language>fa</language><pubDate>2026-11-11 09:11:39</pubDate><image><url>https://files.virgool.ir/upload/users/144619/avatar/avatar.png</url><title>Hossein Sohan</title><link>https://virgool.ir/@hossein.sohan</link></image><item><title>خطای &#34;سرریز پایین صفحه&#34; ناشی از صفحه کلید در فلاتر Bottom Overflowed</title><link>https://virgool.ir/flutter-community/خطای-سرریز-پایین-صفحه-ناشی-از-صفحه-کلید-در-فلاتر-bottom-overflowed-vdq3urjhgd5e</link><description>سلام! خوشحالم که دوباره با مقاله جدیدی درباره Flutter، با شما هستم. اگر تا به حال با TextFormFields در Flutter کار کرده باشید، مطمئن هستم که نوارهای زرد / سیاه روی پایین صفحه نمایش خود دیده اید، درست مانند تصویر زیر. در این مقاله ، ما در مورد بهترین راه حل برای جلوگیری از خطای سرریز پایین صفحه (Bottom Overflough) هنگام ظاهر شدن صفحه کلید صحبت خواهیم کرد.همانطور که مشاهده می کنید ویجت ها باید به صورت عمودی نمایش داده شوند، به همین دلیل به عنوان والد به یک ویجت ستون یا همان column احتیاج داریم. رنگ پس زمینه و فاصله چپ / راست (padding) را فراموش نکنید! برای سفارشی کردن پس زمینه به یک Container با خاصیت decotation مانند کد زیر نیاز داریم. برای اعتبارسنجی قسمت فرم متن ، به یک ویجت به نام Form نیاز داریم که باید یک key برای آن تعریف کنیم.final _formKey = new GlobalKey&lt;FormState&gt;(); // outside the build() method &#xA;&#xA;...@override&#xA;&#xA;Widget build(BuildContext context) {&#xA;  return Scaffold(&#xA;      body: Container(&#xA;    color: Color.fromRGBO(36, 43, 47, 1),&#xA;    padding: const EdgeInsets.symmetric(horizontal: 43.0),&#xA;    child: Form(&#xA;      key: _formKey,&#xA;      child: Container(&#xA;        alignment: Alignment.center,&#xA;        child: Column(&#xA;          mainAxisAlignment: MainAxisAlignment.center,&#xA;          children: &lt;Widget&gt;[&#xA;            _buildFirstName(),&#xA;            _buildLastName(),&#xA;            _buildEmail(),&#xA;            _buildPassword(),&#xA;            _buildConfirmPassword(),&#xA;            _buildSignUpButton(context)&#xA;          ],&#xA;        ),&#xA;      ),&#xA;    ),&#xA;  ));&#xA;}اول یک decoration برای هر یک از tetxfieldها درست کنیمInputDecoration _buildInputDecoration(String hint, String iconPath) {&#xA;  return InputDecoration(&#xA;      focusedBorder: UnderlineInputBorder(&#xA;          borderSide: BorderSide(color: Color.fromRGBO(252, 252, 252, 1))),&#xA;      hintText: hint,&#xA;      enabledBorder: UnderlineInputBorder(&#xA;          borderSide: BorderSide(color: Color.fromRGBO(151, 151, 151, 1))),&#xA;      hintStyle: TextStyle(color: Color.fromRGBO(252, 252, 252, 1)),&#xA;      icon: iconPath != &#39;&#39; ? Image.asset(iconPath) : null,&#xA;      errorStyle: TextStyle(color: Color.fromRGBO(248, 218, 87, 1)),&#xA;      errorBorder: UnderlineInputBorder(&#xA;          borderSide: BorderSide(color:  Color.fromRGBO(248, 218, 87, 1))),&#xA;      focusedErrorBorder: UnderlineInputBorder(&#xA;          borderSide: BorderSide(color:  Color.fromRGBO(248, 218, 87, 1))));&#xA;}و در ادامه هر کدام از ویجت های موجد در form را جداگانه تعریف می کنیم._buildFirstName()Widget _buildFirstName() {&#xA;  return TextFormField(&#xA;    validator: (value) =&gt;&#xA;        value.isEmpty ? &#34;First name cannot be empty&#34; : null,&#xA;    style: TextStyle(&#xA;        color: Color.fromRGBO(252, 252, 252, 1), fontFamily: &#39;RadikalLight&#39;),&#xA;    decoration:&#xA;        _buildInputDecoration(&#34;First name&#34;, &#39;assets/ic_worker.png&#39;),&#xA;  );&#xA;}_buildLastName()Widget _buildLastName() {&#xA;  return Container(&#xA;      margin: const EdgeInsets.only(left: 40),&#xA;      child: TextFormField(&#xA;        validator: (value) =&gt;&#xA;            value.isEmpty ? &#34;Last name cannot be empty&#34; : null,&#xA;        style: TextStyle(&#xA;            color: Color.fromRGBO(252, 252, 252, 1), fontFamily: &#39;RadikalLight&#39;),&#xA;        decoration: _buildInputDecoration(&#34;Last name&#34;, &#39;&#39;),&#xA;      ));&#xA;}_buildEmail()Widget _buildEmail() {&#xA;  return TextFormField(&#xA;    validator: (value) =&gt; !isEmail(value) ? &#34;Sorry, we do not recognize this email address&#34; : null,&#xA;    style: TextStyle(&#xA;        color: Color.fromRGBO(252, 252, 252, 1), fontFamily: &#39;RadikalLight&#39;),&#xA;    decoration: _buildInputDecoration(&#34;Email&#34;, &#39;assets/ic_email.png&#39;),&#xA;  );&#xA;}_buildPassword()final _passwordController = TextEditingController(); //this line is outside the build() method &#xA;...Widget _buildPassword() {&#xA;  return TextFormField(&#xA;    obscureText: true,&#xA;    controller: _passwordController,&#xA;    validator: (value) =&gt;&#xA;        value.length &lt;= 6 ? &#34;Password must be 6 or more characters in length&#34; : null,&#xA;    style: TextStyle(&#xA;        color: Color.fromRGBO(252, 252, 252, 1), fontFamily: &#39;RadikalLight&#39;),&#xA;    decoration:&#xA;        _buildInputDecoration(&#34;Password&#34;, &#39;assets/ic_password.png&#39;),&#xA;  );&#xA;}bool isEmail(String value) {&#xA;  String regex =&#xA;      r&#39;^(([^&lt;&gt;()[\]\\.,;:\s@\&#34;]+(\.[^&lt;&gt;()[\]\\.,;:\s@\&#34;]+)*)|(\&#34;.+\&#34;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$&#39;;&#xA;&#xA;  RegExp regExp = new RegExp(regex);&#xA;&#xA;  return value.isNotEmpty &amp;&amp; regExp.hasMatch(value);&#xA;}_buildConfirmPassword()Widget _buildConfirmPassword() {&#xA;  return Container(&#xA;      margin: const EdgeInsets.only(left: 40),&#xA;      child: TextFormField(&#xA;        obscureText: true,&#xA;        validator: (value) =&gt; value.isEmpty ||&#xA;                (value.isNotEmpty &amp;&amp; value != _passwordController.text)&#xA;            ? &#34;Must match the previous entry&#34;&#xA;            : null,&#xA;        style: TextStyle(&#xA;            color: Color.fromRGBO(252, 252, 252, 1), fontFamily: &#39;RadikalLight&#39;),&#xA;        decoration: _buildInputDecoration(&#34;Confirm password&#34;, &#39;&#39;),&#xA;      ));&#xA;}_buildSignUpButton().Widget _buildSignUpButton(BuildContext context) {&#xA;  return Container(&#xA;    margin: const EdgeInsets.only(top: 43.0),&#xA;    width: MediaQuery.of(context).size.width * 0.62,&#xA;    child: RaisedButton(&#xA;      child: const Text(&#xA;        &#34;Sign Up&#34;,&#xA;        style: TextStyle(&#xA;            color: Color.fromRGBO(40, 48, 52, 1),&#xA;            fontFamily: &#39;RadikalMedium&#39;,&#xA;            fontSize: 14),&#xA;      ),&#xA;      color: Colors.white,&#xA;      elevation: 4.0,&#xA;      onPressed: () {&#xA;        _validateAndSubmit();&#xA;      },&#xA;    ),&#xA;  );&#xA;}خب دوستان کد رو روی صفحه کوچک تست کنید.اگر برنامه را اجرا کنید مشکلی وجود ندارد &#xA;مشکل زمانی هست که کیبورد فعال شود. مانند شکل بالا!!!یک راه حل سریع این است که ویجت های داخل Scaffold را مسدود کنید تا در زمان باز شدن صفحه کلید تغییر اندازه دهند اما از این طریق برخی ویجت ها توسط صفحه کلید مبهم می شوند. ما می توانیم این کار را با استفاده از ویژگی resizeToAvoidBottomInset در ویجت Scaffold انجام دهیم. روش ساخت به شرح زیر است:@override&#xA;Widget build(BuildContext context) {&#xA;  return Scaffold(&#xA;      resizeToAvoidBottomInset: false,   //new line&#xA;      body: Container(&#xA;        color: Color.fromRGBO(36, 43, 47, 1),&#xA;        padding: const EdgeInsets.symmetric(horizontal: 43.0),&#xA;        child: Form(&#xA;          key: _formKey,&#xA;          child: Container(&#xA;            alignment: Alignment.center,&#xA;            child: Column(&#xA;              mainAxisAlignment: MainAxisAlignment.center,&#xA;              children: &lt;Widget&gt;[&#xA;                _buildFirstName(),&#xA;                _buildLastName(),&#xA;                _buildEmail(),&#xA;                _buildPassword(),&#xA;                _buildConfirmPassword(),&#xA;                _buildSignUpButton(context)&#xA;              ],&#xA;            ),&#xA;          ),&#xA;        ),&#xA;      ));&#xA;}راه حل دیگر این است که ویجت Column را در یک ویجت قابل پیمایش قرار دهید. ویجت قابل پیمایش ساخته شده توسط Flutter که به خوبی کار می کند SingleChildScrollView است. این بهترین راه حل برای جلوگیری از خطای &#34;Bottom overflough&#34; هنگام باز شدن صفحه کلید است.@override&#xA;Widget build(BuildContext context) {&#xA;  return Scaffold(&#xA;      body: Container(&#xA;    color: Color.fromRGBO(36, 43, 47, 1),&#xA;    padding: const EdgeInsets.symmetric(horizontal: 43.0),&#xA;    child: Form(&#xA;      key: _formKey,&#xA;      child: Container(&#xA;        alignment: Alignment.center,&#xA;        child: SingleChildScrollView(    // new line&#xA;          child: Column(&#xA;            mainAxisAlignment: MainAxisAlignment.center,&#xA;            children: &lt;Widget&gt;[&#xA;              _buildFirstName(),&#xA;              _buildLastName(),&#xA;              _buildEmail(),&#xA;              _buildPassword(),&#xA;              _buildConfirmPassword(),&#xA;              _buildSignUpButton(context)&#xA;            ],&#xA;          ),&#xA;        ),&#xA;      ),&#xA;    ),&#xA;  ));&#xA;}امیدوارم که این مقاله به شما کمک کند که درک بهتری داشته باشین که چرا صفحه کلید باعث ایجاد خطای &#34;Bottom overflough&#34; می شود ، و همچنین چگونه آن را برطرف کنید.با ما همراه باشید ، مقالات بیشتری درباره Flutter در راه است!ممنون از خواندن!</description><category>Hossein Sohan</category><author>Hossein Sohan</author><pubDate>Wed, 11 Mar 2020 18:51:06 +0330</pubDate></item><item><title>ویجت wrap در #فلاتر (Flutter Wrap Widget)</title><link>https://virgool.ir/flutter-community/ویجت-wrap-در-فلاتر-flutter-wrap-widget-tyosvsgpmfst</link><description>انتقال ویجت های شلوغ به خط بعدیاگر قبلا ویدیو Widget of the Week درباره دسته بندی را ندیده اید، پیشنهاد اول فیلم را تماشا کنید. https://youtu.be/z5iw2SeFx2M بصورت عادی (بیسیک)به طور معمول وقتی می خواهید چندین ویجت را به صورت افقی یا عمودی طراحی کنید می توانید از یک ردیف(Row) یا ستون(Column) استفاده کنید.Row(&#xA;  children: [&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;  ],&#xA;),اما اگر فضای کافی وجود نداشته باشد، محتوای آن بریده می شود و اخطار سرریز زرد و سیاه رنگ را دریافت می کنید.برای حل این مشکل میتوانید بجای Row از ویجت Wrap استفاده کنید.Wrap(&#xA;  children: [&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;  ],&#xA;),ویجت Wrap بصورت پیش فرض ویجت های فرزند خود را بصورت افقی می چیند. اما اگر شما میخواهید بصورت عمودی بچینید، می توانید direction را تغییر بدیدWrap(&#xA;  direction: Axis.vertical,&#xA;  children: [&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;    MyWidget(),&#xA;  ],&#xA;),خب دوستان به پایان این مطلب مفید رسیدیم. امیدوارم از این مطلب خوشتون اومده باشه.منتظر مطالب مفید بعدی باشید.</description><category>Hossein Sohan</category><author>Hossein Sohan</author><pubDate>Thu, 05 Mar 2020 12:17:07 +0330</pubDate></item></channel></rss>