فلاتر

دیباگ رابطه کاربری با استفاده از Flutter Inspector

به عنوان یک برنامه نویس موبایل تا به حال با مشکلات مختلفی در دیباگ کردن رابط کاربری احتمالا برخورد کرده اید, به خصوص در اپلیکیشن های اندروید که تنوع گوشی های هوشمند بسیار بیشتر هستند.

در این پست قصد داریم با ابزاری در فلاتر آشنا شویم به نام Flutter Inspector که با کمک آن به بررسی مشکلات طراحی و رابط کاربری میپردازیم تا نواقص موجود را برطرف کنیم.

مشکلاتی که درباره آنها در طراحی رابط کاربری فلاتر صحبت میکنیم به دلایل مختلفی ممکن است رخ دهد مثل زمانی که اندازه ارتفاع به درستی در viewport  مشخص نمیشود.

به طور کلی مشکلات طراحی در Flutter به دو بخش عمده overflow و renderbox تقسیم میشود.

برای حل این مشکلات خوشبختانه DevTool بخشی به نام Flutter Inspector دارد که میتوانید علت وجود خطا و نحوه حل آن را مشاهده کنید.

Flutter Inspector چیست؟

Flutter Inspector ابزاری است برای کاوش و مصور سازی ویجت های استفاده شده در یک صفحه از برنامه همچنین بهترین گزینه برای بررسی ریزه کاری های لایه برنامه نیز می باشد.

با کمک این قابلیت میتونید خیلی راحت تاثیر Flex در یک Row را مشاهده کنید یا متوجه بشوید که چرا یک ویجت شما نمایش داده نمیشود.

در این آموزش روی بخش های زیر تمرکز میکنیم:

  • درخت جزییات: به شما این امکان را میدهد تا ویژگی های هر ویجت را بررسی کنید. میتونید سایز واقعی یک ویجت را مشاده کنید و ببینید که چگونه از طرف ویجت های دیگر محدود شده است.
  • کاوش در لایه: به شما این امکان را میدهد تا درباره ویجت هایی مثل Row, Column و… به همراه فرزندان آنها تصویر سازی کنید.

برای شروع کار در ابتدا نیاز هست که Dart DevTools را اجرا کنید و بعد از آن Inspector  اولین ابزاری است که مشاهده خواهید کرد.

دیباگ رابط کاربری فلاتر

کار خودمون رو با پروژه دمود شروع میکنیم و سه مشکل طراحی آن را قصد داریم حل کنیم.

برای رفع مشکلات طراحی چند مرحله وجود داره که به ترتیب باید انجام دهید.

  1. پیام خطا را در بخش کنسول بخوانید تا نوع خطا و ویجت مورد نظر را تشخیص دهید.
  2. Layout Explorer را باز کنید و ویجت مورد نظر را پیدا کنید.
  3. اندازه و محدودیت هایی که باعث خطا شده را بررسی کنید همچنین به وسیله جزییات درخت ریشه ویجت را پیدا کنید.
  4. به بخش کد ها برگشته و مشکل را رفع کنید.

پروژه جدید فلاتر ایجاد کنید و کدهای زیر را در فایل main جایگزین کنید.

import 'package:flutter/material.dart';

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

class MenuItem extends StatelessWidget {
  const MenuItem(this.icon, this.itemText);
  final String icon;
  final String itemText;
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: Text(
        icon,
        style: TextStyle(
          fontSize: 30.0,
        ),
      ),
      title: Text(itemText),
    );
  }
}

class Menu extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Menu Demo'),
        ),
        body: Padding(
          padding: EdgeInsets.all(20.0),
          child: Column(
            children: [
              // Modify code here
              Example1(),
            ],
          ),
        ),
      ),
    );
  }
}

// Problem 1: Overflow error
class Example1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(bottom: 30.0),
      child: Row(
        children: [
          Text(
            'Explore the restaurant\'s delicious menu items below!',
            style: TextStyle(
              fontSize: 18.0,
            ),
          ),
        ],
      ),
    );
  }
}

// Problem 2: Viewport was given unbounded height error
class Example2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        MenuItem('?', 'Burger'),
        MenuItem('?', 'Hot Dog'),
        MenuItem('?', 'Fries'),
        MenuItem('?', 'Soda'),
        MenuItem('?', 'Ice Cream'),
      ],
    );
  }
}

// Problem 3: Invisible VerticalDivider
class Example3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        RaisedButton(
          onPressed: () {
            print('Pickup button pressed.');
          },
          child: Text(
            'Pickup',
          ),
        ),
        // This widget is not shown on screen initially.
        VerticalDivider(
          width: 20.0,
          thickness: 5.0,
        ),
        RaisedButton(
          onPressed: () {
            print('Delivery button pressed.');
          },
          child: Text(
            'Delivery',
          ),
        )
      ],
    );
  }
}

برنامه را اجرا کنید و Dart DevTools را باز کنید.

خطای Overflow

وقتی برنامه را اجرا میکنید با تصویر زیر روبرو میشوید که یک جعبه سیاه و زرد را به عنوان خطای برنامه میبینید.

این بدان معنی است که یک خطای overflow داریم.

برای حل مشکل متن خطا را در کنسول بررسی کنید.

دریافت موقعیت کاربر در Flutter

اول از همه ویجتی که باعث این خطا شده است را پیدا کنید. در اینجا همانطور که میبینید ویجت Row در خط 54 فایل main باعث این اتفاق است.

بخش Layout Explorer را باز کنید.

روی Row کلیک کنید و میبینید که یک پیغام هشدار نمایش میدهد و اطلاع میده که اندازه عرض ویجت Text برابر width = 447 است درحالی که عرض Row برابر width=335 است.

شما نیاز دارید که حداکثر اندازه Text را برابر اندازه Row قرار دهید.

برای این کار میتونید مقدار flex را مساوی 1 قرار دهید یا Text را درون ویجت Expanded اضافه کنید.

خطای ارتفاع نامحدود

برای بررسی مثال بعدی ویجت Example2() را داخل یک Column قرار دهید و برنامه را اجرا کنید.

Column(
  children: [
    // Modify code here
    Example2(),
  ],
)

بعد از اجرا متوجه میشوید هیچ چیزی نمایش داده نمیشود و صفحه سفید خالی هست درحالی که یک لیست برای نمایش داریم.

با بررسی کنسول میبینیم که خطا در خط 72 و ویجت ListView  رخ داده است.

علت هم نوشته شده: Vertical viewport was given unbounded height

دوباره وارد Layout Explorer می شویم در اینجا هم میبینیم که صفحه هیچ اطلاعاتی نمایش نمیدهد پس به مرحله بعد میرویم!

از درخت جزییات Details Tree اندازه و محدودیت ها را بررسی کنید.

در این قسمت روی ListView و سپس renderObject کلیک کنید تا اطلاعات بیشتری از آن مشاهده کنید.

در قسمت نارنجی رنگ نوشته شده که لیست ویو اندازه مشخصی ندارد و همین علت نمایش ندادن آن است.

در بخش شماره دو هم ارتفاع constraints بینهایت قرار داده شده است.

به کد های خودتون برگردید و به این شکل مشکل را رفع کنید:

class Example2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: ListView(
        ...
      ),
    );
  }
}

توجه داشته باشید قرار گرفتن هر ویجت درون Expanded باعث میشود که ارتفاع آن به اندازه ارتفاع ویجت والد آن باشد.

خطای نمایش ندادن VerticalDivider

حالا ویجت Example3() را جایگزین قبلی کنید و برنامه را اجرا کنید.

در این کد ما یک VerticalDivider در بین دو دکمه داریم اما در حال حاضر چیزی نمایش داده نمیشود و فقط دو دکمه میبینم.

در این حالت خطایی هم در بخش کنسول نمایش داده نشده است.

وارد Layout Explorer شوید و تصویر زیر را مشاده کنید.

وقتی که روی VerticalDivider کلیک کنید در سمت راست میبینید که عرض و ارتفاع بصورت unconstrained است.

همچنین ارتفاع هم مقدار 0 می باشد و دلیل نمایش ندادن آن نیز همین است.

قرار دادن VerticalDivider درون ویجت Expanded  مشکل را حل نمیکند.

گزینه بعدی که باید امتحان کنیم این است که اندازه ارتفاع VerticalDivider را برابر ارتفاع دکمه ها قرار دهیم.

طبق تصویر زیر اولین renderObject  زیر VerticalDivider را باز کنید.

در شماره یک میبینید که هیچ عرض و ارتفاعی وجود ندارد که مقدار آن با مقدار نمایش داده شده در Layout Explorer برابر باشد اما در additionalConstraints عرض برابر 20 است همانطور که انتظار داشتیم اما همچنان ارتفاع صفر است.

وقتی renderObject  را در Row باز میکنید میبینیم که هیچ محدودیت ارتفاعی ندارد.

چرا این اتفاق افتاد؟ به این دلیل که:

ویجت Column  به Row اطلاع میده که هر ارتفاعی میخواهی انتخاب کن.

Row هم به VerticalDivider اطلاع میده که هر مقدار اندازه عرض میخواهی انتخاب کن چون Column گفته من ارتفاع آن را انتخاب کنم بنابراین تو هم ارتفاع خودت را انتخاب کن.

برای VerticalDivider عرض قرار داده شده بود 20بنابراین اندازه عرض مشکلی ندارد و وقتی ارتفاع قرار داده نشده است به شکل پیش فرض مقدار 0 انتخاب شده است.

برای اینکه VerticalDivider  اندازه ارتفاع آن برابر اندازه ارتفاع Row باشد باید برای Row ارتفاع تعیین کرد به شکل زیر:

class Example3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 50.0,
      child: Row(
        ...
      ),
    );
  }
}

حالا تمام کدهای دیباگ شده را کنار هم میتوانید قرار دهید.

Column(
  children: [
    // Modify code here
    Example1(),
    Example2(),
    Example3(),
  ],
)
Hesam

Recent Posts

گیتهاب اکشن چیست؟ آموزش استفاده از گیتهاب اکشن در برنامه نویسی فلاتر

گیتهاب اکشن GitHub Actions یکی از ابزارهای گیتهاب است که به شما کمک می‌کنه تا…

2 هفته ago

آموزش افزایش سرعت اجرای وب اپلیکیشن های فلاتر

اگر یک برنامه نویس فلاتر هستید و با از نسخه وب اپلیکیشن پروژتون استفاده میکنید…

1 ماه ago

آموزش جامع انتشار اپلیکیشن اندروید و فلاتر در فروشگاه گوگل پلی Google play

به عنوان یک برنامه نویس فلاتر یا اندروید بعد از اتمام پروسه طراحی اپلیکیشن نیاز…

2 ماه ago

دانلود سورس کد رابط کاربری اپلیکیشن فلاتر پروژه پادکست

طراحی رابط کاربری اپلیکیشن پادکست خود را با استفاده از این کیت توسعه UI/UX فلاتر…

3 ماه ago

فایربیس چیست؟ معرفی سرویس ابری Firebase و کاربردهای آن

فایربیس، پلتفرمی قدرتمند از شرکت گوگل برای توسعه و مدیریت برنامه‌های موبایل و وب است.…

3 ماه ago

آموزش پیاده سازی Method Channel در فلاتر + فیلم

فلاتر یک فریم ورک برنامه نویسی چندسکویی است که این امکان را برای برنامه نویس…

3 ماه ago