ऐप्स विकसित करें

निम्नलिखित सामग्री ऐप डेवलपर्स के लिए है।

अपने ऐप को रोटरी समर्थन देने के लिए, आपको यह करना होगा:

  1. संबंधित गतिविधि लेआउट में FocusParkingView रखें।
  2. उन विचारों को सुनिश्चित करें जो ध्यान केंद्रित करने योग्य हैं (या नहीं हैं)।
  3. FocusParkingView को छोड़कर, अपने सभी फोकस करने योग्य दृश्यों को लपेटने के लिए FocusArea का उपयोग करें।

रोटरी-सक्षम ऐप्स विकसित करने के लिए अपना वातावरण स्थापित करने के बाद, इनमें से प्रत्येक कार्य का विवरण नीचे दिया गया है।

एक रोटरी नियंत्रक स्थापित करें

इससे पहले कि आप रोटरी-सक्षम ऐप्स विकसित करना शुरू करें, आपको या तो एक रोटरी नियंत्रक या एक स्टैंड-इन की आवश्यकता होगी। आपके पास नीचे वर्णित विकल्प हैं।

एम्यूलेटर

source build/envsetup.sh && lunch car_x86_64-userdebug
m -j
emulator -wipe-data -no-snapshot -writable-system

आप aosp_car_x86_64-userdebug भी उपयोग कर सकते हैं।

अनुकरणित रोटरी नियंत्रक तक पहुँचने के लिए:

  1. टूलबार के नीचे तीन बिंदुओं पर टैप करें:

    एक्सेस एम्युलेटेड रोटरी कंट्रोलर
    चित्र 1. एक्सेस एम्युलेटेड रोटरी नियंत्रक
  2. विस्तारित नियंत्रण विंडो में कार रोटरी का चयन करें:

    कार रोटरी का चयन करें
    चित्र 2. कार रोटरी का चयन करें

यूएसबी कीबोर्ड

  • अपने डिवाइस में एक यूएसबी कीबोर्ड प्लग करें जो एंड्रॉइड ऑटोमोटिव ओएस (एएओएस) चलाता है, कुछ मामलों में, यह ऑन-स्क्रीन कीबोर्ड को प्रदर्शित होने से रोकता है।
  • userdebug या eng बिल्ड का उपयोग करें।
  • मुख्य ईवेंट फ़िल्टरिंग सक्षम करें:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • प्रत्येक क्रिया के लिए संबंधित कुंजी ढूंढने के लिए नीचे दी गई तालिका देखें:
    चाबी रोटरी क्रिया
    क्यू वामावर्त स्थिति में घुमाएं
    घड़ी की सुई की दिशा में घुमाओ
    कुहनी बाएँ
    डी दाहिनी ओर इशारा करें
    डब्ल्यू कुहनी ऊपर उठाओ
    एस नीचे झुको
    एफ या अल्पविराम केंद्र बटन
    आर या Esc पिछला बटन

एडीबी आदेश

आप रोटरी इनपुट इवेंट को इंजेक्ट करने के लिए car_service कमांड का उपयोग कर सकते हैं। ये कमांड एंड्रॉइड ऑटोमोटिव ओएस (एएओएस) चलाने वाले डिवाइस या एमुलेटर पर चलाए जा सकते हैं।

कार_सेवा आदेश रोटरी इनपुट
adb shell cmd car_service inject-rotary वामावर्त स्थिति में घुमाएं
adb shell cmd car_service inject-rotary -c true घड़ी की सुई की दिशा में घुमाओ
adb shell cmd car_service inject-rotary -dt 100 50 कई बार वामावर्त घुमाएँ (100 एमएस पहले और 50 एमएस पहले)
adb shell cmd car_service inject-key 282 कुहनी बाएँ
adb shell cmd car_service inject-key 283 दाहिनी ओर इशारा करें
adb shell cmd car_service inject-key 280 कुहनी ऊपर उठाओ
adb shell cmd car_service inject-key 281 नीचे झुको
adb shell cmd car_service inject-key 23 केंद्र बटन क्लिक करें
adb shell input keyevent inject-key 4 बैक बटन क्लिक करें

OEM रोटरी नियंत्रक

जब आपका रोटरी कंट्रोलर हार्डवेयर चालू और चालू हो, तो यह सबसे यथार्थवादी विकल्प है। यह तेज़ रोटेशन के परीक्षण के लिए विशेष रूप से उपयोगी है।

फोकसपार्किंग दृश्य

FocusParkingView कार यूआई लाइब्रेरी (कार-यूआई-लाइब्रेरी) में एक पारदर्शी दृश्य है। RotaryService इसका उपयोग रोटरी नियंत्रक नेविगेशन का समर्थन करने के लिए करता है। FocusParkingView लेआउट में पहला फोकस करने योग्य दृश्य होना चाहिए। इसे सभी FocusArea के बाहर रखा जाना चाहिए। प्रत्येक विंडो में एक FocusParkingView होना चाहिए। यदि आप पहले से ही कार-यूआई-लाइब्रेरी बेस लेआउट का उपयोग कर रहे हैं, जिसमें FocusParkingView शामिल है, तो आपको एक और FocusParkingView जोड़ने की आवश्यकता नहीं है। RotaryPlayground में FocusParkingView का एक उदाहरण नीचे दिखाया गया है।

<FrameLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
   <com.android.car.ui.FocusParkingView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
   <FrameLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"/>
</FrameLayout>

यहां वे कारण दिए गए हैं जिनकी आपको FocusParkingView आवश्यकता है:

  1. जब फोकस किसी अन्य विंडो में सेट किया जाता है तो एंड्रॉइड स्वचालित रूप से फोकस साफ़ नहीं करता है। यदि आप पिछली विंडो में फ़ोकस साफ़ करने का प्रयास करते हैं, तो एंड्रॉइड उस विंडो में एक दृश्य को फिर से फ़ोकस करता है, जिसके परिणामस्वरूप दो विंडो एक साथ फ़ोकस हो जाती हैं। प्रत्येक विंडो में FocusParkingView जोड़ने से यह समस्या ठीक हो सकती है। यह दृश्य पारदर्शी है और इसका डिफ़ॉल्ट फोकस हाइलाइट अक्षम है, ताकि यह उपयोगकर्ता के लिए अदृश्य हो, चाहे वह फोकस हो या नहीं। यह फोकस ले सकता है ताकि RotaryService फोकस हाइलाइट को हटाने के लिए फोकस को उस पर पार्क कर सके।
  2. यदि वर्तमान विंडो में केवल एक FocusArea है, तो FocusArea में नियंत्रक को घुमाने से RotaryService फोकस को दाईं ओर के दृश्य से बाईं ओर के दृश्य में ले जाती है (और इसके विपरीत)। इस दृश्य को प्रत्येक विंडो में जोड़ने से समस्या ठीक हो सकती है। जब RotaryService निर्धारित करता है कि फोकस लक्ष्य एक FocusParkingView है, तो यह निर्धारित कर सकता है कि एक रैप-अराउंड होने वाला है, जिस बिंदु पर यह फोकस को न हिलाकर रैप-अराउंड से बचता है।
  3. जब रोटरी कंट्रोल एक ऐप लॉन्च करता है, तो एंड्रॉइड पहले फोकस करने योग्य दृश्य पर ध्यान केंद्रित करता है, जो हमेशा FocusParkingView है। FocusParkingView फोकस करने के लिए इष्टतम दृश्य निर्धारित करता है और फिर फोकस लागू करता है।

ध्यान केंद्रित करने योग्य दृश्य

RotaryService एंड्रॉइड फ्रेमवर्क के व्यू फोकस की मौजूदा अवधारणा पर आधारित है, जो तब से है जब फोन में भौतिक कीबोर्ड और डी-पैड होते थे। मौजूदा android:nextFocusForward विशेषता को रोटरी के लिए पुन: उपयोग किया गया है ( FocusArea अनुकूलन देखें), लेकिन android:nextFocusLeft , android:nextFocusRight , android:nextFocusUp , और android:nextFocusDown नहीं हैं।

RotaryService केवल उन विचारों पर ध्यान केंद्रित करती है जो ध्यान केंद्रित करने योग्य हों। कुछ दृश्य, जैसे Button , आमतौर पर ध्यान केंद्रित करने योग्य होते हैं। अन्य, जैसे TextView s और ViewGroup s, आमतौर पर नहीं होते हैं। क्लिक करने योग्य दृश्य स्वचालित रूप से फ़ोकस करने योग्य होते हैं और जब उनके पास क्लिक श्रोता होता है तो दृश्य स्वचालित रूप से क्लिक करने योग्य होते हैं। यदि इस स्वचालित तर्क के परिणामस्वरूप वांछित फोकसबिलिटी आती है, तो आपको दृश्य की फोकसबिलिटी को स्पष्ट रूप से सेट करने की आवश्यकता नहीं है। यदि स्वचालित तर्क के परिणामस्वरूप वांछित फ़ोकसबिलिटी नहीं मिलती है, android:focusable विशेषता को true या false पर सेट करें, या प्रोग्रामेटिक रूप से View.setFocusable(boolean) के साथ दृश्य की फ़ोकसबिलिटी सेट करें। RotaryService को इस पर ध्यान केंद्रित करने के लिए, एक दृश्य को निम्नलिखित आवश्यकताओं को पूरा करना होगा:

  • फ़ोकस करने योग्य
  • सक्रिय
  • दृश्यमान
  • चौड़ाई और ऊंचाई के लिए गैर-शून्य मान रखें

यदि कोई दृश्य इन सभी आवश्यकताओं को पूरा नहीं करता है, उदाहरण के लिए फोकस करने योग्य लेकिन अक्षम बटन, तो उपयोगकर्ता उस पर ध्यान केंद्रित करने के लिए रोटरी नियंत्रण का उपयोग नहीं कर सकता है। यदि आप अक्षम दृश्यों पर ध्यान केंद्रित करना चाहते हैं, तो यह संकेत दिए बिना कि एंड्रॉइड को इसे अक्षम मानना ​​चाहिए, यह नियंत्रित करने के लिए android:state_enabled के बजाय एक कस्टम स्थिति का उपयोग करने पर विचार करें कि दृश्य कैसा दिखाई देता है। आपका ऐप उपयोगकर्ता को सूचित कर सकता है कि टैप करने पर दृश्य क्यों अक्षम हो जाता है। अगला भाग बताता है कि यह कैसे करना है।

कस्टम स्थिति

एक कस्टम स्थिति जोड़ने के लिए:

  1. अपने दृश्य में एक कस्टम विशेषता जोड़ने के लिए। उदाहरण के लिए, CustomView व्यू क्लास में एक state_rotary_enabled कस्टम स्थिति जोड़ने के लिए, उपयोग करें:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. इस स्थिति को ट्रैक करने के लिए, एक्सेसर विधियों के साथ अपने दृश्य में एक इंस्टेंस वेरिएबल जोड़ें:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. जब आपका दृश्य बनाया जाता है तो आपकी विशेषता का मान पढ़ने के लिए:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. अपने व्यू क्लास में, onCreateDrawableState() विधि को ओवरराइड करें और फिर उपयुक्त होने पर कस्टम स्थिति जोड़ें। उदाहरण के लिए:
    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mRotaryEnabled) extraSpace++;
        int[] drawableState = super.onCreateDrawableState(extraSpace);
        if (mRotaryEnabled) {
            mergeDrawableStates(drawableState, { R.attr.state_rotary_enabled });
        }
        return drawableState;
    }
    
  5. अपने व्यू के क्लिक हैंडलर को उसकी स्थिति के आधार पर अलग-अलग तरीके से निष्पादित करें। उदाहरण के लिए, mRotaryEnabled false होने पर क्लिक हैंडलर कुछ नहीं कर सकता है या यह एक टोस्ट पॉप अप कर सकता है।
  6. बटन को अक्षम दिखाने के लिए, अपने दृश्य की पृष्ठभूमि में, android:state_enabled के बजाय app:state_rotary_enabled उपयोग करें। यदि आपके पास यह पहले से नहीं है, तो आपको जोड़ना होगा:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. यदि आपका दृश्य किसी भी लेआउट में अक्षम है, तो android:enabled="false" app:state_rotary_enabled="false" से बदलें और फिर ऊपर बताए अनुसार app नेमस्पेस जोड़ें।
  8. यदि आपका दृश्य प्रोग्रामेटिक रूप से अक्षम है, तो setEnabled() पर कॉल को setRotaryEnabled() पर कॉल से बदलें।

ध्यानाकर्षण क्षेत्र

नेविगेशन को आसान बनाने और अन्य ऐप्स के साथ सुसंगत रहने के लिए फोकस करने योग्य दृश्यों को ब्लॉक में विभाजित करने के लिए FocusAreas उपयोग करें। उदाहरण के लिए, यदि आपके ऐप में टूलबार है, तो टूलबार आपके बाकी ऐप से अलग FocusArea में होना चाहिए। टैब बार और अन्य नेविगेशन तत्वों को भी बाकी ऐप से अलग किया जाना चाहिए। बड़ी सूचियों में आम तौर पर अपना स्वयं का FocusArea होना चाहिए। यदि नहीं, तो कुछ दृश्यों तक पहुंचने के लिए उपयोगकर्ताओं को पूरी सूची में घूमना होगा।

FocusArea कार-यूआई-लाइब्रेरी में LinearLayout का एक उपवर्ग है। जब यह सुविधा सक्षम होती है, तो FocusArea एक हाइलाइट खींचता है जब उसके किसी वंशज पर ध्यान केंद्रित किया जाता है। अधिक जानने के लिए, फोकस हाइलाइट अनुकूलन देखें।

लेआउट फ़ाइल में नेविगेशन ब्लॉक बनाते समय, यदि आप उस ब्लॉक के लिए एक कंटेनर के रूप में LinearLayout उपयोग करना चाहते हैं, तो इसके बजाय FocusArea उपयोग करें। अन्यथा, ब्लॉक को FocusArea में लपेटें।

किसी FocusArea किसी अन्य FocusArea में घोंसला बनाएं। ऐसा करने से अपरिभाषित नेविगेशन व्यवहार उत्पन्न होता है। सुनिश्चित करें कि सभी फ़ोकस करने योग्य दृश्य FocusArea में निहित हैं।

RotaryPlayground में FocusArea का एक उदाहरण नीचे दिखाया गया है:

<com.android.car.ui.FocusArea
       android:layout_margin="16dp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">
       <EditText
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:singleLine="true">
       </EditText>
   </com.android.car.ui.FocusArea>

FocusArea इस प्रकार काम करता है:

  1. रोटेट और नज क्रियाओं को संभालते समय, RotaryService दृश्य पदानुक्रम में FocusArea के उदाहरणों की तलाश करता है।
  2. रोटेशन ईवेंट प्राप्त करते समय, RotaryService फ़ोकस को दूसरे दृश्य पर ले जाता है जो उसी FocusArea में फ़ोकस ले सकता है।
  3. नज इवेंट प्राप्त करते समय, RotaryService फोकस को दूसरे दृश्य पर ले जाती है जो फोकस को दूसरे (आमतौर पर आसन्न) FocusArea में ले जा सकता है।

यदि आप अपने लेआउट में कोई FocusAreas शामिल नहीं करते हैं, तो मूल दृश्य को एक अंतर्निहित फोकस क्षेत्र के रूप में माना जाता है। उपयोगकर्ता ऐप में नेविगेट करने के लिए धक्का नहीं दे सकता. इसके बजाय, वे सभी फोकस करने योग्य दृश्यों के माध्यम से घूमेंगे, जो संवादों के लिए पर्याप्त हो सकते हैं।

फोकसएरिया अनुकूलन

रोटरी नेविगेशन को अनुकूलित करने के लिए दो मानक दृश्य विशेषताओं का उपयोग किया जा सकता है:

  • android:nextFocusForward ऐप डेवलपर्स को फोकस क्षेत्र में रोटेशन ऑर्डर निर्दिष्ट करने की अनुमति देता है। यह वही विशेषता है जिसका उपयोग कीबोर्ड नेविगेशन के लिए टैब क्रम को नियंत्रित करने के लिए किया जाता है। लूप बनाने के लिए इस विशेषता का उपयोग न करें । इसके बजाय, लूप बनाने के लिए app:wrapAround (नीचे देखें) का उपयोग करें।
  • android:focusedByDefault ऐप डेवलपर्स को विंडो में डिफ़ॉल्ट फोकस दृश्य निर्दिष्ट करने की अनुमति देता है। इस विशेषता और app:defaultFocus (नीचे देखें) का उपयोग एक ही FocusArea में करें।

FocusArea रोटरी नेविगेशन को अनुकूलित करने के लिए कुछ विशेषताओं को भी परिभाषित करता है। अंतर्निहित फोकस क्षेत्रों को इन विशेषताओं के साथ अनुकूलित नहीं किया जा सकता है।

  1. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    app:defaultFocus उपयोग फोकस करने योग्य वंशज दृश्य की आईडी को निर्दिष्ट करने के लिए किया जा सकता है, जिस पर उपयोगकर्ता द्वारा इस FocusArea पर ध्यान केंद्रित किया जाना चाहिए।
  2. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    app:defaultFocusOverridesHistory ऊपर निर्दिष्ट दृश्य पर ध्यान केंद्रित करने के लिए true पर सेट किया जा सकता है, भले ही इतिहास के साथ इस FocusArea में किसी अन्य दृश्य पर ध्यान केंद्रित किया गया हो।
  3. ( एंड्रॉइड 12 )
    फोकस करने योग्य वंशज दृश्य की आईडी निर्दिष्ट करने के लिए app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcut और app:nudgeDownShortcut उपयोग करें, जिस पर उपयोगकर्ता द्वारा किसी दिए गए दिशा में इशारा करने पर ध्यान केंद्रित किया जाना चाहिए। अधिक जानने के लिए, नीचे नज शॉर्टकट की सामग्री देखें।

    ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 में अप्रचलित ) app:nudgeShortcut और app:nudgeShortcutDirection केवल एक नज शॉर्टकट का समर्थन करता है।

  4. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    इस FocusArea में चारों ओर घूमने के लिए रोटेशन को सक्षम करने के लिए, app:wrapAround को true पर सेट किया जा सकता है। इसका उपयोग आम तौर पर तब किया जाता है जब दृश्यों को एक वृत्त या अंडाकार में व्यवस्थित किया जाता है।
  5. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    इस FocusArea में हाइलाइट की पैडिंग को समायोजित करने के लिए, app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontal , और app:highlightPaddingVertical उपयोग करें।
  6. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    नज लक्ष्य खोजने के लिए इस FocusArea की अनुमानित सीमाओं को समायोजित करने के लिए, app:startBoundOffset , app:endBoundOffset , ऐप: app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffset और app:verticalBoundOffset उपयोग करें।
  7. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    दिए गए निर्देशों में आसन्न FocusArea (या क्षेत्रों) की आईडी को स्पष्ट रूप से निर्दिष्ट करने के लिए, app:nudgeLeft , app:nudgeRight , app:nudgeUp , और app:nudgeDown उपयोग करें। इसका उपयोग तब करें जब डिफ़ॉल्ट रूप से उपयोग की जाने वाली ज्यामितीय खोज को वांछित लक्ष्य न मिले।

नडिंग आमतौर पर फोकस एरिया के बीच नेविगेट करती है। लेकिन नज शॉर्टकट के साथ, नज्डिंग कभी-कभी पहले FocusArea भीतर नेविगेट करता है ताकि उपयोगकर्ता को अगले FocusArea पर नेविगेट करने के लिए दो बार नज करना पड़े। नज शॉर्टकट तब उपयोगी होते हैं जब FocusArea एक लंबी सूची होती है जिसके बाद फ़्लोटिंग एक्शन बटन होता है , जैसा कि नीचे दिए गए उदाहरण में है:

नज शॉर्टकट
चित्र 3. नज शॉर्टकट

नज शॉर्टकट के बिना, उपयोगकर्ता को FAB तक पहुंचने के लिए पूरी सूची में घूमना होगा।

फोकस हाइलाइट अनुकूलन

जैसा कि ऊपर बताया गया है, RotaryService एंड्रॉइड फ्रेमवर्क की व्यू फोकस की मौजूदा अवधारणा पर आधारित है। जब उपयोगकर्ता घूमता है और कुहनी मारता है, RotaryService फोकस को चारों ओर ले जाता है, एक दृश्य पर ध्यान केंद्रित करता है और दूसरे पर ध्यान केंद्रित करता है। एंड्रॉइड में, जब किसी दृश्य पर ध्यान केंद्रित किया जाता है, तो दृश्य:

  • अपना स्वयं का फोकस हाइलाइट निर्दिष्ट किया है, एंड्रॉइड दृश्य का फोकस हाइलाइट खींचता है।
  • फोकस हाइलाइट निर्दिष्ट नहीं करता है, और डिफ़ॉल्ट फोकस हाइलाइट अक्षम नहीं है, एंड्रॉइड दृश्य के लिए डिफ़ॉल्ट फोकस हाइलाइट खींचता है।

स्पर्श के लिए डिज़ाइन किए गए ऐप्स आमतौर पर उचित फ़ोकस हाइलाइट्स निर्दिष्ट नहीं करते हैं।

डिफ़ॉल्ट फोकस हाइलाइट एंड्रॉइड फ्रेमवर्क द्वारा प्रदान किया जाता है और इसे OEM द्वारा ओवरराइड किया जा सकता है। ऐप डेवलपर्स को यह तब प्राप्त होता है जब वे जिस थीम का उपयोग कर रहे हैं वह Theme.DeviceDefault से ली गई है।

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

किसी दृश्य के लिए एक कस्टम फोकस हाइलाइट निर्दिष्ट करने के लिए, दृश्य की पृष्ठभूमि या अग्रभूमि को खींचने योग्य में बदलें जो दृश्य पर केंद्रित होने पर भिन्न हो। आमतौर पर, आप पृष्ठभूमि बदल देंगे। निम्नलिखित ड्रॉएबल, यदि एक वर्ग दृश्य के लिए पृष्ठभूमि के रूप में उपयोग किया जाता है, तो एक गोल फोकस हाइलाइट उत्पन्न होता है:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_focused="true" android:state_pressed="true">
      <shape android:shape="oval">
         <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color"/>
         <stroke
            android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width"
            android:color="@color/car_ui_rotary_focus_pressed_stroke_color"/>
      </shape>
   </item>
   <item android:state_focused="true">
      <shape android:shape="oval">
         <solid android:color="@color/car_ui_rotary_focus_fill_color"/>
         <stroke
            android:width="@dimen/car_ui_rotary_focus_stroke_width"
            android:color="@color/car_ui_rotary_focus_stroke_color"/>
      </shape>
   </item>
   <item>
      <ripple...>
         ...
      </ripple>
   </item>
</selector>

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

बोल्ड संसाधनों के लिए डिफ़ॉल्ट मान
चित्र 4. बोल्ड संसाधनों के लिए डिफ़ॉल्ट मान

इसके अलावा, जब किसी बटन को उपयोगकर्ता के ध्यान में लाने के लिए एक ठोस पृष्ठभूमि रंग दिया जाता है, तो एक कस्टम फोकस हाइलाइट की आवश्यकता होती है, जैसा कि नीचे दिए गए उदाहरण में है। इससे फोकस हाइलाइट को देखना मुश्किल हो सकता है। इस स्थिति में, द्वितीयक रंगों का उपयोग करके एक कस्टम फोकस हाइलाइट निर्दिष्ट करें:

ठोस पृष्ठभूमि रंग
  • ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • ( एंड्रॉइड 12 )
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

उदाहरण के लिए:

फोकस किया गया, दबाया नहीं गयाकेंद्रित, दबाया हुआ
फोकस किया गया, दबाया नहीं गया केंद्रित, दबाया हुआ

रोटरी स्क्रॉलिंग

यदि आपका ऐप RecyclerView s का उपयोग करता है, तो आपको इसके बजाय CarUiRecyclerView s का उपयोग करना चाहिए। यह सुनिश्चित करता है कि आपका यूआई दूसरों के साथ सुसंगत है क्योंकि OEM का अनुकूलन सभी CarUiRecyclerView s पर लागू होता है।

यदि आपकी सूची के सभी तत्व फोकस करने योग्य हैं, तो आपको कुछ और करने की आवश्यकता नहीं है। रोटरी नेविगेशन सूची में तत्वों के माध्यम से फोकस को स्थानांतरित करता है और नए केंद्रित तत्व को दृश्यमान बनाने के लिए सूची स्क्रॉल करता है।

( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
यदि फ़ोकस करने योग्य और फ़ोकस करने योग्य तत्वों का मिश्रण है, या यदि सभी तत्व फ़ोकस करने योग्य नहीं हैं, तो आप रोटरी स्क्रॉलिंग सक्षम कर सकते हैं, जो उपयोगकर्ता को फ़ोकस करने योग्य आइटम को छोड़े बिना सूची में धीरे-धीरे स्क्रॉल करने के लिए रोटरी नियंत्रक का उपयोग करने की अनुमति देता है। रोटरी स्क्रॉलिंग सक्षम करने के लिए, app:rotaryScrollEnabled विशेषता को true पर सेट करें।

( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
आप CarUiUtils में setRotaryScrollEnabled() विधि से av CarUiRecyclerView सहित किसी भी स्क्रॉल करने योग्य दृश्य में रोटरी स्क्रॉलिंग सक्षम कर सकते हैं। यदि आप ऐसा करते हैं, तो आपको यह करना होगा:

  • स्क्रॉल करने योग्य दृश्य को फ़ोकस करने योग्य बनाएं ताकि उस पर तब फ़ोकस किया जा सके जब उसका कोई भी फ़ोकस करने योग्य वंशज दृश्य दिखाई न दे,
  • setDefaultFocusHighlightEnabled(false) पर कॉल करके स्क्रॉल करने योग्य दृश्य पर डिफ़ॉल्ट फोकस हाइलाइट को अक्षम करें ताकि स्क्रॉल करने योग्य दृश्य केंद्रित न हो,
  • setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) पर कॉल करके सुनिश्चित करें कि स्क्रॉल करने योग्य दृश्य उसके वंशजों से पहले केंद्रित है।
  • स्क्रॉल करने की दूरी और दिशा (चिह्न के माध्यम से) इंगित करने के लिए SOURCE_ROTARY_ENCODER और AXIS_VSCROLL या AXIS_HSCROLL के साथ MotionEvents सुनें।

जब CarUiRecyclerView पर रोटरी स्क्रॉलिंग सक्षम की जाती है और उपयोगकर्ता उस क्षेत्र में घूमता है जहां कोई फोकस करने योग्य दृश्य मौजूद नहीं है, तो स्क्रॉलबार ग्रे से नीले रंग में बदल जाता है, जैसे कि यह इंगित करने के लिए कि स्क्रॉलबार केंद्रित है। यदि आप चाहें तो आप समान प्रभाव लागू कर सकते हैं।

MotionEvents स्रोत को छोड़कर, माउस पर स्क्रॉल व्हील द्वारा उत्पन्न किए गए समान ही होते हैं।

प्रत्यक्ष हेरफेर मोड

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

डीएम को दो तरीकों में से एक में लागू करें। यदि आपको केवल रोटेशन को संभालने की आवश्यकता है और जिस दृश्य में आप हेरफेर करना चाहते हैं वह ACTION_SCROLL_FORWARD और ACTION_SCROLL_BACKWARD AccessibilityEvent पर उचित रूप से प्रतिक्रिया करता है, तो सरल तंत्र का उपयोग करें। अन्यथा, उन्नत तंत्र का उपयोग करें.

सिस्टम विंडोज़ में सरल तंत्र ही एकमात्र विकल्प है; ऐप्स किसी भी तंत्र का उपयोग कर सकते हैं।

सरल तंत्र

( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 )
आपके ऐप को DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) कॉल करना चाहिए। RotaryService यह पहचानती है कि उपयोगकर्ता DM मोड में है और जब उपयोगकर्ता दृश्य केंद्रित होने पर केंद्र बटन दबाता है तो DM मोड में प्रवेश करता है। DM मोड में होने पर, रोटेशन ACTION_SCROLL_FORWARD या ACTION_SCROLL_BACKWARD निष्पादित करते हैं और जब उपयोगकर्ता बैक बटन दबाता है तो DM मोड से बाहर निकल जाता है। डीएम मोड में प्रवेश करने और बाहर निकलने पर सरल तंत्र दृश्य की चयनित स्थिति को टॉगल करता है।

यह दृश्य संकेत प्रदान करने के लिए कि उपयोगकर्ता डीएम मोड में है, चयनित होने पर अपना दृश्य अलग दिखाएं। उदाहरण के लिए, जब android:state_selected true हो तो पृष्ठभूमि बदलें।

उन्नत तंत्र

ऐप यह निर्धारित करता है कि RotaryService कब डीएम मोड में प्रवेश करती है और कब बाहर निकलती है। सुसंगत उपयोगकर्ता अनुभव के लिए, डीएम दृश्य पर ध्यान केंद्रित करते हुए केंद्र बटन को दबाने पर डीएम मोड में प्रवेश करना चाहिए और बैक बटन को डीएम मोड से बाहर निकलना चाहिए। यदि केंद्र बटन और/या नज का उपयोग नहीं किया जाता है, तो वे डीएम मोड से बाहर निकलने के वैकल्पिक तरीके हो सकते हैं। मैप्स जैसे ऐप्स के लिए, डीएम मोड में प्रवेश करने के लिए डीएम का प्रतिनिधित्व करने वाले बटन का उपयोग किया जा सकता है।

उन्नत डीएम मोड का समर्थन करने के लिए, एक दृश्य:

  1. ( एंड्रॉइड 11 क्यूपीआर3, एंड्रॉइड 11 कार, एंड्रॉइड 12 ) डीएम मोड में प्रवेश करने के लिए एक KEYCODE_DPAD_CENTER इवेंट को सुनना चाहिए और डीएम मोड से बाहर निकलने के लिए एक KEYCODE_BACK इवेंट को सुनना चाहिए, प्रत्येक मामले में DirectManipulationHelper.enableDirectManipulationMode() को कॉल करना चाहिए। इन घटनाओं को सुनने के लिए, निम्नलिखित में से कोई एक कार्य करें:
    • एक OnKeyListener पंजीकृत करें।
    • या,
    • दृश्य का विस्तार करें और फिर इसकी dispatchKeyEvent() विधि को ओवरराइड करें।
  2. यदि दृश्य को नज को संभालना चाहिए तो उसे नज घटनाओं ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT , या KEYCODE_DPAD_RIGHT ) को सुनना चाहिए।
  3. यदि दृश्य रोटेशन को संभालना चाहता है तो उसे MotionEvent को सुनना चाहिए और AXIS_SCROLL में रोटेशन गिनती प्राप्त करनी चाहिए। इसे करने बहुत सारे तरीके हैं:
    1. एक OnGenericMotionListener पंजीकृत करें।
    2. दृश्य का विस्तार करें और इसकी dispatchTouchEvent() विधि को ओवरराइड करें।
  4. डीएम मोड में फंसने से बचने के लिए, डीएम मोड से बाहर निकलना जरूरी है जब दृश्य जिस फ्रैगमेंट या गतिविधि से संबंधित हो वह इंटरैक्टिव न हो।
  5. यह इंगित करने के लिए एक दृश्य संकेत प्रदान करना चाहिए कि दृश्य डीएम मोड में है।

मानचित्र को पैन और ज़ूम करने के लिए डीएम मोड का उपयोग करने वाले कस्टम दृश्य का एक नमूना नीचे दिया गया है:

/** Whether this view is in DM mode. */
private boolean mInDirectManipulationMode;

/** Initializes the view. Called by the constructors. */ private void init() { setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK events. case KeyEvent.KEYCODE_DPAD_CENTER: if (!mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = true; DirectManipulationHelper.enableDirectManipulationMode(this, true); setSelected(true); // visually indicate DM mode } return true; case KeyEvent.KEYCODE_BACK: if (mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); setSelected(false); } return true; // Consume controller nudge events only when in DM mode. // When in DM mode, nudges pan the map. case KeyEvent.KEYCODE_DPAD_UP: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, -10f); return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, 10f); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(-10f, 0f); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(10f, 0f); return true; // Don't consume other key events. default: return false; } });
// When in DM mode, rotation zooms the map. setOnGenericMotionListener(((view, motionEvent) -> { if (!mInDirectManipulationMode) return false; float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); zoom(10 * scroll); return true; })); }
@Override public void onPause() { if (mInDirectManipulationMode) { // To ensure that the user doesn't get stuck in DM mode, disable DM mode // when the fragment is not interactive (e.g., a dialog shows up). mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); } super.onPause(); }

अधिक उदाहरण RotaryPlayground प्रोजेक्ट में पाए जा सकते हैं।

गतिविधि दृश्य

गतिविधि दृश्य का उपयोग करते समय:

  • ActivityView फोकस करने योग्य नहीं होना चाहिए।
  • ( Android 11 QPR3, Android 11 कार, Android 11 में बंद कर दिया गया )
    ActivityView की सामग्री में पहले फोकस करने योग्य दृश्य के रूप में FocusParkingView होना चाहिए, और इसकी app:shouldRestoreFocus विशेषता false होनी चाहिए।
  • ActivityView की सामग्री में कोई android:focusByDefault दृश्य नहीं होना चाहिए।

उपयोगकर्ता के लिए, एक्टिविटी व्यू का नेविगेशन पर कोई प्रभाव नहीं होना चाहिए, सिवाय इसके कि फोकस क्षेत्र एक्टिविटी व्यू का विस्तार नहीं कर सकते। दूसरे शब्दों में, आपके पास एक भी फोकस क्षेत्र नहीं हो सकता है जिसमें ActivityView अंदर और बाहर सामग्री हो। यदि आप अपने ActivityView में कोई फोकसएरिया नहीं जोड़ते हैं, तो ActivityView में दृश्य पदानुक्रम की जड़ को एक अंतर्निहित फोकस क्षेत्र माना जाता है।

बटन जो दबाए रखने पर काम करते हैं

क्लिक करने पर अधिकांश बटन कुछ क्रिया उत्पन्न करते हैं। इसके बजाय कुछ बटन दबाए रखने पर काम करते हैं। उदाहरण के लिए, फास्ट फॉरवर्ड और रिवाइंड बटन आमतौर पर दबाए जाने पर काम करते हैं। ऐसे बटनों को रोटरी का समर्थन करने के लिए, KEYCODE_DPAD_CENTER KeyEvents को निम्नानुसार सुनें:

mButton.setOnKeyListener((v, keyCode, event) ->
{
    if (keyCode != KEYCODE_DPAD_CENTER) {
        return false;
    }
    if (event.getAction() == ACTION_DOWN) {
        mButton.setPressed(true);
        mHandler.post(mRunnable);
    } else {
        mButton.setPressed(false);
        mHandler.removeCallbacks(mRunnable);
    }
    return true;
});

जिसमें mRunnable एक कार्रवाई करता है (जैसे रिवाइंडिंग) और देरी के बाद चलने के लिए खुद को शेड्यूल करता है।

स्पर्श मोड

उपयोगकर्ता कार में हेड यूनिट के साथ दो तरीकों से बातचीत करने के लिए रोटरी कंट्रोलर का उपयोग कर सकते हैं, या तो रोटरी कंट्रोलर का उपयोग करके या स्क्रीन को छूकर। रोटरी नियंत्रक का उपयोग करते समय, फोकस करने योग्य दृश्यों में से एक को हाइलाइट किया जाता है। स्क्रीन को छूने पर कोई फोकस हाइलाइट दिखाई नहीं देता। उपयोगकर्ता किसी भी समय इन इनपुट मोड के बीच स्विच कर सकता है:

  • रोटरी → स्पर्श. जब उपयोगकर्ता स्क्रीन को छूता है, तो फोकस हाइलाइट गायब हो जाता है।
  • स्पर्श करें → रोटरी. जब उपयोगकर्ता केंद्र बटन को धक्का देता है, घुमाता है या दबाता है, तो फोकस हाइलाइट दिखाई देता है।

बैक और होम बटन का इनपुट मोड पर कोई प्रभाव नहीं पड़ता है।

एंड्रॉइड की टच मोड की मौजूदा अवधारणा पर रोटरी पिग्गीबैक। उपयोगकर्ता किस इनपुट मोड का उपयोग कर रहा है यह निर्धारित करने के लिए आप View.isInTouchMode() का उपयोग कर सकते हैं। परिवर्तनों को सुनने के लिए आप OnTouchModeChangeListener का उपयोग कर सकते हैं। हालाँकि इसका उपयोग आपके उपयोगकर्ता इंटरफ़ेस को वर्तमान इनपुट मोड के लिए अनुकूलित करने के लिए किया जा सकता है, लेकिन किसी भी बड़े बदलाव से बचें क्योंकि वे परेशान करने वाले हो सकते हैं।

समस्या निवारण

स्पर्श के लिए डिज़ाइन किए गए ऐप में, नेस्टेड फ़ोकस करने योग्य दृश्य होना आम बात है। उदाहरण के लिए, ImageButton के आसपास एक FrameLayout हो सकता है, जो दोनों फोकस करने योग्य हैं। यह स्पर्श के लिए कोई नुकसान नहीं पहुंचाता है लेकिन इसके परिणामस्वरूप रोटरी के लिए खराब उपयोगकर्ता अनुभव हो सकता है क्योंकि उपयोगकर्ता को अगले इंटरैक्टिव दृश्य पर जाने के लिए नियंत्रक को दो बार घुमाना होगा। एक अच्छे उपयोगकर्ता अनुभव के लिए, Google आपको बाहरी दृश्य या आंतरिक दृश्य को फोकस करने योग्य बनाने की सलाह देता है, लेकिन दोनों को नहीं।

यदि रोटरी नियंत्रक के माध्यम से दबाए जाने पर कोई बटन या स्विच फोकस खो देता है, तो इनमें से एक स्थिति लागू हो सकती है:

  • बटन दबाए जाने के कारण बटन या स्विच अक्षम किया जा रहा है (संक्षेप में या अनिश्चित काल के लिए)। किसी भी स्थिति में, इसे संबोधित करने के दो तरीके हैं:
    • android:enabled स्थिति को true के रूप में छोड़ दें और कस्टम स्थिति में वर्णित अनुसार बटन या स्विच को ग्रे करने के लिए एक कस्टम स्थिति का उपयोग करें।
    • बटन या स्विच को घेरने के लिए एक कंटेनर का उपयोग करें और बटन या स्विच के बजाय कंटेनर को फोकस करने योग्य बनाएं। (क्लिक श्रोता कंटेनर पर होना चाहिए।)
  • बटन या स्विच बदला जा रहा है. उदाहरण के लिए, जब बटन दबाया जाता है या स्विच टॉगल किया जाता है तो की गई कार्रवाई उपलब्ध क्रियाओं को ताज़ा कर सकती है, जिससे मौजूदा बटनों को बदलने के लिए नए बटन बन सकते हैं। इसे संबोधित करने के दो तरीके हैं:
    • नया बटन या स्विच बनाने के बजाय, मौजूदा बटन या स्विच का आइकन और/या टेक्स्ट सेट करें।
    • जैसा कि ऊपर बताया गया है, बटन या स्विच के चारों ओर एक फोकस करने योग्य कंटेनर जोड़ें।

रोटरी खेल का मैदान

RotaryPlayground रोटरी के लिए एक संदर्भ ऐप है। अपने ऐप्स में रोटरी सुविधाओं को एकीकृत करने का तरीका जानने के लिए इसका उपयोग करें। RotaryPlayground एमुलेटर बिल्ड और एंड्रॉइड ऑटोमोटिव ओएस (एएओएस) चलाने वाले उपकरणों के बिल्ड में शामिल किया गया है।

  • RotaryPlayground रिपॉजिटरी: packages/apps/Car/tests/RotaryPlayground/
  • संस्करण: Android 11 QPR3, Android 11 Car, और Android 12

RotaryPlayground ऐप बाईं ओर निम्नलिखित टैब दिखाता है:

  • पत्ते। फोकस क्षेत्रों के आसपास नेविगेट करने का परीक्षण करें, फोकस न करने योग्य तत्वों और टेक्स्ट इनपुट को छोड़ दें।
  • प्रत्यक्ष हेरफेर. परीक्षण विजेट जो सरल और उन्नत प्रत्यक्ष हेरफेर मोड का समर्थन करते हैं। यह टैब विशेष रूप से ऐप विंडो के भीतर सीधे हेरफेर के लिए है।
  • Sys यूआई हेरफेर। परीक्षण विजेट जो सिस्टम विंडो में प्रत्यक्ष हेरफेर का समर्थन करते हैं जहां केवल सरल प्रत्यक्ष हेरफेर मोड समर्थित है।
  • ग्रिड। स्क्रॉलिंग के साथ z-पैटर्न रोटरी नेविगेशन का परीक्षण करें।
  • अधिसूचना। हेड-अप नोटिफिकेशन के अंदर और बाहर जाने का परीक्षण करें।
  • स्क्रॉल करें. फोकस करने योग्य और फोकस न करने योग्य सामग्री के मिश्रण के माध्यम से स्क्रॉलिंग का परीक्षण करें।
  • वेबव्यू. WebView में लिंक के माध्यम से नेविगेट करने का परीक्षण करें।
  • कस्टम FocusArea . FocusArea अनुकूलन का परीक्षण करें:
    • चारों ओर लपेट दो।
    • android:focusedByDefault और app:defaultFocus
    • .
    • स्पष्ट संकेत लक्ष्य.
    • शॉर्टकट कुहनी मारो.
    • FocusArea जिसमें कोई फ़ोकस करने योग्य दृश्य नहीं है।
,

निम्नलिखित सामग्री ऐप डेवलपर्स के लिए है।

अपने ऐप को रोटरी समर्थन देने के लिए, आपको यह करना होगा:

  1. संबंधित गतिविधि लेआउट में FocusParkingView रखें।
  2. उन विचारों को सुनिश्चित करें जो ध्यान केंद्रित करने योग्य हैं (या नहीं हैं)।
  3. FocusParkingView को छोड़कर, अपने सभी फोकस करने योग्य दृश्यों को लपेटने के लिए FocusArea का उपयोग करें।

रोटरी-सक्षम ऐप्स विकसित करने के लिए अपना वातावरण स्थापित करने के बाद, इनमें से प्रत्येक कार्य का विवरण नीचे दिया गया है।

एक रोटरी नियंत्रक स्थापित करें

इससे पहले कि आप रोटरी-सक्षम ऐप्स विकसित करना शुरू करें, आपको या तो एक रोटरी नियंत्रक या एक स्टैंड-इन की आवश्यकता होगी। आपके पास नीचे वर्णित विकल्प हैं।

एम्यूलेटर

source build/envsetup.sh && lunch car_x86_64-userdebug
m -j
emulator -wipe-data -no-snapshot -writable-system

आप aosp_car_x86_64-userdebug भी उपयोग कर सकते हैं।

अनुकरणित रोटरी नियंत्रक तक पहुँचने के लिए:

  1. टूलबार के नीचे तीन बिंदुओं पर टैप करें:

    एक्सेस एम्युलेटेड रोटरी कंट्रोलर
    चित्र 1. एक्सेस एम्युलेटेड रोटरी नियंत्रक
  2. विस्तारित नियंत्रण विंडो में कार रोटरी का चयन करें:

    कार रोटरी का चयन करें
    चित्र 2. कार रोटरी का चयन करें

यूएसबी कीबोर्ड

  • अपने डिवाइस में एक यूएसबी कीबोर्ड प्लग करें जो एंड्रॉइड ऑटोमोटिव ओएस (एएओएस) चलाता है, कुछ मामलों में, यह ऑन-स्क्रीन कीबोर्ड को प्रदर्शित होने से रोकता है।
  • userdebug या eng बिल्ड का उपयोग करें।
  • मुख्य ईवेंट फ़िल्टरिंग सक्षम करें:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • प्रत्येक क्रिया के लिए संबंधित कुंजी ढूंढने के लिए नीचे दी गई तालिका देखें:
    चाबी रोटरी क्रिया
    क्यू वामावर्त स्थिति में घुमाएं
    घड़ी की सुई की दिशा में घुमाओ
    कुहनी बाएँ
    डी दाहिनी ओर इशारा करें
    डब्ल्यू कुहनी ऊपर उठाओ
    एस नीचे झुको
    एफ या अल्पविराम केंद्र बटन
    आर या Esc पिछला बटन

एडीबी आदेश

आप रोटरी इनपुट इवेंट को इंजेक्ट करने के लिए car_service कमांड का उपयोग कर सकते हैं। ये कमांड एंड्रॉइड ऑटोमोटिव ओएस (एएओएस) चलाने वाले डिवाइस या एमुलेटर पर चलाए जा सकते हैं।

कार_सेवा आदेश रोटरी इनपुट
adb shell cmd car_service inject-rotary वामावर्त स्थिति में घुमाएं
adb shell cmd car_service inject-rotary -c true घड़ी की सुई की दिशा में घुमाओ
adb shell cmd car_service inject-rotary -dt 100 50 कई बार वामावर्त घुमाएँ (100 एमएस पहले और 50 एमएस पहले)
adb shell cmd car_service inject-key 282 कुहनी बाएँ
adb shell cmd car_service inject-key 283 दाहिनी ओर इशारा करें
adb shell cmd car_service inject-key 280 कुहनी ऊपर उठाओ
adb shell cmd car_service inject-key 281 नीचे झुको
adb shell cmd car_service inject-key 23 केंद्र बटन क्लिक करें
adb shell input keyevent inject-key 4 बैक बटन क्लिक करें

OEM रोटरी नियंत्रक

जब आपका रोटरी कंट्रोलर हार्डवेयर चालू और चालू हो, तो यह सबसे यथार्थवादी विकल्प है। यह तेज़ रोटेशन के परीक्षण के लिए विशेष रूप से उपयोगी है।

फोकसपार्किंग दृश्य

FocusParkingView कार यूआई लाइब्रेरी (कार-यूआई-लाइब्रेरी) में एक पारदर्शी दृश्य है। RotaryService इसका उपयोग रोटरी नियंत्रक नेविगेशन का समर्थन करने के लिए करता है। FocusParkingView लेआउट में पहला फोकस करने योग्य दृश्य होना चाहिए। इसे सभी FocusArea के बाहर रखा जाना चाहिए। प्रत्येक विंडो में एक FocusParkingView होना चाहिए। यदि आप पहले से ही कार-यूआई-लाइब्रेरी बेस लेआउट का उपयोग कर रहे हैं, जिसमें FocusParkingView शामिल है, तो आपको एक और FocusParkingView जोड़ने की आवश्यकता नहीं है। RotaryPlayground में FocusParkingView का एक उदाहरण नीचे दिखाया गया है।

<FrameLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
   <com.android.car.ui.FocusParkingView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
   <FrameLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"/>
</FrameLayout>

यहां वे कारण दिए गए हैं जिनकी आपको FocusParkingView आवश्यकता है:

  1. जब फोकस किसी अन्य विंडो में सेट किया जाता है तो एंड्रॉइड स्वचालित रूप से फोकस साफ़ नहीं करता है। यदि आप पिछली विंडो में फ़ोकस साफ़ करने का प्रयास करते हैं, तो एंड्रॉइड उस विंडो में एक दृश्य को फिर से फ़ोकस करता है, जिसके परिणामस्वरूप दो विंडो एक साथ फ़ोकस हो जाती हैं। प्रत्येक विंडो में FocusParkingView जोड़ने से यह समस्या ठीक हो सकती है। यह दृश्य पारदर्शी है और इसका डिफ़ॉल्ट फोकस हाइलाइट अक्षम है, ताकि यह उपयोगकर्ता के लिए अदृश्य हो, चाहे वह फोकस हो या नहीं। यह फोकस ले सकता है ताकि RotaryService फोकस हाइलाइट को हटाने के लिए फोकस को उस पर पार्क कर सके।
  2. यदि वर्तमान विंडो में केवल एक FocusArea है, तो FocusArea में नियंत्रक को घुमाने से RotaryService फोकस को दाईं ओर के दृश्य से बाईं ओर के दृश्य में ले जाती है (और इसके विपरीत)। इस दृश्य को प्रत्येक विंडो में जोड़ने से समस्या ठीक हो सकती है। जब RotaryService निर्धारित करता है कि फोकस लक्ष्य एक FocusParkingView है, तो यह निर्धारित कर सकता है कि एक रैप-अराउंड होने वाला है, जिस बिंदु पर यह फोकस को न हिलाकर रैप-अराउंड से बचता है।
  3. जब रोटरी कंट्रोल एक ऐप लॉन्च करता है, तो एंड्रॉइड पहले फोकस करने योग्य दृश्य पर ध्यान केंद्रित करता है, जो हमेशा FocusParkingView है। FocusParkingView फोकस करने के लिए इष्टतम दृश्य निर्धारित करता है और फिर फोकस लागू करता है।

ध्यान केंद्रित करने योग्य दृश्य

RotaryService एंड्रॉइड फ्रेमवर्क के व्यू फोकस की मौजूदा अवधारणा पर आधारित है, जो तब से है जब फोन में भौतिक कीबोर्ड और डी-पैड होते थे। मौजूदा android:nextFocusForward विशेषता को रोटरी के लिए पुन: उपयोग किया गया है ( FocusArea अनुकूलन देखें), लेकिन android:nextFocusLeft , android:nextFocusRight , android:nextFocusUp , और android:nextFocusDown नहीं हैं।

RotaryService केवल उन विचारों पर ध्यान केंद्रित करती है जो ध्यान केंद्रित करने योग्य हों। कुछ दृश्य, जैसे Button , आमतौर पर ध्यान केंद्रित करने योग्य होते हैं। अन्य, जैसे TextView s और ViewGroup s, आमतौर पर नहीं होते हैं। क्लिक करने योग्य दृश्य स्वचालित रूप से फ़ोकस करने योग्य होते हैं और जब उनके पास क्लिक श्रोता होता है तो दृश्य स्वचालित रूप से क्लिक करने योग्य होते हैं। यदि इस स्वचालित तर्क के परिणामस्वरूप वांछित फोकसबिलिटी आती है, तो आपको दृश्य की फोकसबिलिटी को स्पष्ट रूप से सेट करने की आवश्यकता नहीं है। यदि स्वचालित तर्क के परिणामस्वरूप वांछित फ़ोकसबिलिटी नहीं मिलती है, android:focusable विशेषता को true या false पर सेट करें, या प्रोग्रामेटिक रूप से View.setFocusable(boolean) के साथ दृश्य की फ़ोकसबिलिटी सेट करें। RotaryService को इस पर ध्यान केंद्रित करने के लिए, एक दृश्य को निम्नलिखित आवश्यकताओं को पूरा करना होगा:

  • फ़ोकस करने योग्य
  • सक्रिय
  • दृश्यमान
  • चौड़ाई और ऊंचाई के लिए गैर-शून्य मान रखें

यदि कोई दृश्य इन सभी आवश्यकताओं को पूरा नहीं करता है, उदाहरण के लिए फोकस करने योग्य लेकिन अक्षम बटन, तो उपयोगकर्ता उस पर ध्यान केंद्रित करने के लिए रोटरी नियंत्रण का उपयोग नहीं कर सकता है। यदि आप अक्षम दृश्यों पर ध्यान केंद्रित करना चाहते हैं, तो यह संकेत दिए बिना कि एंड्रॉइड को इसे अक्षम मानना ​​चाहिए, यह नियंत्रित करने के लिए android:state_enabled के बजाय एक कस्टम स्थिति का उपयोग करने पर विचार करें कि दृश्य कैसा दिखाई देता है। आपका ऐप उपयोगकर्ता को सूचित कर सकता है कि टैप करने पर दृश्य क्यों अक्षम हो जाता है। अगला भाग बताता है कि यह कैसे करना है।

कस्टम स्थिति

एक कस्टम स्थिति जोड़ने के लिए:

  1. अपने दृश्य में एक कस्टम विशेषता जोड़ने के लिए। उदाहरण के लिए, CustomView व्यू क्लास में एक state_rotary_enabled कस्टम स्थिति जोड़ने के लिए, उपयोग करें:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. इस स्थिति को ट्रैक करने के लिए, एक्सेसर विधियों के साथ अपने दृश्य में एक इंस्टेंस वेरिएबल जोड़ें:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. जब आपका दृश्य बनाया जाता है तो आपकी विशेषता का मान पढ़ने के लिए:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. अपने व्यू क्लास में, onCreateDrawableState() विधि को ओवरराइड करें और फिर उपयुक्त होने पर कस्टम स्थिति जोड़ें। उदाहरण के लिए:
    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mRotaryEnabled) extraSpace++;
        int[] drawableState = super.onCreateDrawableState(extraSpace);
        if (mRotaryEnabled) {
            mergeDrawableStates(drawableState, { R.attr.state_rotary_enabled });
        }
        return drawableState;
    }
    
  5. अपने व्यू के क्लिक हैंडलर को उसकी स्थिति के आधार पर अलग-अलग तरीके से निष्पादित करें। उदाहरण के लिए, mRotaryEnabled false होने पर क्लिक हैंडलर कुछ नहीं कर सकता है या यह एक टोस्ट पॉप अप कर सकता है।
  6. बटन को अक्षम दिखाने के लिए, अपने दृश्य की पृष्ठभूमि में, android:state_enabled के बजाय app:state_rotary_enabled उपयोग करें। यदि आपके पास यह पहले से नहीं है, तो आपको जोड़ना होगा:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. यदि आपका दृश्य किसी भी लेआउट में अक्षम है, तो android:enabled="false" app:state_rotary_enabled="false" से बदलें और फिर ऊपर बताए अनुसार app नेमस्पेस जोड़ें।
  8. यदि आपका दृश्य प्रोग्रामेटिक रूप से अक्षम है, तो setEnabled() पर कॉल को setRotaryEnabled() पर कॉल से बदलें।

ध्यानाकर्षण क्षेत्र

नेविगेशन को आसान बनाने और अन्य ऐप्स के साथ सुसंगत रहने के लिए फोकस करने योग्य दृश्यों को ब्लॉक में विभाजित करने के लिए FocusAreas उपयोग करें। उदाहरण के लिए, यदि आपके ऐप में टूलबार है, तो टूलबार आपके बाकी ऐप से अलग FocusArea में होना चाहिए। टैब बार और अन्य नेविगेशन तत्वों को भी बाकी ऐप से अलग किया जाना चाहिए। बड़ी सूचियों में आम तौर पर अपना स्वयं का FocusArea होना चाहिए। यदि नहीं, तो कुछ दृश्यों तक पहुंचने के लिए उपयोगकर्ताओं को पूरी सूची में घूमना होगा।

FocusArea कार-यूआई-लाइब्रेरी में LinearLayout का एक उपवर्ग है। जब यह सुविधा सक्षम होती है, तो FocusArea एक हाइलाइट खींचता है जब उसके किसी वंशज पर ध्यान केंद्रित किया जाता है। अधिक जानने के लिए, फोकस हाइलाइट अनुकूलन देखें।

लेआउट फ़ाइल में नेविगेशन ब्लॉक बनाते समय, यदि आप उस ब्लॉक के लिए एक कंटेनर के रूप में LinearLayout उपयोग करना चाहते हैं, तो इसके बजाय FocusArea उपयोग करें। अन्यथा, ब्लॉक को FocusArea में लपेटें।

किसी FocusArea किसी अन्य FocusArea में घोंसला बनाएं। ऐसा करने से अपरिभाषित नेविगेशन व्यवहार उत्पन्न होता है। सुनिश्चित करें कि सभी फ़ोकस करने योग्य दृश्य FocusArea में निहित हैं।

RotaryPlayground में FocusArea का एक उदाहरण नीचे दिखाया गया है:

<com.android.car.ui.FocusArea
       android:layout_margin="16dp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">
       <EditText
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:singleLine="true">
       </EditText>
   </com.android.car.ui.FocusArea>

FocusArea इस प्रकार काम करता है:

  1. रोटेट और नज क्रियाओं को संभालते समय, RotaryService दृश्य पदानुक्रम में FocusArea के उदाहरणों की तलाश करता है।
  2. रोटेशन ईवेंट प्राप्त करते समय, RotaryService फ़ोकस को दूसरे दृश्य पर ले जाता है जो उसी FocusArea में फ़ोकस ले सकता है।
  3. नज इवेंट प्राप्त करते समय, RotaryService फोकस को दूसरे दृश्य पर ले जाती है जो फोकस को दूसरे (आमतौर पर आसन्न) FocusArea में ले जा सकता है।

यदि आप अपने लेआउट में कोई FocusAreas शामिल नहीं करते हैं, तो मूल दृश्य को एक अंतर्निहित फोकस क्षेत्र के रूप में माना जाता है। उपयोगकर्ता ऐप में नेविगेट करने के लिए धक्का नहीं दे सकता. इसके बजाय, वे सभी फोकस करने योग्य दृश्यों के माध्यम से घूमेंगे, जो संवादों के लिए पर्याप्त हो सकते हैं।

फोकसएरिया अनुकूलन

रोटरी नेविगेशन को अनुकूलित करने के लिए दो मानक दृश्य विशेषताओं का उपयोग किया जा सकता है:

  • android:nextFocusForward APP डेवलपर्स को फोकस क्षेत्र में रोटेशन ऑर्डर निर्दिष्ट करने की अनुमति देता है। यह वही विशेषता है जिसका उपयोग कीबोर्ड नेविगेशन के लिए टैब ऑर्डर को नियंत्रित करने के लिए किया जाता है। लूप बनाने के लिए इस विशेषता का उपयोग न करें । इसके बजाय, app:wrapAround (नीचे देखें)।
  • android:focusedByDefault ऐप डेवलपर्स को विंडो में डिफ़ॉल्ट फोकस दृश्य निर्दिष्ट करने की अनुमति देता है। इस विशेषता और ऐप का उपयोग करें app:defaultFocus (नीचे देखें) एक ही FocusArea में।

FocusArea रोटरी नेविगेशन को अनुकूलित करने के लिए कुछ विशेषताओं को भी परिभाषित करता है। अंतर्निहित फोकस क्षेत्रों को इन विशेषताओं के साथ अनुकूलित नहीं किया जा सकता है।

  1. ( Android 11 QPR3, Android 11 CAR, Android 12 )
    app:defaultFocus उपयोग एक फोकस वंशज दृश्य की ID को निर्दिष्ट करने के लिए किया जा सकता है, जिसे इस बात पर ध्यान केंद्रित किया जाना चाहिए कि उपयोगकर्ता इस FocusArea को नग्न करता है।
  2. ( Android 11 QPR3, Android 11 CAR, Android 12 )
    app:defaultFocusOverridesHistory true पर सेट किया जा सकता है ताकि ऊपर निर्दिष्ट दृश्य को ध्यान में रखा जा सके, भले ही इतिहास के साथ इस FocusArea में एक और दृश्य को इंगित करने के लिए ध्यान केंद्रित किया गया हो।
  3. ( एंड्रॉइड 12 )
    app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcut , और app:nudgeDownShortcut एक फोकस वंशज दृश्य की आईडी निर्दिष्ट करने के लिए, जो किसी दिए गए दिशा में उपयोगकर्ता को नग्न करने पर ध्यान केंद्रित किया जाना चाहिए। अधिक जानने के लिए, नीचे Nudge शॉर्टकट के लिए सामग्री देखें।

    app:nudgeShortcut app:nudgeShortcutDirection

  4. ( Android 11 QPR3, Android 11 CAR, Android 12 )
    रोटेशन को इस FocusArea में चारों ओर लपेटने में सक्षम करने के लिए, app:wrapAround true पर सेट किया जा सकता है। यह आमतौर पर सबसे अधिक उपयोग किया जाता है जब दृश्य एक सर्कल या अंडाकार में व्यवस्थित होते हैं।
  5. ( Android 11 QPR3, Android 11 CAR, Android 12 )
    इस FocusArea में हाइलाइट की पैडिंग को समायोजित करने के लिए, app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontal , और app:highlightPaddingVertical
  6. ( Android 11 QPR3, Android 11 CAR, Android 12 )
    इस FocusArea की कथित सीमा को समायोजित करने के लिए एक nudge लक्ष्य खोजने के लिए, app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffset , और app:verticalBoundOffset
  7. ( Android 11 QPR3, Android 11 CAR, Android 12 )
    दिए गए निर्देशों में एक आसन्न FocusArea (या क्षेत्रों) की आईडी को स्पष्ट रूप से निर्दिष्ट करने के लिए, app:nudgeLeft , app:nudgeRight , app:nudgeUp , और app:nudgeDown । इसका उपयोग करें जब डिफ़ॉल्ट रूप से उपयोग की जाने वाली ज्यामितीय खोज को वांछित लक्ष्य नहीं मिलता है।

आमतौर पर फोकसरीस के बीच नेविगेट करता है। लेकिन न्यूड शॉर्टकट के साथ, कभी -कभी नग्न करना कभी -कभी एक FocusArea के भीतर नेविगेट करता है ताकि उपयोगकर्ता को अगले FocusArea में नेविगेट करने के लिए दो बार नग्न करने की आवश्यकता हो। Nudge शॉर्टकट उपयोगी होते हैं जब एक FocusArea एक लंबी सूची होती है, जिसके बाद एक फ्लोटिंग एक्शन बटन होता है , जैसा कि नीचे दिए गए उदाहरण में होता है:

कुरसी
चित्रा 3. नग शॉर्टकट

Nudge शॉर्टकट के बिना, उपयोगकर्ता को FAB तक पहुंचने के लिए पूरी सूची के माध्यम से घूमना होगा।

फोकस हाइलाइट अनुकूलन

जैसा कि ऊपर उल्लेख किया गया है, RotaryService एंड्रॉइड फ्रेमवर्क की मौजूदा अवधारणा पर ध्यान केंद्रित करता है। जब उपयोगकर्ता घूमता है और नग्नता करता है, RotaryService एक दृश्य को ध्यान केंद्रित करते हुए और दूसरे को अपोकस करने के लिए ध्यान केंद्रित करता है। एंड्रॉइड में, जब कोई दृश्य केंद्रित होता है, यदि दृश्य:

  • अपने स्वयं के फोकस हाइलाइट को निर्दिष्ट किया है, एंड्रॉइड दृश्य का फोकस हाइलाइट खींचता है।
  • फोकस हाइलाइट निर्दिष्ट नहीं करता है, और डिफ़ॉल्ट फोकस हाइलाइट अक्षम नहीं है, Android दृश्य के लिए डिफ़ॉल्ट फोकस हाइलाइट खींचता है।

टच के लिए डिज़ाइन किए गए ऐप्स आमतौर पर उपयुक्त फोकस हाइलाइट्स को निर्दिष्ट नहीं करते हैं।

डिफ़ॉल्ट फोकस हाइलाइट एंड्रॉइड फ्रेमवर्क द्वारा प्रदान किया जाता है और इसे OEM द्वारा ओवरराइड किया जा सकता है। ऐप डेवलपर्स इसे तब प्राप्त करते हैं जब वे जिस विषय का उपयोग कर Theme.DeviceDefault होते हैं वह थी।

एक सुसंगत उपयोगकर्ता अनुभव के लिए, जब भी संभव हो डिफ़ॉल्ट फोकस हाइलाइट पर भरोसा करें। यदि आपको एक कस्टम-आकार की आवश्यकता है (उदाहरण के लिए, गोल या गोली के आकार का) फोकस हाइलाइट, या यदि आप Theme.DeviceDefault से प्राप्त विषय का उपयोग कर रहे हैं, प्रत्येक दृश्य।

एक दृश्य के लिए एक कस्टम फोकस हाइलाइट निर्दिष्ट करने के लिए, दृश्य को देखने के लिए पृष्ठभूमि या अग्रभूमि ड्रा को एक ड्रॉ को बदलें जो कि दृश्य पर केंद्रित होने पर भिन्न होता है। आमतौर पर, आप पृष्ठभूमि को बदल देंगे। निम्नलिखित ड्रॉ, यदि एक वर्ग दृश्य के लिए पृष्ठभूमि के रूप में उपयोग किया जाता है, तो एक गोल फोकस हाइलाइट का उत्पादन करता है:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_focused="true" android:state_pressed="true">
      <shape android:shape="oval">
         <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color"/>
         <stroke
            android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width"
            android:color="@color/car_ui_rotary_focus_pressed_stroke_color"/>
      </shape>
   </item>
   <item android:state_focused="true">
      <shape android:shape="oval">
         <solid android:color="@color/car_ui_rotary_focus_fill_color"/>
         <stroke
            android:width="@dimen/car_ui_rotary_focus_stroke_width"
            android:color="@color/car_ui_rotary_focus_stroke_color"/>
      </shape>
   </item>
   <item>
      <ripple...>
         ...
      </ripple>
   </item>
</selector>

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

बोल्ड संसाधनों के लिए डिफ़ॉल्ट मान
चित्रा 4. बोल्ड संसाधनों के लिए डिफ़ॉल्ट मान

इसके अलावा, एक कस्टम फोकस हाइलाइट के लिए कहा जाता है जब एक बटन को उपयोगकर्ता के ध्यान में लाने के लिए एक ठोस पृष्ठभूमि रंग दिया जाता है, जैसा कि नीचे दिए गए उदाहरण में। यह फोकस को देखने में मुश्किल हो सकता है। इस स्थिति में, द्वितीयक रंगों का उपयोग करके एक कस्टम फोकस हाइलाइट निर्दिष्ट करें:

ठोस पृष्ठभूमि रंग
  • ( Android 11 QPR3, Android 11 CAR, Android 12 )
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • ( एंड्रॉइड 12 )
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

उदाहरण के लिए:

ध्यान केंद्रित, दबाया नहीं गयाध्यान केंद्रित, दबाया
ध्यान केंद्रित, दबाया नहीं गया ध्यान केंद्रित, दबाया

रोटरी स्क्रॉलिंग

यदि आपका ऐप RecyclerView s का उपयोग करता है, तो आपको इसके बजाय CarUiRecyclerView s का उपयोग करना चाहिए। यह सुनिश्चित करता है कि आपका UI दूसरों के अनुरूप है क्योंकि एक OEM का अनुकूलन सभी CarUiRecyclerView s पर लागू होता है।

यदि आपकी सूची के तत्व सभी ध्यान केंद्रित करने योग्य हैं, तो आपको कुछ और करने की आवश्यकता नहीं है। रोटरी नेविगेशन सूची में तत्वों के माध्यम से ध्यान केंद्रित करता है और सूची में नए केंद्रित तत्व को दृश्यमान बनाने के लिए स्क्रॉल होता है।

( Android 11 QPR3, Android 11 CAR, Android 12 )
यदि फोकस और अपरिहार्य तत्वों का मिश्रण है, या यदि सभी तत्व अपरिहार्य हैं, तो आप रोटरी स्क्रॉलिंग को सक्षम कर सकते हैं, जो उपयोगकर्ता को रोटरी कंट्रोलर का उपयोग करने के लिए धीरे -धीरे सूची के माध्यम से अनफॉकेबल आइटमों को छोड़ने के बिना स्क्रॉल करने की अनुमति देता है। रोटरी स्क्रॉलिंग को सक्षम करने के लिए, app:rotaryScrollEnabled विशेषता को true पर सेट करें।

( Android 11 QPR3, Android 11 CAR, Android 12 )
आप किसी भी स्क्रॉल करने योग्य दृश्य में रोटरी स्क्रॉलिंग को सक्षम कर सकते हैं, जिसमें एवी CarUiRecyclerView शामिल है, जिसमें CarUiUtils में setRotaryScrollEnabled() विधि के साथ। यदि आप ऐसा करते हैं, तो आपको आवश्यकता है:

  • स्क्रॉल करने योग्य दृश्य को फ़ोकस करने योग्य बनाएं ताकि यह इस बात पर ध्यान केंद्रित किया जा सके कि इसका कोई भी ध्यान केंद्रित करने योग्य वंशज दृश्य दिखाई नहीं दे रहा है,
  • setDefaultFocusHighlightEnabled(false) को कॉल करके स्क्रॉल करने योग्य दृश्य पर डिफ़ॉल्ट फ़ोकस हाइलाइट को अक्षम करें ताकि स्क्रॉल करने योग्य दृश्य ध्यान केंद्रित न हो,
  • सुनिश्चित करें कि स्क्रॉल करने योग्य दृश्य setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) कॉल करके अपने वंशजों से पहले केंद्रित है।
  • SOURCE_ROTARY_ENCODER और या तो AXIS_VSCROLL या AXIS_HSCROLL के साथ मोशनवेंट्स के लिए स्क्रॉल करने और दिशा (साइन के माध्यम से) की दूरी को इंगित करने के लिए सुनें।

जब रोटरी स्क्रॉलिंग को एक CarUiRecyclerView पर सक्षम किया जाता है और उपयोगकर्ता एक ऐसे क्षेत्र में घूमता है जहां कोई फोकस दृश्य मौजूद नहीं होता है, तो स्क्रॉलबार ग्रे से नीले रंग में बदल जाता है, जैसे कि स्क्रॉलबार को इंगित करने के लिए केंद्रित है। यदि आप चाहें तो आप एक समान प्रभाव लागू कर सकते हैं।

SotionEvents स्रोत को छोड़कर, एक माउस पर एक स्क्रॉल व्हील द्वारा उत्पन्न होने वाले समान हैं।

प्रत्यक्ष हेरफेर विधा

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

दो तरीकों में से एक में डीएम को लागू करें। यदि आपको केवल रोटेशन को संभालने की आवश्यकता है और जिस दृश्य को आप ACTION_SCROLL_FORWARD और ACTION_SCROLL_BACKWARD AccessibilityEvent के लिए उचित रूप से हेरफेर करना चाहते हैं, तो सरल तंत्र का उपयोग करें। अन्यथा, उन्नत तंत्र का उपयोग करें।

सरल तंत्र सिस्टम विंडोज में एकमात्र विकल्प है; ऐप्स या तो तंत्र का उपयोग कर सकते हैं।

सरल तंत्र

( Android 11 QPR3, Android 11 CAR, Android 12 )
आपके ऐप को DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) कॉल करना चाहिए। जब उपयोगकर्ता डीएम मोड में होता है और जब उपयोगकर्ता ध्यान केंद्रित होता है RotaryService तो उपयोगकर्ता केंद्र बटन दबाता है। जब DM मोड में, रोटेशन ACTION_SCROLL_FORWARD या ACTION_SCROLL_BACKWARD प्रदर्शन करते हैं और जब उपयोगकर्ता बैक बटन दबाता है तो DM मोड से बाहर निकलता है। सरल तंत्र डीएम मोड में प्रवेश और बाहर निकलने पर देखने की चयनित स्थिति को टॉगल करता है।

एक दृश्य क्यू प्रदान करने के लिए कि उपयोगकर्ता डीएम मोड में है, चयनित होने पर अपने दृश्य को अलग -अलग दिखाई दें। उदाहरण के लिए, पृष्ठभूमि को बदलें जब android:state_selected true है।

उन्नत तंत्र

ऐप निर्धारित करता है कि RotaryService कब प्रवेश करता है और डीएम मोड से बाहर निकलता है। एक सुसंगत उपयोगकर्ता अनुभव के लिए, डीएम व्यू के साथ केंद्र बटन को दबाने से डीएम मोड में प्रवेश करना चाहिए और बैक बटन को डीएम मोड से बाहर निकलना चाहिए। यदि केंद्र बटन और/या कुहनी का उपयोग नहीं किया जाता है, तो वे डीएम मोड से बाहर निकलने के वैकल्पिक तरीके हो सकते हैं। मैप्स जैसे ऐप्स के लिए, डीएम मोड में प्रवेश करने के लिए डीएम का प्रतिनिधित्व करने के लिए एक बटन का उपयोग किया जा सकता है।

उन्नत डीएम मोड का समर्थन करने के लिए, एक दृश्य:

  1. ( Android 11 QPR3, Android 11 Car, Android 12 ) DM मोड में प्रवेश करने के लिए KEYCODE_DPAD_CENTER इवेंट के लिए सुनना चाहिए और DM मोड से बाहर निकलने के लिए KEYCODE_BACK इवेंट को सुनना चाहिए, प्रत्येक मामले में DirectManipulationHelper.enableDirectManipulationMode() को कॉल करना चाहिए। इन घटनाओं को सुनने के लिए, निम्न में से एक करें:
    • एक OnKeyListener रजिस्टर करें।
    • या,
    • दृश्य का विस्तार करें और फिर इसके dispatchKeyEvent() विधि को ओवरराइड करें।
  2. यदि दृश्य को कुदालों को संभालना चाहिए, तो Nudge घटनाओं ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT , या KEYCODE_DPAD_RIGHT ) के लिए सुनना चाहिए।
  3. यदि दृश्य रोटेशन को संभालना चाहता है, तो MotionEvent एस को सुनना चाहिए और AXIS_SCROLL में रोटेशन काउंट प्राप्त करना चाहिए। इसे करने बहुत सारे तरीके हैं:
    1. एक OnGenericMotionListener रजिस्टर करें।
    2. दृश्य को विस्तारित करें और इसके dispatchTouchEvent() विधि को ओवरराइड करें।
  4. डीएम मोड में फंसने से बचने के लिए, जब दृश्य या गतिविधि का दृश्य होता है, तो डीएम मोड से बाहर निकलना चाहिए।
  5. यह इंगित करने के लिए एक दृश्य क्यू प्रदान करना चाहिए कि दृश्य डीएम मोड में है।

एक कस्टम दृश्य का एक नमूना जो पैन और ज़ूम करने के लिए DM मोड का उपयोग करता है, नीचे दिए गए हैं:

/** Whether this view is in DM mode. */
private boolean mInDirectManipulationMode;

/** Initializes the view. Called by the constructors. */ private void init() { setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK events. case KeyEvent.KEYCODE_DPAD_CENTER: if (!mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = true; DirectManipulationHelper.enableDirectManipulationMode(this, true); setSelected(true); // visually indicate DM mode } return true; case KeyEvent.KEYCODE_BACK: if (mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); setSelected(false); } return true; // Consume controller nudge events only when in DM mode. // When in DM mode, nudges pan the map. case KeyEvent.KEYCODE_DPAD_UP: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, -10f); return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, 10f); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(-10f, 0f); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(10f, 0f); return true; // Don't consume other key events. default: return false; } });
// When in DM mode, rotation zooms the map. setOnGenericMotionListener(((view, motionEvent) -> { if (!mInDirectManipulationMode) return false; float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); zoom(10 * scroll); return true; })); }
@Override public void onPause() { if (mInDirectManipulationMode) { // To ensure that the user doesn't get stuck in DM mode, disable DM mode // when the fragment is not interactive (e.g., a dialog shows up). mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); } super.onPause(); }

RotaryPlayground प्रोजेक्ट में अधिक उदाहरण पाए जा सकते हैं।

ActactiveView

एक गतिविधि व्यू का उपयोग करते समय:

  • ActivityView फोकस करने योग्य नहीं होना चाहिए।
  • ( Android 11 QPR3, Android 11 CAR, Android 11 में पदावनत )
    ActivityView की सामग्री में पहले फोकस दृश्य के रूप में एक FocusParkingView होना चाहिए, और इसका app:shouldRestoreFocus विशेषता false होनी चाहिए।
  • ActivityView की सामग्री में कोई android:focusByDefault दृश्य।

उपयोगकर्ता के लिए, एक्टिविटीव्यू का नेविगेशन पर कोई प्रभाव नहीं होना चाहिए, सिवाय इसके कि फोकस क्षेत्र एक्टिविटीव्यू नहीं कर सकते हैं। दूसरे शब्दों में, आपके पास एक भी फोकस क्षेत्र नहीं हो सकता है जिसमें किसी ActivityView अंदर और बाहर सामग्री हो। यदि आप अपने ActivityView में कोई फ़ोकसरीस नहीं जोड़ते हैं, तो ActivityView में दृश्य पदानुक्रम की जड़ को एक अंतर्निहित फोकस क्षेत्र माना जाता है।

बटन जो नीचे आयोजित होते हैं

अधिकांश बटन क्लिक होने पर कुछ कार्रवाई करते हैं। कुछ बटन संचालित होने पर संचालित होते हैं। उदाहरण के लिए, तेजी से आगे और रिवाइंड बटन आमतौर पर नीचे आयोजित होने पर काम करते हैं। इस तरह के बटन रोटरी का समर्थन करने के लिए, KEYCODE_DPAD_CENTER KeyEvents के लिए इस प्रकार सुनें:

mButton.setOnKeyListener((v, keyCode, event) ->
{
    if (keyCode != KEYCODE_DPAD_CENTER) {
        return false;
    }
    if (event.getAction() == ACTION_DOWN) {
        mButton.setPressed(true);
        mHandler.post(mRunnable);
    } else {
        mButton.setPressed(false);
        mHandler.removeCallbacks(mRunnable);
    }
    return true;
});

जिसमें mRunnable एक कार्रवाई करता है (जैसे कि रिवाइंडिंग) और एक देरी के बाद चलाने के लिए खुद को शेड्यूल करता है।

स्पर्श मोड

उपयोगकर्ता रोटरी कंट्रोलर का उपयोग दो तरह से कार में हेड यूनिट के साथ बातचीत करने के लिए कर सकते हैं, या तो रोटरी कंट्रोलर का उपयोग करके या स्क्रीन को छूकर। रोटरी नियंत्रक का उपयोग करते समय, फोकस योग्य विचारों में से एक को हाइलाइट किया जाता है। स्क्रीन को छूते समय, कोई फोकस हाइलाइट प्रकट नहीं होता है। उपयोगकर्ता किसी भी समय इन इनपुट मोड के बीच स्विच कर सकता है:

  • रोटरी → स्पर्श। जब उपयोगकर्ता स्क्रीन को छूता है, तो फोकस हाइलाइट गायब हो जाता है।
  • टच → रोटरी। जब उपयोगकर्ता केंद्र बटन को नग्न करता है, घुमाता है, या दबाता है, तो फोकस हाइलाइट दिखाई देता है।

इनपुट मोड पर बैक और होम बटन का कोई प्रभाव नहीं पड़ता है।

टच मोड की एंड्रॉइड की मौजूदा अवधारणा पर रोटरी पिग्गीबैक। आप यह निर्धारित करने के लिए View.isInTouchMode() का उपयोग कर सकते हैं कि उपयोगकर्ता किस इनपुट मोड का उपयोग कर रहा है। आप परिवर्तनों के लिए सुनने के लिए OnTouchModeChangeListener का उपयोग कर सकते हैं। हालांकि इसका उपयोग वर्तमान इनपुट मोड के लिए आपके उपयोगकर्ता इंटरफ़ेस को अनुकूलित करने के लिए किया जा सकता है, किसी भी बड़े बदलाव से बचें क्योंकि वे डिस्कनेक्टिंग हो सकते हैं।

समस्या निवारण

टच के लिए डिज़ाइन किए गए एक ऐप में, नेस्टेड फोकस दृश्य के लिए यह आम है। उदाहरण के लिए, एक ImageButton के आसपास एक FrameLayout हो सकता है, दोनों फोकस करने योग्य हैं। यह स्पर्श के लिए कोई नुकसान नहीं करता है, लेकिन यह रोटरी के लिए एक खराब उपयोगकर्ता अनुभव के परिणामस्वरूप हो सकता है क्योंकि उपयोगकर्ता को अगले इंटरैक्टिव दृश्य में जाने के लिए नियंत्रक को दो बार घुमाना होगा। एक अच्छे उपयोगकर्ता अनुभव के लिए, Google आपको या तो बाहरी दृश्य या आंतरिक दृश्य पर ध्यान देने योग्य बनाने की सलाह देता है, लेकिन दोनों नहीं।

यदि कोई बटन या स्विच रोटरी कंट्रोलर के माध्यम से दबाने पर फोकस खो देता है, तो इनमें से एक शर्तें लागू हो सकती हैं:

  • बटन दबाए जाने के कारण बटन या स्विच को अक्षम किया जा रहा है (संक्षेप में या अनिश्चित काल तक)। या तो मामले में, इसे संबोधित करने के दो तरीके हैं:
    • android:enabled स्थिति को true के रूप में और कस्टम स्थिति में वर्णित बटन या स्विच करने के लिए एक कस्टम स्थिति का उपयोग करें।
    • बटन को घेरने या स्विच करने के लिए एक कंटेनर का उपयोग करें और बटन या स्विच के बजाय कंटेनर को फ़ोकस करने योग्य बनाएं। (क्लिक श्रोता कंटेनर पर होना चाहिए।)
  • बटन या स्विच को प्रतिस्थापित किया जा रहा है। उदाहरण के लिए, जब बटन दबाया जाता है या स्विच को टॉगल किया जाता है, तो कार्रवाई उपलब्ध कार्यों के एक ताज़ा हो सकती है, जिससे नए बटन मौजूदा बटन को बदल सकते हैं। इसे संबोधित करने के दो तरीके हैं:
    • एक नया बटन या स्विच बनाने के बजाय, मौजूदा बटन या स्विच के आइकन और/या पाठ सेट करें।
    • ऊपर के रूप में, बटन या स्विच के चारों ओर एक फ़ोकस करने योग्य कंटेनर जोड़ें।

रोटरीप्लेग्राउंड

RotaryPlayground रोटरी के लिए एक संदर्भ ऐप है। अपने ऐप्स में रोटरी सुविधाओं को एकीकृत करने का तरीका जानने के लिए इसका उपयोग करें। RotaryPlayground एमुलेटर बिल्ड में शामिल किया गया है और एंड्रॉइड ऑटोमोटिव ओएस (एएओएस) चलाने वाले उपकरणों के लिए बिल्ड में शामिल है।

  • RotaryPlayground रिपॉजिटरी: packages/apps/Car/tests/RotaryPlayground/
  • संस्करण: Android 11 QPR3, Android 11 Car, और Android 12

RotaryPlayground ऐप बाईं ओर निम्नलिखित टैब दिखाता है:

  • पत्ते। फोकस क्षेत्रों के आसपास नेविगेट करने का परीक्षण करें, अयोग्य तत्वों और पाठ इनपुट को छोड़ दें।
  • प्रत्यक्ष हेरफेर। टेस्ट विजेट जो सरल और उन्नत प्रत्यक्ष हेरफेर मोड का समर्थन करते हैं। यह टैब विशेष रूप से ऐप विंडो के भीतर सीधे हेरफेर के लिए है।
  • Sys ui हेरफेर। टेस्ट विजेट जो सिस्टम विंडो में प्रत्यक्ष हेरफेर का समर्थन करते हैं, जहां केवल सरल प्रत्यक्ष हेरफेर मोड समर्थित है।
  • ग्रिड। स्क्रॉलिंग के साथ जेड-पैटर्न रोटरी नेविगेशन का परीक्षण करें।
  • अधिसूचना। सिर-अप सूचनाओं के अंदर और बाहर नग्नता का परीक्षण करें।
  • स्क्रॉल करें. फोकस और अपरिहार्य सामग्री के मिश्रण के माध्यम से टेस्ट स्क्रॉलिंग।
  • वेबव्यू। एक WebView में लिंक के माध्यम से नेविगेटिंग का परीक्षण करें।
  • कस्टम FocusArea टेस्ट FocusArea अनुकूलन:
    • चारों ओर लपेट दो।
    • android:focusedByDefault और app:defaultFocus
    • .
    • स्पष्ट नग लक्ष्य।
    • नग्न शॉर्टकट।
    • कोई फोकस दृश्य के साथ FocusArea