فلاتر وب - mouse effect (قسمت دوم)

سلام، تو این مقاله قصد داریم صحبت راجب mouseEvent رو کامل کنیم که ادامه مقاله قبلی هستش.
پس اگر هنوز نخوندینش پیشنها میکنم حتما یه نگاهی بهش بندازین.

https://virgool.io/flutter-community/%D9%81%D9%84%D8%A7%D8%AA%D8%B1-%D9%88%D8%A8-%DA%86%D8%B7%D9%88%D8%B1-%D9%85%D9%88%D8%B3-%D8%AA%D8%B1%DA%A9%D8%B1-%D8%A8%D8%B3%D8%A7%D8%B2%DB%8C%D9%85-utjvhyszpsue



بعضی از سایت ها با استفاده از جاوا اسکریپت effect های جالبی پیاده‌سازی می کنند؛ یکی از نمونه های خوبش سایت samsaraubud هست. مینی پروژه‌ای که قصد پیاده‌سازیش رو داریم شباهت زیادی با ترکر و هاور موس این سایت داره. درمورد نحوه اجرای موس ترکر توی مقاله قبلی حرف زدیم و امروز یک هاور متفاوت رو اجرا می‌کنیم.

توی تصویر زیر هر دو مورد مشخص هستن.

samsaraubud سایت
samsaraubud سایت




تو مقاله قبلی، تا ساخت موس افکت ترکر پیش رفتیم؛ که هر جایی موس رو هاور می کردیم یک کانتینر دنبالش می‌کرد.

نتیجه مینی پروژه قبلی رو توی تصویر زیر می‌تونید ببینید.

مینی پروژه مقاله قبل
مینی پروژه مقاله قبل

اول از همه، رنگ کانتینر (Container) رو پاک میکنیم تا بی رنگ باشه و به جاش بهش بوردر (border) با رنگ قرمز میدیم و رنگ بکگراند اصلی رو هم به مشکی تغییر میدیم.

decoration: BoxDecoration(
     shape:  BoxShape.circle,
     border: Border.all(
           color: Colors.red,
           width:  1,
      ),
),

ولی تو کدی که نوشتیم، یک مشکل کوچیک وجود داشت؛ وقتی موس رو به کناره‌ها نزدیک می‌کردیم، دیگه cursor موس وسط کانتینر قرار نمی‌گرفت و این باعث می‌شد برای پیاده سازی هاور به مشکل بخوریم.

پس اول از همه این مشکل رو برطرف کنیم، دقیقا مثل کاری که برای کل صفحه انجام دادیم، اینبار باید همون نسبت رو با شعاع کانتینر قرار بدیم و مقدارش رو از یک کم کنیم و درنهایت با خودش جمع کنیم که cursor رو دقیقا وسط کانتینر قرار بده.

ما اینکار رو یکبار باید برای عرض صفحه (X) و یکبار برای ارتفاع (Y) صفحه انجام بدیم، پس هر دوتاشون رو کنار هم میزاریم و برای هر کدوم یک متغییر موقت جدید به اسم های xTempPadding و yTempPadding می سازیم.

کد نهایی به شکل زیر میشه.

pointerConverter() {
   double xTemp = x / screenWidth;
   double yTemp = y / screenHeight;
   double xTempPadding = xTemp - (1 - xTemp);
   double yTempPadding = yTemp - (1 - yTemp);
   setState(() {
          x1 = xTempPadding + (xTempPadding / 15);
          y1 = yTempPadding + (yTempPadding / 15);
    });
}



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

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

ما تمام کد آیتم هایی که داریم داخل یک MouseRegion قرار داره که برای اضافه کردن آیکون نیازه یک Stack اضافه کنیم و آیکون رو داخلش بزاریم، به این دلیل که نیازه جایی که آیکون قرار داره رو بدیم تا بتونیم برای هاور در نظر بگیریم راهی نداریم جز اینکه داخل Align قرار بدیمش و به شکل دستی جایگاهش رو توی صفحه مشخص کنیم.

Stack(
 children: [
    Align(
        alignment: const Alignment(-0.9, -0.9),
         child: const Icon(Icons.menu, size: 40, color: Colors.red),
    ),
    MouseRegion(
     onHover: _updateLocation,
     child: Align(
        alignment: Alignment(x1, y1),
        child: Container(
            width: 40,
            height: 40,
            decoration: BoxDecoration(
                shape:  BoxShape.circle,
                border: Border.all(
                    color: Colors.red,
                    width: 1, 
               ),
             ),
          ),
        ),
      ),
   ],
),

داخل ویجت Align به شکل دستی Alignment(-0.9, -0.9) داده شده، پس ما میدونیم که دقیقا آیکون منو ما کجای صفحه قرار داره و دقیقا پوزیشن موس هم داریم، حالا یه شرط اضافه میکنیم که اگر وارد محدوده ی آیکون شدیم برامون یک متغییر رو true کنه.

یک متغییر جدید به اسم menuHovered می سازیم که جنسش bool باشه و اگر موس وارد محدوده ی آیکون شد او رو true میکنیم، برای اینکار کد زیر رو به pointerConverter ای که قرار داده بودیم اضافه میکنیم.

if (-0.9 < xTempPadding &&  xTempPadding < -0.8 &&  -0.9 < yTempPadding && yTempPadding < -0.8) {
    setState(() {
      menuHovered = true;
    }); 
  } else {
     setState(() { 
          menuHovered = false;
     });
}

تو این مرحله ما میدونیم که کجا وارد محدوده ی آیکون می شیم و کجا از اون محدوده خارج میشیم، پس با کمک همین متغییر ظاهر کانتینر رو عوض میکنیم.
برای تغییر دادن شکل کانتینر:

shape: menuHovered ? BoxShape.rectangle : BoxShape.circle,

و برای تغییر دادن قطر بوردر کانتینر:

border: Border.all(
     color: Colors.red,
     width: menuHovered ? 2.5 : 1,
)


با یکسری تغییرات کوچیک می تونیم مینی پروژه خودمون رو به samsaraubud نزدیک تر کنیم، اول از همه نیازه که به بکگراند یک تصویر اضافه بکنیم که من یک تصویر از unsplash انتخاب کردم


و در نهایت به جای تغییر دادن shape موقع هاور شدن، بوردر رو حذف کنیم و به جاش کانتینر رو بزرگتر و رنگش رو هم تغییر بدیم.

Container(
   width: menuHovered ? 60 : 40,
   height: menuHovered ? 60 : 40,
   decoration: BoxDecoration(
        color: menuHovered  ? Colors.blueGrey.withOpacity(0.7) : Colors.transparent, 
        shape: BoxShape.circle,
        border: Border.all(
             color: menuHovered ? Colors.transparent : Colors.red,
         ),
     ),
),


که نتیجه این تغییرات بالا و اضافه کردن تصویر میشه ویدیو زیر:

الان لحظه هاور شدن روی آیکون کانتینر ما خیلی سریع رنگ و اندازش تغییر میکنه که یجورایی تو ذوق میزنه، پس خیلی عالی میشه اگر یک انیمیشن ساده بهش اضافه کنیم که لحظه ی تغییر با انیمیشن باشه.

برای اینکار کافیه جای Container رو با AnimatedContainer عوض کنیم و یک زمان به این ویجت بدیم که من 100 میلی ثانیه زمان رو برای این تغییر مناسب می دونم.

AnimatedContainer(
   duration: const Duration(milliseconds: 100),
   width: menuHovered ? 60 : 40,
   height: menuHovered ? 60 : 40,
   decoration: BoxDecoration(
        color: menuHovered  ? Colors.blueGrey.withOpacity(0.7) : Colors.transparent, 
        shape: BoxShape.circle,
        border: Border.all(
             color: menuHovered ? Colors.transparent : Colors.red,
         ),
     ),
),

ممنون که تا آخر مقاله همراه من بودید، اگر پیشنهاد یا انتقادی داشتید باعث افتخار اگر برای من کامنت کنید یا در لینکدین به من پیام بدین، سورس کد این پروژه روی گیتهاب من هست که با لینک زیر میتونید روی برنچ "part-2" از این مینی پروژه استفاده کنید.