अपने ऐप्लिकेशन को फ़ोल्ड करें

बड़े अनफ़ोल्ड डिसप्ले और फ़ोल्ड किए गए यूनीक स्टेटस की मदद से, नए उपयोगकर्ता अनुभव पाएं फ़ोल्ड किए जा सकने वाले डिवाइस. अपने ऐप्लिकेशन को फ़ोल्ड किए जा सकने वाले डिवाइसों के हिसाब से बनाने के लिए, Jetpack WindowManager लाइब्रेरी का इस्तेमाल करें. यह लाइब्रेरी, फ़ोल्ड किए जा सकने वाले डिवाइस की विंडो की सुविधाओं के लिए एपीआई प्लैटफ़ॉर्म उपलब्ध कराती है. जैसे, फ़ोल्ड और हिंज. जब आपका ऐप्लिकेशन फ़ोल्ड अवेयर आपके ऐप्लिकेशन का लेआउट इस्तेमाल कर सकता है, तब वह इसके लेआउट के हिसाब से बदलाव कर सकता है ज़रूरी कॉन्टेंट को फ़ोल्ड या कब्ज़ों पर न डालें. साथ ही, फ़ोल्ड का इस्तेमाल करें और हिंग, नैचुरल सेपरेटर की तरह हैं.

यह समझने से कि कोई डिवाइस, टेबलटॉप या किताब के तौर पर इस्तेमाल करने जैसे कॉन्फ़िगरेशन के साथ काम करता है या नहीं, अलग-अलग लेआउट के साथ काम करने या खास सुविधाएं देने के बारे में फ़ैसले लिए जा सकते हैं.

विंडो की जानकारी

Jetpack WindowManager में WindowInfoTracker इंटरफ़ेस, विंडो के लेआउट की जानकारी दिखाता है. इंटरफ़ेस का windowLayoutInfo() तरीका, WindowLayoutInfo डेटा की स्ट्रीम दिखाता है. इससे आपके ऐप्लिकेशन को फ़ोल्ड किए जा सकने वाले डिवाइस की फ़ोल्ड की गई स्थिति के बारे में पता चलता है. WindowInfoTracker#getOrCreate() तरीके से WindowInfoTracker का इंस्टेंस.

WindowManager, Kotlin फ़्लो और Java कॉलबैक का इस्तेमाल करके WindowLayoutInfo डेटा इकट्ठा करने की सुविधा देता है.

Kotlin फ़्लो

WindowLayoutInfo डेटा कलेक्शन को शुरू और बंद करने के लिए, रीस्टार्टेबल बटन का इस्तेमाल किया जा सकता है लाइफ़साइकल-अवेयर कोरूटीन, जिसमें repeatOnLifecycle कोड ब्लॉक होता है लाइफ़साइकल कम से कम STARTED होने पर लागू होता है और तब रुक जाता है, जब लाइफ़साइकल STOPPED है. कोड ब्लॉक चलाने की प्रोसेस अपने-आप फिर से शुरू हो जाती है जब लाइफ़साइकल फिर से STARTED होगा. नीचे दिए गए उदाहरण में, कोड ब्लॉक WindowLayoutInfo का डेटा इकट्ठा और इस्तेमाल करता है:

class DisplayFeaturesActivity : AppCompatActivity() {

    private lateinit var binding: ActivityDisplayFeaturesBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityDisplayFeaturesBinding.inflate(layoutInflater)
        setContentView(binding.root)

        lifecycleScope.launch(Dispatchers.Main) {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                WindowInfoTracker.getOrCreate(this@DisplayFeaturesActivity)
                    .windowLayoutInfo(this@DisplayFeaturesActivity)
                    .collect { newLayoutInfo ->
                        // Use newLayoutInfo to update the layout.
                    }
            }
        }
    }
}

Java कॉलबैक

androidx.window:window-java डिपेंडेंसी में शामिल कॉलबैक के साथ काम करने वाली लेयर की मदद से, Kotlin फ़्लो का इस्तेमाल किए बिना WindowLayoutInfo अपडेट इकट्ठा किए जा सकते हैं. आर्टफ़ैक्ट में शामिल है WindowInfoTrackerCallbackAdapter क्लास, जो इन पर कॉलबैक रजिस्टर करने (और रजिस्टर करने) में मदद करने के लिए WindowInfoTracker WindowLayoutInfo अपडेट पाएं, उदाहरण के लिए:

public class SplitLayoutActivity extends AppCompatActivity {

    private WindowInfoTrackerCallbackAdapter windowInfoTracker;
    private ActivitySplitLayoutBinding binding;
    private final LayoutStateChangeCallback layoutStateChangeCallback =
            new LayoutStateChangeCallback();

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
       setContentView(binding.getRoot());

       windowInfoTracker =
                new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
   }

   @Override
   protected void onStart() {
       super.onStart();
       windowInfoTracker.addWindowLayoutInfoListener(
                this, Runnable::run, layoutStateChangeCallback);
   }

   @Override
   protected void onStop() {
       super.onStop();
       windowInfoTracker
           .removeWindowLayoutInfoListener(layoutStateChangeCallback);
   }

   class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
       @Override
       public void accept(WindowLayoutInfo newLayoutInfo) {
           SplitLayoutActivity.this.runOnUiThread( () -> {
               // Use newLayoutInfo to update the layout.
           });
       }
   }
}

RxJava सहायता

अगर RxJava (2 या 3 वर्शन) का इस्तेमाल पहले से किया जा रहा है, तो ऐसे आर्टफ़ैक्ट का फ़ायदा लिया जा सकता है जिनकी मदद से, Kotlin फ़्लो का इस्तेमाल किए बिना WindowLayoutInfo अपडेट इकट्ठा करने के लिए, Observable या Flowable का इस्तेमाल किया जा सकता है.

androidx.window:window-rxjava2 और androidx.window:window-rxjava3 डिपेंडेंसी में WindowInfoTracker#windowLayoutInfoFlowable() और WindowInfoTracker#windowLayoutInfoObservable() तरीके हैं जिनसे आपको ऐप्लिकेशन को WindowLayoutInfo अपडेट पाने के लिए, उदाहरण के लिए:

class RxActivity: AppCompatActivity {

    private lateinit var binding: ActivityRxBinding

    private var disposable: Disposable? = null
    private lateinit var observable: Observable<WindowLayoutInfo>

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
       setContentView(binding.getRoot());

        // Create a new observable.
        observable = WindowInfoTracker.getOrCreate(this@RxActivity)
            .windowLayoutInfoObservable(this@RxActivity)
   }

   @Override
   protected void onStart() {
       super.onStart();

        // Subscribe to receive WindowLayoutInfo updates.
        disposable?.dispose()
        disposable = observable
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { newLayoutInfo ->
            // Use newLayoutInfo to update the layout.
        }
   }

   @Override
   protected void onStop() {
       super.onStop();

        // Dispose of the WindowLayoutInfo observable.
        disposable?.dispose()
   }
}

फ़ोल्ड किए जा सकने वाले डिसप्ले की सुविधाएं

Jetpack WindowManager की WindowLayoutInfo क्लास, डिसप्ले विंडो, DisplayFeature एलिमेंट की सूची के तौर पर उपलब्ध है.

FoldingFeature एक तरह का DisplayFeature है. इसमें फ़ोल्ड किए जा सकने वाले डिसप्ले के बारे में जानकारी मिलती है. इसमें यह जानकारी शामिल है:

  • state: डिवाइस को फ़ोल्ड किया गया होने की स्थिति, FLAT या HALF_OPENED

  • orientation: फ़ोल्ड या हिंज का ओरिएंटेशन, HORIZONTAL या VERTICAL

  • occlusionType: क्या फ़ोल्ड या हिंज, डिसप्ले का कुछ हिस्सा छिपाता है, NONE या FULL

  • isSeparating: क्या फ़ोल्ड या हिंज दो लॉजिकल डिसप्ले एरिया बनाता है, सही या गलत

फ़ोल्ड किए जा सकने वाला ऐसा डिवाइस जो HALF_OPENED है, वह isSeparating को हमेशा 'सही' के तौर पर रिपोर्ट करता है, क्योंकि उसकी स्क्रीन दो डिसप्ले एरिया में बंटी होती है. साथ ही, जब ऐप्लिकेशन दोनों स्क्रीन पर दिखता है, तो ड्यूअल स्क्रीन वाले डिवाइस पर isSeparating हमेशा 'सही' होता है.

FoldingFeature bounds प्रॉपर्टी (DisplayFeature से इनहेरिट की गई) फ़ोल्ड या हिंज जैसी फ़ोल्डिंग रेक्टैंगल को दिखाता है. बॉउंड का इस्तेमाल, स्क्रीन पर एलिमेंट को फ़ीचर के हिसाब से पोज़िशन करने के लिए किया जा सकता है:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    lifecycleScope.launch(Dispatchers.Main) {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            // Safely collects from WindowInfoTracker when the lifecycle is
            // STARTED and stops collection when the lifecycle is STOPPED.
            WindowInfoTracker.getOrCreate(this@MainActivity)
                .windowLayoutInfo(this@MainActivity)
                .collect { layoutInfo ->
                    // New posture information.
                    val foldingFeature = layoutInfo.displayFeatures
                        .filterIsInstance<FoldingFeature>()
                        .firstOrNull()
                    // Use information from the foldingFeature object.
                }

        }
    }
}

Java

private WindowInfoTrackerCallbackAdapter windowInfoTracker;
private final LayoutStateChangeCallback layoutStateChangeCallback =
                new LayoutStateChangeCallback();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    ...
    windowInfoTracker =
            new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
}

@Override
protected void onStart() {
    super.onStart();
    windowInfoTracker.addWindowLayoutInfoListener(
            this, Runnable::run, layoutStateChangeCallback);
}

@Override
protected void onStop() {
    super.onStop();
    windowInfoTracker.removeWindowLayoutInfoListener(layoutStateChangeCallback);
}

class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
    @Override
    public void accept(WindowLayoutInfo newLayoutInfo) {
        // Use newLayoutInfo to update the Layout.
        List<DisplayFeature> displayFeatures = newLayoutInfo.getDisplayFeatures();
        for (DisplayFeature feature : displayFeatures) {
            if (feature instanceof FoldingFeature) {
                // Use information from the feature object.
            }
        }
    }
}

टेबलटॉप पॉस्चर

FoldingFeature ऑब्जेक्ट में शामिल जानकारी का इस्तेमाल करके, आपका ऐप्लिकेशन टेबलटॉप जैसे पोज़िशन के साथ काम कर सकता है. इसमें फ़ोन किसी सतह पर होता है, हिंज हॉरिज़ॉन्टल पोज़िशन में होता है, और फ़ोल्ड होने वाली स्क्रीन आधी खुली होती है.

टेबलटॉप पॉस्चर की मदद से, उपयोगकर्ता आसानी से अपना फ़ोन इस्तेमाल कर सकते हैं हाथ में फ़ोन पकड़ा हुआ था. टेबलटॉप पोज़िशन, मीडिया देखने, फ़ोटो लेने, और वीडियो कॉल करने के लिए बेहतरीन है.

पहला डायग्राम. टेबलटॉप पोज़िशन में वीडियो प्लेयर ऐप्लिकेशन.

FoldingFeature.State और FoldingFeature.Orientation का इस्तेमाल करके पता लगाएं डिवाइस टेबलटॉप पोज़िशन में है या नहीं:

Kotlin

fun isTableTopPosture(foldFeature : FoldingFeature?) : Boolean {
    contract { returns(true) implies (foldFeature != null) }
    return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
}

Java

boolean isTableTopPosture(FoldingFeature foldFeature) {
    return (foldFeature != null) &&
           (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
           (foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL);
}

जब आपको पता चल जाए कि डिवाइस टेबलटॉप पोज़िशन में है, तो ऐप्लिकेशन का लेआउट अपडेट करें भुगतान करते हैं. मीडिया ऐप्लिकेशन के लिए, आम तौर पर इसका मतलब है कि वीडियो चलाने की सुविधा को फ़ोल्ड के ऊपर रखना. साथ ही, कंट्रोल और अन्य कॉन्टेंट को उसके नीचे रखना, ताकि बिना हाथ इस्तेमाल किए वीडियो देखा या सुना जा सके.

Android 15 (एपीआई लेवल 35) और इसके बाद के वर्शन पर, सिंक्रोनस एपीआई का इस्तेमाल करके यह पता लगाया जा सकता है कि कोई डिवाइस, टेबलटॉप पोज़िशन के साथ काम करता है या नहीं. भले ही, डिवाइस की मौजूदा स्थिति कुछ भी हो.

एपीआई, डिवाइस के साथ काम करने वाले पॉस्चर की सूची उपलब्ध कराता है. अगर सूची इसमें टेबलटॉप पॉस्चर शामिल है. पॉस्चर को ठीक रखने के लिए, अपने ऐप्लिकेशन के लेआउट को स्प्लिट किया जा सकता है और टेबलटॉप और फ़ुल-स्क्रीन लेआउट के लिए, अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) पर A/B टेस्ट करें.

Kotlin

if (WindowSdkExtensions.getInstance().extensionsVersion >= 6) {
    val postures = WindowInfoTracker.getOrCreate(context).supportedPostures
    if (postures.contains(TABLE_TOP)) {
        // Device supports tabletop posture.
   }
}

Java

if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) {
    List<SupportedPosture> postures = WindowInfoTracker.getOrCreate(context).getSupportedPostures();
    if (postures.contains(SupportedPosture.TABLETOP)) {
        // Device supports tabletop posture.
    }
}

उदाहरण

किताब का पॉज़िशन

फ़ोल्ड किए जा सकने वाले डिवाइस की एक और खास सुविधा है, किताब का पॉस्चर. इसमें डिवाइस आधा खुला हुआ है और हिंज वर्टिकल होता है. ई-बुक पढ़ने के लिए, किताब पढ़ने का आसन सबसे अच्छा है. बड़ी स्क्रीन वाले फ़ोल्ड किए जा सकने वाले डिवाइस पर, दो पेजों के लेआउट में किताब को बंधी हुई किताब की तरह खोला जा सकता है. इस मोड में, किताब पढ़ने का अनुभव असल किताब पढ़ने जैसा ही होता है.

अगर फ़ोटो के किसी दूसरे हिस्से को कैप्चर करना है, तो फ़ोटोग्राफ़ी के लिए भी इसका इस्तेमाल किया जा सकता है हैंड्स-फ़्री तरीके से फ़ोटो लेते समय अनुपात.

टेबलटॉप पोज़िशन के लिए इस्तेमाल की गई तकनीकों का इस्तेमाल करके, किताब पढ़ने के लिए पोज़िशन तय करें. इन दोनों में सिर्फ़ एक अंतर है. कोड को यह देखना चाहिए कि फ़ोल्डिंग की सुविधा का ओरिएंटेशन, हॉरिज़ॉन्टल के बजाय वर्टिकल है या नहीं:

Kotlin

fun isBookPosture(foldFeature : FoldingFeature?) : Boolean {
    contract { returns(true) implies (foldFeature != null) }
    return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
}

Java

boolean isBookPosture(FoldingFeature foldFeature) {
    return (foldFeature != null) &&
           (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
           (foldFeature.getOrientation() == FoldingFeature.Orientation.VERTICAL);
}

विंडो का साइज़ बदलना

डिवाइस के कॉन्फ़िगरेशन में बदलाव होने पर, ऐप्लिकेशन के डिसप्ले एरिया में बदलाव हो सकता है. उदाहरण के लिए, जब डिवाइस को फ़ोल्ड या अनफ़ोल्ड किया जाता है, घुमाया जाता है या मल्टी-विंडो मोड में किसी विंडो का साइज़ बदला जाता है.

Jetpack WindowManager WindowMetricsCalculator क्लास की मदद से, ये काम किए जा सकते हैं मौजूदा और ज़्यादा से ज़्यादा विंडो मेट्रिक फिर से पाने के लिए. जैसे प्लैटफ़ॉर्म एपीआई लेवल 30, WindowManager में WindowMetrics को पेश किया गया है WindowMetrics, विंडो की सीमाएं बताता है. हालांकि, एपीआई पुराने सिस्टम के साथ काम करता है एपीआई लेवल 14 तक कम करें.

विंडो के साइज़ की क्लास इस्तेमाल करना देखें.

अन्य संसाधन

सैंपल

  • Jetpack WindowManager: Jetpack WindowManager लाइब्रेरी इस्तेमाल करने का उदाहरण
  • Jetcaster : Compose की मदद से टेबलटॉप मोड लागू करना

कोडलैब