ওয়েবভিউতে উইন্ডো ইনসেটগুলি বুঝুন

ওয়েবভিউ দুটি ভিউপোর্ট ব্যবহার করে কন্টেন্ট অ্যালাইনমেন্ট পরিচালনা করে: লেআউট ভিউপোর্ট (পৃষ্ঠার আকার) এবং ভিজ্যুয়াল ভিউপোর্ট (পৃষ্ঠার যে অংশটি ব্যবহারকারী আসলে দেখেন)। লেআউট ভিউপোর্ট সাধারণত স্ট্যাটিক থাকে, ব্যবহারকারীরা যখন জুম, স্ক্রোল বা সিস্টেম UI উপাদান (যেমন সফ্টওয়্যার কীবোর্ড) প্রদর্শিত হয় তখন ভিজ্যুয়াল ভিউপোর্ট গতিশীলভাবে পরিবর্তিত হয়।

বৈশিষ্ট্যের সামঞ্জস্যতা

ওয়েব কন্টেন্ট আচরণকে নেটিভ অ্যান্ড্রয়েড অ্যাপের প্রত্যাশার সাথে সামঞ্জস্যপূর্ণ করার জন্য সময়ের সাথে সাথে উইন্ডো ইনসেটের জন্য ওয়েবভিউ সমর্থন বিকশিত হয়েছে:

মাইলস্টোন বৈশিষ্ট্য যোগ করা হয়েছে ব্যাপ্তি
এম১৩৬ CSS সেফ-এরিয়া-ইনসেটের মাধ্যমে displayCutout() এবং systemBars() সাপোর্ট করে। শুধুমাত্র পূর্ণস্ক্রিন ওয়েবভিউ।
এম১৩৯ ime() (ইনপুট মেথড এডিটর, যা একটি কীবোর্ড) ভিজ্যুয়াল ভিউপোর্ট রিসাইজিংয়ের মাধ্যমে সমর্থন করে। সকল ওয়েবভিউ।
এম১৪৪ displayCutout() এবং systemBars() সাপোর্ট। সমস্ত ওয়েবভিউ (পূর্ণস্ক্রিনের অবস্থা নির্বিশেষে)।

আরও তথ্যের জন্য, WindowInsetsCompat দেখুন।

মূল বলবিদ্যা

ওয়েবভিউ দুটি প্রাথমিক প্রক্রিয়ার মাধ্যমে ইনসেট পরিচালনা করে:

  • নিরাপদ এলাকা ( displayCutout , systemBars ): WebView এই মাত্রাগুলিকে CSS safe-area-inset-* ভেরিয়েবলের মাধ্যমে ওয়েব কন্টেন্টে ফরোয়ার্ড করে। এটি ডেভেলপারদের তাদের নিজস্ব ইন্টারেক্টিভ উপাদানগুলি (যেমন নেভিগেশন বার) নচ বা স্ট্যাটাস বার দ্বারা অস্পষ্ট হওয়া থেকে রক্ষা করতে সক্ষম করে।

  • ইনপুট মেথড এডিটর (IME) ব্যবহার করে ভিজ্যুয়াল ভিউপোর্ট রিসাইজ করা: M139 থেকে শুরু করে, ইনপুট মেথড এডিটর (IME) সরাসরি ভিজ্যুয়াল ভিউপোর্টের আকার পরিবর্তন করে। এই রিসাইজিং মেকানিজমটিও WebView-Window ইন্টারসেকশনের উপর ভিত্তি করে তৈরি। উদাহরণস্বরূপ, Android মাল্টিটাস্কিং মোডে, যদি WebView-এর নীচের অংশটি উইন্ডোর নীচের অংশ থেকে 200dp পর্যন্ত প্রসারিত হয়, তাহলে ভিজ্যুয়াল ভিউপোর্টটি WebView-এর আকারের চেয়ে 200dp ছোট হয়। এই ভিজ্যুয়াল ভিউপোর্ট রিসাইজ করা (IME এবং WebView-Window ইন্টারসেকশন উভয়ের জন্য) শুধুমাত্র WebView-এর নীচে প্রয়োগ করা হয়। এই মেকানিজম বাম, ডান বা উপরের ওভারল্যাপের জন্য রিসাইজ করা সমর্থন করে না। এর অর্থ হল সেই প্রান্তগুলিতে প্রদর্শিত ডক করা কীবোর্ডগুলি ভিজ্যুয়াল ভিউপোর্ট রিসাইজ ট্রিগার করে না।

পূর্বে, ভিজ্যুয়াল ভিউপোর্টটি স্থির থাকত, প্রায়শই কীবোর্ডের পিছনে ইনপুট ক্ষেত্রগুলি লুকিয়ে রাখত। ভিউপোর্টের আকার পরিবর্তন করার মাধ্যমে, পৃষ্ঠার দৃশ্যমান অংশটি ডিফল্টরূপে স্ক্রোলযোগ্য হয়ে ওঠে, যা ব্যবহারকারীদের অস্পষ্ট বিষয়বস্তুতে পৌঁছাতে সাহায্য করে।

সীমানা এবং ওভারল্যাপ যুক্তি

WebView শুধুমাত্র তখনই শূন্য-বহির্ভূত ইনসেট মান পাবে যখন সিস্টেম UI উপাদানগুলি (বার, ডিসপ্লে কাটআউট, অথবা কীবোর্ড) WebView এর স্ক্রিন সীমানার সাথে সরাসরি ওভারল্যাপ করবে। যদি একটি WebView এই UI উপাদানগুলির সাথে ওভারল্যাপ না করে (যেমন, যদি একটি WebView স্ক্রিনের কেন্দ্রে থাকে এবং সিস্টেম বারগুলিকে স্পর্শ না করে), তাহলে এটি সেই ইনসেটগুলিকে শূন্য হিসাবে গ্রহণ করবে।

এই ডিফল্ট লজিকটি ওভাররাইড করতে এবং ওভারল্যাপ নির্বিশেষে সম্পূর্ণ সিস্টেম ডাইমেনশন সহ ওয়েব কন্টেন্ট প্রদান করতে, 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-এর ডিফল্ট সেটিংস স্বয়ংক্রিয়ভাবে কাজ করে। তবে, যদি আপনার অ্যাপ কাস্টম লেআউট ব্যবহার করে (উদাহরণস্বরূপ, যদি আপনি স্ট্যাটাস বার বা কীবোর্ডের জন্য আপনার নিজস্ব প্যাডিং যোগ করেন), তাহলে ওয়েব কন্টেন্ট এবং নেটিভ UI কীভাবে একসাথে কাজ করে তা উন্নত করতে আপনি নিম্নলিখিত পদ্ধতিগুলি ব্যবহার করতে পারেন। যদি আপনার নেটিভ UI WindowInsets উপর ভিত্তি করে একটি কন্টেইনারে প্যাডিং প্রয়োগ করে, তাহলে ডাবল-প্যাডিং এড়াতে WebView-এ পৌঁছানোর আগে আপনাকে এই ইনসেটগুলি সঠিকভাবে পরিচালনা করতে হবে।

ডাবল-প্যাডিং হলো এমন একটি পরিস্থিতি যেখানে নেটিভ লেআউট এবং ওয়েব কন্টেন্ট একই ইনসেট ডাইমেনশন প্রয়োগ করে, যার ফলে অতিরিক্ত স্পেসিং তৈরি হয়। উদাহরণস্বরূপ, 40px স্ট্যাটাস বার সহ একটি ফোন কল্পনা করুন। নেটিভ ভিউ এবং ওয়েবভিউ উভয়ই 40px ইনসেট দেখতে পায়। উভয়ই 40px প্যাডিং যোগ করে, যার ফলে ব্যবহারকারী উপরের দিকে 80px গ্যাপ দেখতে পান।

শূন্যীকরণ পদ্ধতি

ডাবল-প্যাডিং প্রতিরোধ করার জন্য, আপনাকে নিশ্চিত করতে হবে যে একটি নেটিভ ভিউ প্যাডিংয়ের জন্য একটি ইনসেট ডাইমেনশন ব্যবহার করার পরে, আপনি একটি নতুন WindowInsets অবজেক্টে Insets.NONE ব্যবহার করে সেই ডাইমেনশনটি শূন্যে রিসেট করুন এবং পরিবর্তিত অবজেক্টটিকে ভিউ হায়ারার্কির নিচে WebView-এ পাঠান।

প্যারেন্ট ভিউতে প্যাডিং প্রয়োগ করার সময়, আপনার সাধারণত WindowInsetsCompat.CONSUMED এর পরিবর্তে Insets.NONE সেট করে জিরোয়িং পদ্ধতি ব্যবহার করা উচিত। WindowInsetsCompat.CONSUMED রিটার্ন করা কিছু পরিস্থিতিতে কাজ করতে পারে। তবে, আপনার অ্যাপের হ্যান্ডলার যদি ইনসেট পরিবর্তন করে বা নিজস্ব প্যাডিং যোগ করে তবে এটি সমস্যার সম্মুখীন হতে পারে। জিরোয়িং পদ্ধতিতে এই সীমাবদ্ধতাগুলি নেই।

ইনসেট শূন্য করে ঘোস্ট প্যাডিং এড়িয়ে চলুন

যদি আপনি অ্যাপটি পূর্বে নন-কনজুমড ইনসেটগুলি পাস করার সময় ইনসেটগুলি ব্যবহার করেন, অথবা ইনসেটগুলি পরিবর্তিত হয় (যেমন কীবোর্ড লুকানো), তবে সেগুলি গ্রহণ করলে ওয়েবভিউ প্রয়োজনীয় আপডেট বিজ্ঞপ্তি পেতে বাধা দেয়। এর ফলে ওয়েবভিউ পূর্ববর্তী অবস্থা থেকে ঘোস্ট প্যাডিং ধরে রাখতে পারে (উদাহরণস্বরূপ, কীবোর্ড লুকানোর পরে কীবোর্ড প্যাডিং রাখা)।

নিম্নলিখিত উদাহরণটি অ্যাপ এবং WebView এর মধ্যে একটি ভাঙা মিথস্ক্রিয়া দেখায়:

  1. প্রাথমিক অবস্থা: অ্যাপটি প্রাথমিকভাবে নন-কনজুমড ইনসেটগুলি (উদাহরণস্বরূপ, displayCutout() বা systemBars() ) WebView-এ পাস করে, যা অভ্যন্তরীণভাবে ওয়েব কন্টেন্টে প্যাডিং প্রয়োগ করে।
  2. অবস্থা পরিবর্তন এবং ত্রুটি: যদি অ্যাপটি অবস্থা পরিবর্তন করে (উদাহরণস্বরূপ, কীবোর্ড লুকায়) এবং অ্যাপটি WindowInsetsCompat.CONSUMED রিটার্ন করে ফলাফলের ইনসেটগুলি পরিচালনা করতে পছন্দ করে।
  3. বিজ্ঞপ্তি ব্লক করা হয়েছে: ইনসেটগুলি ব্যবহার করলে অ্যান্ড্রয়েড সিস্টেম ভিউ হায়ারার্কির নিচে প্রয়োজনীয় আপডেট বিজ্ঞপ্তি ওয়েবভিউতে পাঠাতে বাধা দেয়।
  4. ঘোস্ট প্যাডিং: যেহেতু ওয়েবভিউ আপডেটটি গ্রহণ করে না, তাই এটি পূর্ববর্তী অবস্থা থেকে প্যাডিং ধরে রাখে, যার ফলে ঘোস্ট প্যাডিং হয় (উদাহরণস্বরূপ, কীবোর্ড লুকানোর পরে কীবোর্ড প্যাডিং রাখা)।

পরিবর্তে, চাইল্ড ভিউতে অবজেক্টটি পাস করার আগে হ্যান্ডেল করা টাইপগুলিকে শূন্যে সেট করতে 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. ইন্টারসেপ্ট ইনসেট: একটি WebView সাবক্লাসে setOnApplyWindowInsetsListener ব্যবহার করুন অথবা onApplyWindowInsets ওভাররাইড করুন।

  2. ইনসেট সাফ করুন: শুরু থেকেই ইনসেটের একটি গ্রাস করা সেট (উদাহরণস্বরূপ, WindowInsetsCompat.CONSUMED ) ফিরিয়ে আনুন। এই ক্রিয়াটি ইনসেট বিজ্ঞপ্তিটিকে ওয়েবভিউতে সম্পূর্ণভাবে প্রচার করা থেকে বিরত রাখে, কার্যকরভাবে আধুনিক ভিউপোর্ট রিসাইজিং অক্ষম করে এবং ওয়েবভিউকে তার প্রাথমিক ভিজ্যুয়াল ভিউপোর্ট আকার ধরে রাখতে বাধ্য করে।