एंड्रॉइड पर एज-टू-एज: इसे सही करना

पिछले Google I / O 2019 ने कई सनसनीखेज नवाचार लाए, जिनमें से कई आने वाले वर्षों में मोबाइल विकास उद्योग को प्रभावित करेंगे। उभरते रुझानों का पालन करना कोई कम दिलचस्प नहीं था। सबसे पहले, यांत्रिक नियंत्रण कुंजी इतिहास में नीचे चली गईं, स्मार्टफोन स्क्रीन बड़े हो गए और साइड फ्रेम अधिक असंगत हो गए। इशारों ने ऑन-स्क्रीन सिस्टम बटन को प्रतिस्थापित किया, जिससे सामग्री की खपत के लिए अधिक से अधिक स्थान छूट गया। एप्लिकेशन को डिस्प्ले के पूरे दृश्य सतह पर प्रदर्शित किया जाता है, नीचे से ऊपर के फ्रेम तक, स्थिति बार और नेविगेशन पैनल की सशर्त सीमाओं तक खुद को सीमित किए बिना। हम एज-टू-एज युग के कगार पर हैं।



एज-टू-एज क्या है? शाब्दिक रूप से समझा जाता है, इसका मतलब है कि आपके आवेदन को डिस्प्ले के पूरे दृश्य सतह पर नीचे से ऊपर के फ्रेम तक प्रदर्शित किया जाना चाहिए, बिना अपने आप को स्टेटस बार और लोअर नेविगेशन बटन तक सीमित किए बिना।


एंड्रॉइड सिस्टम शेल के उदाहरण पर एज-टू-एज।

जब यह एंड्रॉइड की बात आती है, तो एक सरल विचार हमेशा लागू करना आसान होता है। इस लेख में, हम किसी भी डिवाइस के स्क्रीन पर सभी उपलब्ध स्थान के उपयोग को अधिकतम करने के बारे में बात करेंगे, चाहे निर्माता, सिस्टम का संस्करण और सेटिंग्स की विविधता जो कि मध्य साम्राज्य (और न केवल) से डिवाइस निर्माताओं को उपयोगकर्ताओं को खुश करना पसंद है। लेख में प्रस्तुत कोड को हमारे द्वारा व्यक्तिगत रूप से 30 से अधिक उपकरणों पर और हमारे अनुप्रयोगों के 100 हजार उपयोगकर्ताओं द्वारा 231 विभिन्न उपकरणों पर परीक्षण किया गया था।

एज-टू-एज इंटरफेस बनाने की समस्या अपने आप में कोई नई बात नहीं है और I / O 2019 से बहुत पहले प्रासंगिक थी। निश्चित रूप से, आप में से प्रत्येक को याद होगा कि आप पहली बार श्रेणी से कुछ कैसे गूगल करते हैं: "एंड्रॉइड ट्रांसपेरेंट स्टेटस बार" या "एंड्रॉइड स्टेटस बार ग्रेडिएंट" ”

एज-टू-एज शीर्षक से मेल करने के लिए आवेदन के मुख्य मानदंड हैं:

  • पारदर्शी स्थिति पट्टी;
  • पारदर्शी नेविगेशन बार।

सामग्री पर उनके बारे में अधिक पढ़ें।


Deezer ऐप एज-टू-एज कंप्लायंस के बारे में चिंता नहीं करता है

यह ध्यान रखना महत्वपूर्ण है कि हम उन्हें पूरी तरह से हटाने के बारे में बात नहीं कर रहे हैं, जैसे कि " फुलस्क्रीन मोड " में। हम उपयोगकर्ता को महत्वपूर्ण सिस्टम जानकारी देखने और परिचित नेविगेशन का उपयोग करने का अवसर छोड़ते हैं।

एक समाधान के लिए समान रूप से महत्वपूर्ण आवश्यकता स्केलेबिलिटी और एक्स्टेंसिबिलिटी है। कई अन्य हैं:

  • सही ढंग से गतिविधि के समायोजित ध्वज के लिए समर्थन को तोड़ने के बिना कीबोर्ड के ऊपर स्क्रीन को स्थानांतरित करें;
  • एप्लिकेशन के UI तत्वों पर स्थिति पट्टी और नेविगेशन बार को ओवरले करने से बचें, जबकि उनके तहत संबंधित पृष्ठभूमि प्रदर्शित करते हैं;
  • Android के वर्तमान संस्करणों के साथ सभी उपकरणों पर काम करें और समान दिखें।

सिद्धांत की बिट


इस तरह के प्रतीत होने वाले सरल कार्य के लिए एक समाधान खोजने में अप्रत्याशित रूप से बहुत समय लग सकता है, जिसे समझना परियोजना प्रबंधक के लिए आसान नहीं होगा। और जब QA अभी भी बिना सोचे-समझे स्मार्टफोन ढूंढता है, जिस पर आपकी स्क्रीन "कैनन के अनुसार" नहीं दिखती है ...
हमारी परियोजना में, हमसे कई बार गलती हुई। केवल एक महीने बाद, परीक्षण और त्रुटि की एक लंबी श्रृंखला से गुजरने के बाद, क्या हमने एक बार और सभी के लिए समस्या का समाधान किया।

सबसे पहले, आपको यह समझने की आवश्यकता है कि एंड्रॉइड सिस्टम पैनल कैसे खींचता है। एंड्रॉइड 5.0 के साथ शुरू, स्क्रीन के क्षैतिज किनारों के साथ सिस्टम इंडेंट के साथ काम करने के लिए एक सुविधाजनक एपीआई प्रदान किया गया था। उन्हें WindowInsets कहा जाता है, और नीचे की तस्वीर में वे लाल रंग के होते हैं:


इसके अलावा, एंड्रॉइड टीम के डेवलपर्स ने श्रोताओं को जोड़ा है जो आपको इन इंडेंट में परिवर्तन की सदस्यता लेने की अनुमति देता है, उदाहरण के लिए, जब कीबोर्ड दिखाई देता है। सख्ती से बोलना, WindowInsets स्क्रीन के किनारों से आपके लेआउट फ़ाइल का मार्जिन है। जब आपकी गतिविधि (विभाजित-स्क्रीन मोड, कीबोर्ड उपस्थिति) का आकार बदल रहा है, तो इनसेट भी बदल जाएगा। इस प्रकार, एज-टू-एज का समर्थन करने के लिए, हमें यह सुनिश्चित करने की आवश्यकता है कि ये इंडेंट नहीं हैं। अशक्त WindowInsets के साथ एक स्क्रीन इस तरह दिखाई देगी:


कार्यान्वयन


हमारे कार्यान्वयन में, हम सक्रिय रूप से विंडो और उसके झंडे पर काम करेंगे।
सभी उदाहरण कोटलिन में लिखे जाएंगे, लेकिन आप विस्तार कार्यों के बजाय उपयोगिताओं का उपयोग करके आसानी से जावा में उन्हें लागू कर सकते हैं।

रूट लेआउट तत्व के साथ पहली बात यह है कि ध्वज को स्पष्ट रूप से सेट करना है:

android:fitsSystemWindows="true" 

यह सुनिश्चित करना आवश्यक है कि सिस्टम तत्वों के तहत रूट व्यू तैयार किया गया है, साथ ही उनके परिवर्तन की सदस्यता लेते समय इनसेट के सही माप के लिए।
अब हम सबसे महत्वपूर्ण बात की ओर मुड़ते हैं - हम स्क्रीन की सीमाओं को हटा देते हैं! हालांकि, यह बहुत सावधानी से किया जाना चाहिए। और यहाँ क्यों है:

  1. इनसेट को कम करने के लिए, हम कीबोर्ड की उपस्थिति के लिए विंडो की प्रतिक्रिया को खोने का जोखिम उठाते हैं: ऊपरी इनसेट को रीसेट करने के लिए स्टैकऑवरफ्लो पर दर्जनों युक्तियां हैं, लेकिन निचले वाले चुपचाप चुप हैं। इस वजह से, नेविगेशनबेर पूरी तरह से पारदर्शी होने के लिए नहीं निकलता है। इनसेट को कम करते समय, समायोजित करें ध्वज को काम करना बंद कर देता है।

    समाधान: प्रत्येक बार जब आप इनसेट को बदलते हैं, तो निर्धारित करें कि क्या कीबोर्ड की निचली ऊंचाई इसमें निहित है और केवल इसे अन्यथा रीसेट करें।
  2. जब आप इनसेट रीसेट करते हैं, तो दृश्य के दृश्य भाग स्टेटस बार और नेविगेशन बार के नीचे गिर जाएंगे। मटीरियल डिज़ाइन (और सामान्य ज्ञान) की अवधारणा के अनुसार, कोई सक्रिय तत्व सिस्टम क्षेत्रों में स्थित नहीं होना चाहिए। यही है, इस क्षेत्र में बटन, फ़ील्ड दर्ज करने के लिए फ़ील्ड, चेकबॉक्स आदि नहीं होने चाहिए।

    समाधान: हम श्रोता के साथ एक श्रोता जोड़ेंगे ताकि WindowInsets को बदलते समय, सिस्टम इंडेंट्स को गतिविधि में अनुवाद करें, और व्यू के लिए सही पैडिंग और मार्जिन सेट करके आंतरिक रूप से उनका जवाब दें।


इस व्यवहार की अनुमति नहीं दी जानी चाहिए (टूलबार स्थिति पट्टी पर क्रॉल करता है)।

निष्कासन प्रणाली () फ़ंक्शन इस तरह दिखता है:

 fun removeSystemInsets(view: View, listener: OnSystemInsetsChangedListener) { ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets -> val desiredBottomInset = calculateDesiredBottomInset( view, insets.systemWindowInsetTop, insets.systemWindowInsetBottom, listener ) ViewCompat.onApplyWindowInsets( view, insets.replaceSystemWindowInsets(0, 0, 0, desiredBottomInset) ) } } 

CalculDesiredBottomInset () फ़ंक्शन डिवाइस के वर्तमान कॉन्फ़िगरेशन के आधार पर कीबोर्ड के साथ या बिना नीचे इनसेट की गणना करता है।

 fun calculateDesiredBottomInset( view: View, topInset: Int, bottomInset: Int, listener: OnSystemInsetsChangedListener ): Int { val hasKeyboard = isKeyboardAppeared(view, bottomInset) val desiredBottomInset = if (hasKeyboard) bottomInset else 0 listener(topInset, if (hasKeyboard) 0 else bottomInset) return desiredBottomInset } 

कीबोर्ड की ऊंचाई जांचने के लिए isKeyboardAppeared () विधि का उपयोग करें हमने परिकल्पना पर भरोसा किया कि कीबोर्ड स्क्रीन की ऊंचाई के एक चौथाई से कम पर कब्जा नहीं कर सकता है। यदि वांछित है, तो आप सत्यापन तर्क को संशोधित कर सकते हैं जैसे आप चाहते हैं।

 private fun View.isKeyboardAppeared(bottomInset: Int) = bottomInset / resourdisplayMetrics.heightPixels.toDouble() > .25 

RemoveSystemInsets () विधि एक श्रोता का उपयोग करती है। दरअसल, ये लैंबडा एक्सप्रेशन के लिए सिर्फ टाइपलेसिया हैं। इसका पूरा कोड:

 typealias OnSystemBarsSizeChangedListener = (statusBarSize: Int, navigationBarSize: Int) -> Unit 

अगला कदम सिस्टम बार में पारदर्शिता स्थापित करना है:

 window.statusBarColor = Color.TRANSPARENT window.navigationBarColor = Color.TRANSPARENT 

उपरोक्त सभी को संकलित करने के बाद, हम निम्नलिखित विधि प्राप्त करते हैं:

 fun Activity.setWindowTransparency( listener: OnSystemInsetsChangedListener = { _, _ -> } ) { InsetUtil.removeSystemInsets(window.decorView, listener) window.navigationBarColor = Color.TRANSPARENT window.statusBarColor = Color.TRANSPARENT } 

अब, वांछित गतिविधि के एज-टू-एज मोड को सक्षम करने के लिए, आपको ऑनक्रिएट () विधि में निम्नलिखित फ़ंक्शन को कॉल करना होगा:

 setWindowTransparency { statusBarSize, navigationBarSize -> //  } 

इस प्रकार, कोड की 30 से कम लाइनों में, हमने "एज-टू-एज" प्रभाव प्राप्त किया है, जबकि किसी भी यूएक्स सिद्धांतों का उल्लंघन नहीं करते हैं और उपयोगकर्ता को सामान्य सिस्टम नियंत्रण से वंचित किए बिना। ऐसा कार्यान्वयन किसी के लिए सरल और तुच्छ लग सकता है, लेकिन यह ऐसा है जो किसी भी डिवाइस पर आपके एप्लिकेशन के विश्वसनीय संचालन को सुनिश्चित करता है।
आप लगभग सौ अलग-अलग तरीकों से "एज-टू-एज" प्रभाव को प्राप्त कर सकते हैं (स्टैकऑवरफ़्लो पर इस तरह की युक्तियों की संख्या इस बात की स्पष्ट पुष्टि है), लेकिन उनमें से कई एंड्रॉइड के विभिन्न संस्करणों पर या तो गलत व्यवहार का नेतृत्व करते हैं, या खाता मापदंडों को नहीं लेते हैं जैसे कि लंबे समय तक प्रदर्शित करने की आवश्यकता। कीबोर्ड दिखाते समय स्क्रीन आकार बदल देती है या तोड़ देती है।




मरहम में उड़ना


इस आलेख में वर्णित समाधान सभी वर्तमान उपकरणों के लिए उपयुक्त है। Android लॉलीपॉप (5.0) और उच्चतर पर वास्तविक साधन का मतलब है। उनके लिए, उपरोक्त समाधान पूरी तरह से काम करेगा। लेकिन एंड्रॉइड के पुराने संस्करणों के लिए, आपको अपने स्वयं के कार्यान्वयन की आवश्यकता होगी, क्योंकि उन दिनों में WindowInsets के बारे में कुछ भी ज्ञात नहीं था।

अच्छी खबर यह है कि एंड्रॉइड किटकैट (4.4) पर, सिस्टम पैनल की पारदर्शिता अभी भी समर्थित है। लेकिन पुराने संस्करण ऐसी सुंदरता का समर्थन नहीं करते हैं, आप कोशिश भी नहीं कर सकते।

आइए एंड्रॉइड 4.4 में इनसेट की शिफ्ट पर ध्यान दें। यह fitSystemWindows () विधि में किया जा सकता है। इस प्रकार, आपके लेआउट में मुख्य तत्व एक ओवररेटेड फिट सिस्टम के साथ एक कंटेनर होना चाहिए। जिसमें विंडोज के मौजूदा संस्करणों के उदाहरण में हमारे श्रोता के रूप में बिल्कुल समान कार्यान्वयन होता है।

 class KitkatTransparentSystemBarsFrame @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = -1 ) : FrameLayout(context, attrs, defStyleAttr), KitkatTransparentSystemBarsContainer { override var onSystemInsetsChangedListener: OnSystemInsetsChangedListener = { _, _ -> } override fun fitSystemWindows(insets: Rect?): Boolean { insets ?: return false val desiredBottomInset = InsetUtil.calculateDesiredBottomInset( this, insets.top, insets.bottom, onSystemInsetsChangedListener ) return super.fitSystemWindows(Rect(0, 0, 0, desiredBottomInset)) } 

एंड्रॉइड 4.4 वाले उपकरणों पर, पारभासी झंडे स्थापित करने के माध्यम से केवल आंशिक पारदर्शिता काम करती है:

 window.addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION ) 

ये झंडे सिस्टम पट्टियों को पारभासी बनाते हैं, जिससे उनमें थोड़ा सा ढाल होता है, जो दुर्भाग्य से हटाया नहीं जा सकता है। हालाँकि, इस लाइब्रेरी का उपयोग करके ढाल को एक पारभासी रंग पट्टी में बदल दिया जा सकता है: https://github.com/jgilfelt/SystemBarTint । उसने अतीत में एक से अधिक बार हमें बचाया है। लाइब्रेरी में नवीनतम परिवर्तन 5 साल पहले किए गए थे, इसलिए यह केवल सच्चे प्रतिगामी शहरों के लिए अपने आकर्षण को प्रकट करेगा।

किटकैट के लिए पूरी फ्लैगिंग प्रक्रिया इस तरह दिखाई देगी:

 fun Activity.setWindowTransparencyKitkat( rootView: KitkatTransparentSystemBarsContainer, listener: OnSystemBarsSizeChangedListener = { _, _ -> } ) { rootView.onSystemBarsSizeChangedListener = listener window.addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION ) } 

इसे ध्यान में रखते हुए, हम एक सार्वभौमिक विधि लिखते हैं जो सिस्टम सलाखों को पारदर्शी बना सकती है (या कम से कम पारभासी), इसके बावजूद कि कौन सा एप्लिकेशन किसी डिवाइस पर Android के संस्करण के साथ चल रहा है:

 when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> setWindowTransparency(::updateMargins) Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT -> setWindowTransparencyKitkat(root_container, ::updateMargins) else -> { /*do nothing*/ } } 

नीचे दिए गए स्पॉइलर के नीचे, आप देख सकते हैं कि लेख में प्रस्तुत नमूना कुछ समस्याग्रस्त उपकरणों पर कैसा दिखता है:

स्क्रीनशॉट
Huawei Honor 8, Android 7.0



Xiaomi Redmi Note 4, Android 6.1



एचटीसी डिजायर डुअल सिम, एंड्रॉयड 4.4.2



सैमसंग J3, एंड्रॉइड 7.0



Meizu M3s, एंड्रॉयड 5.1



असूस ज़ेनफोन 3 मैक्स, एंड्रॉयड 6.0



उम्मी रोम, एंड्रॉइड 5.0



Nexus 5X, Android 8.0



Samsung Galaxy S8, Android 9.0





अंत में, मैं यह कहना चाहता हूं कि सिस्टम यूआई के तत्वों की पारदर्शिता स्थापित करने के लिए इस तरह के प्रतीत होने वाले सरल कार्य का समाधान आपको पूरी तरह से नुकसान के साथ खींच सकता है और अंततः वांछित परिणाम नहीं दे सकता है, बल्कि अप्रिय कीड़े पैदा करेगा। अच्छी बात है कि अब आपके पास यह लेख है।

आप कार्यक्रम की पूरी सूची और हमारे गिट रिपॉजिटरी में काम का एक नमूना पा सकते हैं।

यह सामग्री क्रिस बेंस की रिपोर्ट "मास्टर विंडो फिटर बनना" से प्रेरित है।


मैं सामग्री तैयार करने में मदद के लिए सर्फ स्टूडियो और एवगेनी सतरोव का आभार व्यक्त करता हूं।

Source: https://habr.com/ru/post/hi464373/


All Articles