درک حاشیه‌های پنجره در WebView

‫WebView تراز محتوا را بااستفاده از دو درگاه دید مدیریت می‌کند: درگاه دید چیدمان (اندازه صفحه) و درگاه دید بصری (بخشی از صفحه که کاربر واقعاً می‌بیند). درحالی‌که درگاه نمایش چیدمان معمولاً ایستا است، درگاه نمایش تصویری وقتی کاربران زوم‌پیش می‌کنند، پیمایش می‌کنند، یا وقتی عناصر میانای کاربر سیستم (مثل صفحه‌کلید نرم‌افزاری) ظاهر می‌شوند به‌صورت پویا تغییر می‌کند.

سازگاری ویژگی

پشتیبانی «وب‌نما» از حاشیه‌های پنجره درطول زمان تکامل یافته است تا رفتار محتوای وب با انتظارات برنامه Android بومی هماهنگ شود:

Milestone ویژگی اضافه شد حوزه
M136 ‫displayCutout() و systemBars() ازطریق CSS safe-area-insets پشتیبانی می‌کنند. فقط «نمای وب» تمام‌صفحه.
M139 ime() (ویرایشگر روش ورودی، که صفحه‌کلید است) ازطریق تغییر اندازه درگاه دیداری پشتیبانی می‌کند. همه «نمای‌های وب».
M144 ‫displayCutout() و systemBars() پشتیبانی می‌کنند. همه «وب‌نماها» (صرف‌نظر از وضعیت تمام‌صفحه).

برای اطلاعات بیشتر، به WindowInsetsCompat مراجعه کنید.

مکانیک‌های اصلی

«وب‌نما» ازطریق دو سازوکار اصلی از حاشیه‌ها استفاده می‌کند:

  • مناطق امن (displayCutout، systemBars): WebView این ابعاد را ازطریق متغیرهای CSS safe-area-inset-* به محتوای وب ارسال می‌کند. این کار به توسعه‌دهندگان امکان می‌دهد از پنهان شدن عناصر تعاملی خود (مانند نوارهای پیمایش) توسط بریدگی‌ها یا نوارهای وضعیت جلوگیری کنند.

  • تغییر اندازه درگاه دیداری بااستفاده از ویرایشگر روش ورودی (IME): از M139، ویرایشگر روش ورودی (IME) مستقیماً اندازه درگاه دیداری را تغییر می‌دهد. این سازوکار تغییر اندازه نیز براساس تقاطع WebView-Window است. برای مثال، در حالت چندوظیفگی Android، اگر پایین «وب‌نما» ‫۲۰۰ پیکسل پایین‌تر از پایین پنجره باشد، درگاه دیداری ‫۲۰۰ پیکسل کوچک‌تر از اندازه «وب‌نما» است. این تغییر اندازه درگاه دیداری (برای هر دو تقاطع IME و WebView-Window) فقط برای پایین «وب‌نما» اعمال می‌شود. این سازوکار از تغییر اندازه برای هم‌پوشانی چپ، راست، یا بالا پشتیبانی نمی‌کند. این یعنی صفحه‌کلیدهای چسبیده که در این لبه‌ها ظاهر می‌شوند باعث تغییر اندازه درگاه دیداری نمی‌شوند.

قبلاً، درگاه دیداری ثابت می‌ماند و اغلب فیلدهای ورودی را پشت صفحه‌کلید پنهان می‌کرد. با تغییر اندازه درگاه دید، بخش نمایان صفحه به‌طور پیش‌فرض پیمایش‌پذیر می‌شود و تضمین می‌کند که کاربران می‌توانند به محتوای پنهان‌شده دسترسی پیدا کنند.

منطق مرزها و هم‌پوشانی

«نمای وب» فقط زمانی باید مقادیر درج غیرصفر دریافت کند که عناصر واسط کاربر سیستم (نوارها، برش‌های نمایشگر، یا صفحه‌کلید) مستقیماً با محدوده صفحه «نمای وب» هم‌پوشانی داشته باشند. اگر «وب‌نمایی» با این عناصر میانای کاربری هم‌پوشانی نداشته باشد (برای مثال، اگر «وب‌نمایی» در مرکز صفحه‌نمایش قرار داشته باشد و با نوارهای سیستم تماس نداشته باشد)، باید این حاشیه‌ها را به‌عنوان صفر دریافت کند.

برای ملغی کردن این منطق پیش‌فرض و ارائه محتوای وب با ابعاد کامل سیستم بدون درنظر گرفتن هم‌پوشانی، از روش setOnApplyWindowInsetsListener استفاده کنید و شیء windowInsets اصلی و بدون تغییر را از شنونده برگردانید. ارائه ابعاد کامل سیستم می‌تواند با فعال کردن محتوای وب برای تراز شدن با سخت‌افزار دستگاه صرف‌نظر از موقعیت فعلی «وب‌نما»، به تضمین یکپارچگی طراحی کمک کند. این کار باعث می‌شود انتقال همواری هنگام حرکت یا ازهم باز شدن «نمای وب» برای لمس لبه‌های صفحه‌نمایش انجام شود.

کاتلین

ViewCompat.setOnApplyWindowInsetsListener(myWebView) { _, windowInsets ->
    // By returning the original windowInsets object, we override the default
    // behavior that zeroes out system insets (like system bars or display
    // cutouts) when they don't directly overlap the WebView's screen bounds.
    windowInsets
}

جاوا

ViewCompat.setOnApplyWindowInsetsListener(myWebView, (v, windowInsets) -> {
    // By returning the original windowInsets object, we override the default
    // behavior that zeroes out system insets (like system bars or display
    // cutouts) when they don't directly overlap the WebView's screen bounds.
    return windowInsets;
});

مدیریت رویدادهای تغییر اندازه

ازآنجایی‌که رؤیت‌پذیری صفحه‌کلید اکنون باعث تغییر اندازه درگاه دیداری می‌شود، کد وب ممکن است رویدادهای تغییر اندازه را بیشتر ببیند. توسعه‌دهندگان باید مطمئن شوند که کد آن‌ها با پاک کردن تمرکز عنصر به این رویدادهای تغییر اندازه واکنش نشان نمی‌دهد. انجام این کار باعث ایجاد یک حلقه از دست دادن تمرکز و بستن صفحه‌کلید می‌شود که از ورودی کاربر جلوگیری می‌کند:

  1. کاربر روی عنصر ورودی تمرکز می‌کند.
  2. صفحه‌کلید ظاهر می‌شود و رویداد تغییر اندازه را راه‌اندازی می‌کند.
  3. کد وب‌سایت تمرکز را در پاسخ به تغییر اندازه پاک می‌کند.
  4. صفحه‌کلید پنهان می‌شود زیرا تمرکز ازدست رفت.

برای کاهش این رفتار، شنوندگان سمت وب را بررسی کنید تا مطمئن شوید تغییرات درگاه دید به‌طور ناخواسته باعث راه‌اندازی تابع جاوا اسکریپت blur() یا رفتارهای پاک‌سازی تمرکز نمی‌شود.

پیاده‌سازی مدیریت درج

تنظیمات پیش‌فرض WebView به‌طور خودکار برای اکثر برنامه‌ها کار می‌کند. بااین‌حال، اگر برنامه شما از چیدمان‌های سفارشی استفاده می‌کند (برای مثال، اگر برای جبران نوار وضعیت یا صفحه‌کلید، حاشیه خودتان را اضافه می‌کنید)، می‌توانید از رویکردهای زیر برای بهبود نحوه عملکرد مشترک محتوای وب و رابط کاربری بومی استفاده کنید. اگر واسط کاربر بومی شما براساس WindowInsets به محتویات فضای خالی اضافه می‌کند، باید این حاشیه‌ها را قبل‌از رسیدن به «وب‌نما» به‌درستی مدیریت کنید تا فضای خالی دوبرابر نشود.

فاصله‌گذاری دوگانه وضعیتی است که در آن چیدمان بومی و محتوای وب ابعاد درونی یکسانی را اعمال می‌کنند و درنتیجه فاصله‌گذاری اضافی ایجاد می‌شود. برای مثال، تلفنی با نوار وضعیت ۴۰ پیکسل را تصور کنید. هم نمای بومی و هم «وب‌نما» درون‌بَر ۴۰ پیکسل را می‌بینند. هر دو ۴۰ پیکسل حاشیه اضافه می‌کنند و درنتیجه کاربر در بالا ۸۰ پیکسل فاصله می‌بیند.

رویکرد صفر کردن

برای جلوگیری از دوبرابر کردن فضای خالی، باید مطمئن شوید که پس‌از اینکه نمای بومی از بُعد درونی برای فضای خالی استفاده کرد، آن بُعد را بااستفاده از Insets.NONE در شیء WindowInsets جدید قبل‌از انتقال شیء اصلاح‌شده به پایین سلسله‌مراتب نما به «وب‌نما» به صفر بازنشانی کنید.

هنگام اعمال حاشیه داخلی به نمای والد، معمولاً باید از رویکرد صفر کردن با تنظیم Insets.NONE به‌جای WindowInsetsCompat.CONSUMED استفاده کنید. برگرداندن WindowInsetsCompat.CONSUMED ممکن است در شرایط خاصی کار کند. بااین‌حال، اگر کنترل‌کننده برنامه شما حاشیه‌ها را تغییر دهد یا فاصله داخلی خود را اضافه کند، ممکن است با مشکل مواجه شود. رویکرد صفر کردن این محدودیت‌ها را ندارد.

با صفر کردن حاشیه‌ها از حاشیه اضافی جلوگیری کنید

اگر وقتی برنامه قبلاً از حاشیه‌های مصرف‌نشده عبور کرده است از حاشیه‌ها استفاده کنید، یا اگر حاشیه‌ها تغییر کنند (مثلاً صفحه‌کلید پنهان شود)، استفاده از حاشیه‌ها مانع از دریافت اعلان به‌روزرسانی لازم توسط WebView می‌شود. این کار می‌تواند باعث شود که WebView حاشیه شبح‌وار را از وضعیت قبلی حفظ کند (برای مثال، حاشیه صفحه‌کلید را پس‌از پنهان شدن صفحه‌کلید حفظ کند).

مثال زیر تعامل خراب بین برنامه و «وب‌نما» را نشان می‌دهد:

  1. وضعیت اولیه: برنامه در ابتدا حاشیه‌های مصرف‌نشده (برای مثال، displayCutout() یا systemBars()) را به «وب‌نما» منتقل می‌کند که به‌صورت داخلی فاصله‌گذاری را به محتوای وب اعمال می‌کند.
  2. تغییر وضعیت و خطا: اگر برنامه وضعیت خود را تغییر دهد (برای مثال، صفحه‌کلید پنهان شود) و برنامه انتخاب کند که حاشیه‌های نتیجه را با برگرداندن WindowInsetsCompat.CONSUMED مدیریت کند.
  3. اعلان مسدود شد: مصرف حاشیه‌ها مانع از آن می‌شود که سیستم Android اعلان به‌روزرسانی لازم را در سلسله مراتب نمایشی به WebView ارسال کند.
  4. حاشیه شبح‌وار: چون WebView به‌روزرسانی را دریافت نمی‌کند، حاشیه از وضعیت قبلی را حفظ می‌کند و باعث ایجاد حاشیه شبح‌وار می‌شود (برای مثال، حفظ حاشیه صفحه‌کلید پس‌از پنهان شدن صفحه‌کلید).

به‌جای آن، از WindowInsetsCompat.Builder برای تنظیم انواع کنترل‌شده به صفر قبل‌از ارسال شیء به نماهای فرزند استفاده کنید. این به WebView اطلاع می‌دهد که آن حاشیه‌های خاص قبلاً درحین فعال کردن اعلان درنظر گرفته شده‌اند تا اعلان در سلسله مراتب نما ادامه یابد.

کاتلین

ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, windowInsets ->
    // 1. Identify the inset types you want to handle natively
    val types = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()

    // 2. Extract the dimensions and apply them as padding to the native container
    val insets = windowInsets.getInsets(types)
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom)

    // 3. Return a new WindowInsets object with the handled types set to NONE (zeroed).
    // This informs the WebView that these areas are already padded, preventing
    // double-padding while still allowing the WebView to update its internal state.
    WindowInsetsCompat.Builder(windowInsets)
        .setInsets(types, Insets.NONE)
        .build()
}

جاوا

ViewCompat.setOnApplyWindowInsetsListener(rootView, (view, windowInsets) -> {
    // 1. Identify the inset types you want to handle natively
    int types = WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout();

    // 2. Extract the dimensions and apply them as padding to the native container
    Insets insets = windowInsets.getInsets(types);
    rootView.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // 3. Return a new Insets object with the handled types set to NONE (zeroed).
    // This informs the WebView that these areas are already padded, preventing
    // double-padding while still allowing the WebView to update its internal
    // state.
    return new WindowInsetsCompat.Builder(windowInsets)
            .setInsets(types, Insets.NONE)
            .build();
});

نحوه انصراف دادن

برای غیرفعال کردن این رفتارهای مدرن و بازگشت به مدیریت نمای درگاه قدیمی، کارهای زیر را انجام دهید:

  1. میان‌گیری عناصر داخلی: از setOnApplyWindowInsetsListener استفاده کنید یا در زیرکلاس WebView onApplyWindowInsets ملغی کنید.

  2. پاک کردن حاشیه‌ها: مجموعه مصرف‌شده‌ای از حاشیه‌ها (برای نمونه، WindowInsetsCompat.CONSUMED) را از ابتدا برمی‌گرداند. این کنش از انتشار اعلان درون‌بر به «وب‌نما» به‌طور کامل جلوگیری می‌کند و درواقع تغییر اندازه ناحیه نمایش مدرن را غیرفعال می‌کند و «وب‌نما» را مجبور می‌کند اندازه ناحیه نمایش دیداری اولیه خود را حفظ کند.