برنامه ها را توسعه دهید

مطالب زیر برای توسعه دهندگان برنامه است.

برای اینکه برنامه خود را به صورت چرخشی پشتیبانی کنید، باید:

  1. یک FocusParkingView در طرح فعالیت مربوطه قرار دهید.
  2. از نماهایی که قابل تمرکز هستند (یا نیستند) اطمینان حاصل کنید.
  3. از FocusArea استفاده کنید تا همه نماهای قابل فوکوس خود را بپیچید، به جز FocusParkingView .

پس از اینکه محیط خود را برای توسعه برنامه های دارای قابلیت چرخشی تنظیم کردید، هر یک از این وظایف در زیر به تفصیل توضیح داده شده است.

یک کنترلر چرخشی راه اندازی کنید

قبل از اینکه بتوانید توسعه برنامه‌های دارای قابلیت چرخشی را شروع کنید، به یک کنترلر چرخشی یا یک پایه نیاز دارید. شما گزینه های شرح داده شده در زیر را دارید.

شبیه ساز

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. در پنجره کنترل‌های توسعه‌یافته Car rotary را انتخاب کنید:

    چرخش ماشین را انتخاب کنید
    شکل 2. Car rotary را انتخاب کنید

صفحه کلید USB

  • یک صفحه کلید USB را به دستگاه خود وصل کنید که دارای سیستم عامل Android Automotive (AAOS) است، در برخی موارد، این کار از نمایش صفحه کلید روی صفحه جلوگیری می کند.
  • از یک userdebug یا eng build استفاده کنید.
  • فعال کردن فیلتر رویداد کلید:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • برای یافتن کلید مربوطه برای هر عمل به جدول زیر مراجعه کنید:
    کلید عمل چرخشی
    س در خلاف جهت عقربه های ساعت بچرخانید
    E در جهت عقربه های ساعت بچرخانید
    آ به چپ تکان دهید
    D به سمت راست تکان دهید
    دبلیو تلنگر بزنید
    اس به پایین تلنگر بزنید
    F یا کاما دکمه مرکزی
    R یا Esc دکمه برگشت

دستورات ADB

می توانید از دستورات car_service برای تزریق رویدادهای ورودی چرخشی استفاده کنید. این دستورات را می توان در دستگاه هایی اجرا کرد که سیستم عامل Android Automotive (AAOS) یا شبیه ساز را اجرا می کنند.

دستورات 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

FocusParkingView یک نمای شفاف در کتابخانه UI Car (car-ui-library) است. RotaryService از آن برای پشتیبانی از ناوبری کنترلر چرخشی استفاده می کند. FocusParkingView باید اولین نمای قابل فوکوس در طرح باشد. باید خارج از همه FocusArea قرار گیرد. هر پنجره باید یک FocusParkingView داشته باشد. اگر قبلاً از طرح‌بندی پایه car-ui-library که حاوی FocusParkingView است استفاده می‌کنید، نیازی نیست FocusParkingView دیگری اضافه کنید. در زیر نمونه ای از FocusParkingView در RotaryPlayground نشان داده شده است.

<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. هنگامی که فوکوس در پنجره دیگری تنظیم می شود، Android به طور خودکار فوکوس را پاک نمی کند. اگر سعی کنید فوکوس را در پنجره قبلی پاک کنید، اندروید نمای آن پنجره را مجدداً فوکوس می‌کند که منجر به فوکوس شدن همزمان دو پنجره می‌شود. افزودن FocusParkingView به هر پنجره می تواند این مشکل را برطرف کند. این نما شفاف است و برجسته کردن فوکوس پیش‌فرض آن غیرفعال است، به طوری که بدون توجه به فوکوس یا عدم تمرکز، برای کاربر نامرئی است. می تواند فوکوس را بگیرد تا RotaryService بتواند فوکوس را روی آن پارک کند تا برجسته شدن فوکوس حذف شود.
  2. اگر فقط یک FocusArea در پنجره فعلی وجود داشته باشد، چرخاندن کنترلر در FocusArea باعث می شود تا RotaryService فوکوس را از نمای سمت راست به نمای سمت چپ (و بالعکس) منتقل کند. افزودن این نما به هر پنجره می تواند مشکل را برطرف کند. هنگامی که RotaryService تعیین می کند که هدف فوکوس یک FocusParkingView است، می تواند تعیین کند که یک wrap-around در شرف وقوع است که در آن نقطه با عدم حرکت فوکوس از چرخش دور جلوگیری می کند.
  3. هنگامی که کنترل چرخشی یک برنامه را راه اندازی می کند، Android اولین نمای قابل فوکوس را متمرکز می کند که همیشه FocusParkingView است. FocusParkingView نمای بهینه برای فوکوس را تعیین می کند و سپس فوکوس را اعمال می کند.

نماهای قابل تمرکز

RotaryService مبتنی بر مفهوم موجود چارچوب Android از تمرکز دید است که به زمانی برمی گردد که تلفن ها دارای صفحه کلید فیزیکی و D-pad بودند. ویژگی android:nextFocusForward موجود برای چرخشی تغییر کاربری داده شده است (به سفارشی سازی FocusArea مراجعه کنید)، اما android:nextFocusLeft ، android:nextFocusRight ، android:nextFocusUp و android:nextFocusDown اینگونه نیستند.

RotaryService فقط بر روی نماهایی تمرکز می کند که قابل فوکوس هستند. برخی از نماها، مانند Button s، معمولاً قابل فوکوس هستند. سایرین، مانند TextView s و ViewGroup s، معمولاً اینطور نیستند. نماهای قابل کلیک به طور خودکار قابل فوکوس هستند و نماها زمانی که شنونده کلیک داشته باشند به طور خودکار قابل کلیک هستند. اگر این منطق خودکار منجر به فوکوس پذیری مورد نظر می شود، نیازی نیست به صراحت قابلیت فوکوس پذیری نما را تنظیم کنید. اگر منطق خودکار به فوکوس‌پذیری مورد نظر منجر نمی‌شود، ویژگی android:focusable روی true یا false تنظیم کنید، یا با برنامه View.setFocusable(boolean) قابلیت تمرکز نمای را تنظیم کنید. برای اینکه RotaryService روی آن تمرکز کند، یک View باید شرایط زیر را داشته باشد:

  • قابل تمرکز
  • فعال شد
  • قابل رویت
  • مقادیر غیر صفر برای عرض و ارتفاع داشته باشید

اگر یک نما تمام این الزامات را برآورده نکند، برای مثال یک دکمه قابل فوکوس اما غیرفعال، کاربر نمی تواند از کنترل چرخشی برای فوکوس روی آن استفاده کند. اگر می‌خواهید روی نماهای غیرفعال تمرکز کنید، به جای android:state_enabled از یک حالت سفارشی استفاده کنید تا نحوه نمایش نما را کنترل کنید بدون اینکه نشان دهید که Android باید آن را غیرفعال در نظر بگیرد. برنامه شما می‌تواند به کاربر اطلاع دهد که چرا هنگام ضربه زدن، نما غیرفعال است. بخش بعدی نحوه انجام این کار را توضیح می دهد.

حالت سفارشی

برای افزودن حالت سفارشی:

  1. برای افزودن یک ویژگی سفارشی به نمای خود. به عنوان مثال، برای افزودن یک حالت سفارشی state_rotary_enabled به کلاس CustomView ، از
    <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. در کلاس view خود، متد 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() جایگزین کنید.

Focus Area

از FocusAreas برای تقسیم نماهای قابل تمرکز به بلوک‌ها استفاده کنید تا پیمایش آسان‌تر شود و با سایر برنامه‌ها سازگار باشد. به عنوان مثال، اگر برنامه شما دارای یک نوار ابزار است، نوار ابزار باید در یک FocusArea مجزا از بقیه برنامه شما باشد. نوارهای برگه و سایر عناصر ناوبری نیز باید از بقیه برنامه جدا شوند. فهرست‌های بزرگ معمولاً باید FocusArea خاص خود را داشته باشند. در غیر این صورت، کاربران باید در کل لیست بچرخند تا به برخی از نماها دسترسی داشته باشند.

FocusArea یک زیر کلاس از LinearLayout در car-ui-library است. هنگامی که این ویژگی فعال است، FocusArea زمانی که یکی از نوادگان آن فوکوس شده است، یک نقطه برجسته می‌کشد. برای کسب اطلاعات بیشتر، به سفارشی‌سازی برجسته‌سازی فوکوس مراجعه کنید.

هنگام ایجاد یک بلوک ناوبری در فایل طرح بندی، اگر قصد دارید از یک LinearLayout به عنوان ظرفی برای آن بلوک استفاده کنید، به جای آن از FocusArea استفاده کنید. در غیر این صورت، بلوک را در یک FocusArea بپیچید.

یک FocusArea در FocusArea دیگر قرار ندهید . انجام این کار منجر به رفتار ناوبری نامشخص می شود. اطمینان حاصل کنید که همه نماهای قابل فوکوس در یک FocusArea تودرتو هستند.

نمونه ای از FocusArea در RotaryPlayground در زیر نشان داده شده است:

<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 در سلسله مراتب view می گردد.
  2. هنگام دریافت یک رویداد چرخشی، RotaryService فوکوس را به نمای دیگری منتقل می کند که می تواند در همان FocusArea تمرکز کند.
  3. هنگام دریافت یک رویداد نوج، RotaryService فوکوس را به نمای دیگری منتقل می کند که می تواند در FocusArea دیگر (معمولاً مجاور) تمرکز کند.

اگر هیچ FocusAreas در طرح بندی خود وارد نکنید، نمای ریشه به عنوان یک ناحیه تمرکز ضمنی در نظر گرفته می شود. کاربر نمی تواند برای پیمایش در برنامه تلنگر بزند. در عوض، آنها از طریق تمام نمای های قابل فوکوس می چرخند، که ممکن است برای گفتگوها کافی باشد.

سفارشی سازی FocusArea

برای سفارشی کردن ناوبری چرخشی می توان از دو ویژگی View استاندارد استفاده کرد:

  • android:nextFocusForward به توسعه دهندگان برنامه اجازه می دهد تا ترتیب چرخش را در یک ناحیه فوکوس مشخص کنند. این همان مشخصه ای است که برای کنترل ترتیب Tab برای پیمایش صفحه کلید استفاده می شود. از این ویژگی برای ایجاد یک حلقه استفاده نکنید . در عوض، از app:wrapAround (به زیر مراجعه کنید) برای ایجاد یک حلقه استفاده کنید.
  • android:focusedByDefault به توسعه دهندگان برنامه اجازه می دهد نمای فوکوس پیش فرض را در پنجره مشخص کنند. از این ویژگی و app:defaultFocus (به زیر مراجعه کنید) در همان FocusArea استفاده نکنید .

FocusArea همچنین برخی از ویژگی ها را برای سفارشی کردن ناوبری چرخشی تعریف می کند. مناطق فوکوس ضمنی را نمی توان با این ویژگی ها سفارشی کرد.

  1. ( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
    app:defaultFocus می توان برای تعیین شناسه نمای اصلی قابل فوکوس استفاده کرد، که وقتی کاربر به این FocusArea اشاره می کند باید روی آن متمرکز شود.
  2. ( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
    app:defaultFocusOverridesHistory می توان روی true تنظیم کرد تا نمای مشخص شده در بالا تمرکز داشته باشد، حتی اگر با تاریخچه نشان دهد نمای دیگری در این FocusArea روی آن متمرکز شده بود.
  3. ( اندروید 12 )
    از app:nudgeLeftShortcut ، app:nudgeRightShortcut ، app:nudgeUpShortcut ، و app:nudgeDownShortcut برای تعیین شناسه نمای اصلی قابل فوکوس استفاده کنید، که وقتی کاربر در جهت معینی حرکت می‌کند باید روی آن متمرکز شود. برای کسب اطلاعات بیشتر، به محتوای میانبرهای نوج زیر مراجعه کنید.

    ( Android 11 QPR3، Android 11 Car، در Android 12 منسوخ شده است ) app:nudgeShortcut و app:nudgeShortcutDirection تنها از یک میانبر nudge پشتیبانی می کنند.

  4. ( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
    برای فعال کردن چرخش در این FocusArea ، app:wrapAround می توان روی true تنظیم کرد. این معمولاً زمانی استفاده می شود که نماها در یک دایره یا بیضی مرتب شده باشند.
  5. ( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
    برای تنظیم لایه هایلایت در این FocusArea ، از app:highlightPaddingStart ، app:highlightPaddingEnd ، app:highlightPaddingTop ، app:highlightPaddingBottom ، app:highlightPaddingHorizontal و app:highlightPaddingVertical استفاده کنید.
  6. ( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
    برای تنظیم مرزهای درک شده این FocusArea برای یافتن یک هدف حرکتی، از app:startBoundOffset ، app:endBoundOffset ، app:topBoundOffset ، app:bottomBoundOffset ، app:horizontalBoundOffset ، و app:verticalBoundOffset استفاده کنید.
  7. ( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
    برای مشخص کردن صریح شناسه یک FocusArea (یا مناطق) مجاور در جهت‌های داده شده، از app:nudgeLeft ، app:nudgeRight ، app:nudgeUp و app:nudgeDown استفاده کنید. وقتی جستجوی هندسی که به طور پیش‌فرض استفاده می‌شود، هدف مورد نظر را پیدا نمی‌کند، از این استفاده کنید.

Nudging معمولاً بین Focus Areas حرکت می کند. اما با میانبرهای اشاره‌ای، گاهی اوقات حرکت دادن ابتدا در یک FocusArea حرکت می‌کند، به طوری که کاربر ممکن است برای پیمایش به FocusArea بعدی نیاز داشته باشد دو بار ضربه بزند. میانبرهای Nudge زمانی مفید هستند که یک FocusArea شامل یک لیست طولانی و به دنبال آن یک دکمه عمل شناور باشد، مانند مثال زیر:

میانبر اشاره
شکل 3. میانبر اشاره

بدون میانبر nudge، کاربر باید در کل لیست بچرخد تا به FAB برسد.

سفارشی سازی برجسته فوکوس

همانطور که در بالا ذکر شد، RotaryService بر اساس مفهوم موجود در چارچوب Android از تمرکز دیدگاه است. هنگامی که کاربر می‌چرخد و حرکت می‌دهد، RotaryService فوکوس را به اطراف منتقل می‌کند، یک نمای را فوکوس می‌کند و دیگری را از حالت فوکوس خارج می‌کند. در اندروید، وقتی یک نما فوکوس می‌شود، اگر نمای:

  • برجسته تمرکز خود را مشخص کرده است، آندروید برجسته فوکوس نمای را می کشد.
  • برجسته‌سازی فوکوس را مشخص نمی‌کند، و برجسته‌سازی پیش‌فرض فوکوس غیرفعال نیست، اندروید برجسته‌سازی فوکوس پیش‌فرض را برای نما ترسیم می‌کند.

برنامه هایی که برای لمس طراحی شده اند معمولاً نقاط برجسته فوکوس مناسب را مشخص نمی کنند.

برجسته‌سازی پیش‌فرض فوکوس توسط چارچوب Android ارائه می‌شود و می‌تواند توسط OEM لغو شود. توسعه دهندگان برنامه زمانی آن را دریافت می کنند که طرح زمینه ای که استفاده می کنند از Theme.DeviceDefault مشتق شده باشد.

برای تجربه کاربری ثابت، هر زمان که ممکن است به برجسته کردن فوکوس پیش‌فرض تکیه کنید. اگر به برجسته‌سازی فوکوس سفارشی (مثلاً گرد یا قرص‌شکل) نیاز دارید، یا اگر از موضوعی استفاده می‌کنید که از Theme.DeviceDefault مشتق نشده است، از منابع car-ui-library برای مشخص کردن هایلایت فوکوس خودتان استفاده کنید. هر نما

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

<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>

( Android 11 QPR3, Android 11 Car, Android 12 ) منابع پررنگ در نمونه بالا منابع تعریف شده توسط car-ui-library را شناسایی می کند. OEM این موارد را لغو می کند تا با برجسته سازی پیش فرضی که مشخص می کنند مطابقت داشته باشد. این تضمین می‌کند که وقتی کاربر بین یک نمای با برجسته‌سازی فوکوس سفارشی و یک نمای با برجسته‌سازی فوکوس پیش‌فرض حرکت می‌کند، رنگ برجسته فوکوس، عرض ضربه و غیره تغییر نمی‌کند. آخرین مورد یک ریپل است که برای لمس استفاده می شود. مقادیر پیش فرض استفاده شده برای منابع پررنگ به صورت زیر ظاهر می شوند:

مقادیر پیش‌فرض برای منابع پررنگ
شکل 4. مقادیر پیش فرض برای منابع پررنگ

علاوه بر این، هنگامی که به دکمه‌ای رنگ پس‌زمینه ثابت داده می‌شود تا توجه کاربر را جلب کند، برجسته‌سازی فوکوس سفارشی فراخوانی می‌شود، مانند مثال زیر. این می تواند برجسته شدن فوکوس را دشوار کند. در این شرایط، با استفاده از رنگ های ثانویه ، یک برجسته فوکوس سفارشی را مشخص کنید:

رنگ پس زمینه ثابت
  • ( اندروید 11 QPR3، اندروید 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 استفاده کنید. این تضمین می‌کند که UI شما با دیگران سازگار است، زیرا سفارشی‌سازی OEM برای همه CarUiRecyclerView اعمال می‌شود.

اگر عناصر موجود در لیست شما همه قابل تمرکز هستند، لازم نیست کار دیگری انجام دهید. پیمایش چرخشی، فوکوس را از میان عناصر موجود در لیست حرکت می‌دهد و فهرست برای نمایان شدن عنصر تازه فوکوس‌شده، پیمایش می‌کند.

( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
اگر ترکیبی از عناصر قابل فوکوس و غیرقابل تمرکز وجود دارد، یا اگر همه عناصر غیرقابل تمرکز هستند، می‌توانید پیمایش چرخشی را فعال کنید، که به کاربر اجازه می‌دهد از کنترل‌کننده چرخشی استفاده کند تا به تدریج در لیست بدون رد شدن از موارد غیرقابل تمرکز حرکت کند. برای فعال کردن پیمایش چرخشی، ویژگی app:rotaryScrollEnabled را روی true تنظیم کنید.

( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
می‌توانید اسکرول چرخشی را در هر نمای قابل پیمایش، از جمله av CarUiRecyclerView ، با متد setRotaryScrollEnabled() در CarUiUtils فعال کنید. اگر این کار را انجام دهید، باید:

  • نمای پیمایشی را قابل فوکوس کنید تا زمانی که هیچ یک از نماهای اصلی قابل فوکوس قابل مشاهده نیست، روی آن فوکوس شود.
  • با فراخوانی setDefaultFocusHighlightEnabled(false) برجسته کردن فوکوس پیش‌فرض در نمای قابل پیمایش را غیرفعال کنید تا نمای قابل پیمایش متمرکز به نظر نرسد.
  • با فراخوانی setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) اطمینان حاصل کنید که نمای قابل پیمایش قبل از فرزندان خود متمرکز شده است.
  • با SOURCE_ROTARY_ENCODER و AXIS_VSCROLL یا AXIS_HSCROLL به MotionEvents گوش دهید تا فاصله پیمایش و جهت را (از طریق علامت) نشان دهید.

هنگامی که پیمایش چرخشی در CarUiRecyclerView فعال می‌شود و کاربر به ناحیه‌ای می‌چرخد که در آن هیچ نمای قابل تمرکزی وجود ندارد، نوار اسکرول از خاکستری به آبی تغییر می‌کند، گویی که نشان می‌دهد نوار اسکرول فوکوس شده است. اگر دوست دارید می توانید یک افکت مشابه را پیاده سازی کنید.

MotionEvents مانند مواردی است که توسط چرخ اسکرول روی ماوس ایجاد می شود، به جز منبع.

حالت دستکاری مستقیم

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

DM را به یکی از دو روش پیاده سازی کنید. اگر فقط باید چرخش را مدیریت کنید و نمای مورد نظر برای دستکاری به ACTION_SCROLL_FORWARD و ACTION_SCROLL_BACKWARD AccessibilityEvent به طور مناسب پاسخ می دهد، از مکانیسم ساده استفاده کنید. در غیر این صورت از مکانیزم پیشرفته استفاده کنید.

مکانیسم ساده تنها گزینه در ویندوز سیستم است. برنامه ها می توانند از هر مکانیزم استفاده کنند.

مکانیزم ساده

( اندروید 11 QPR3، اندروید 11 ماشین، اندروید 12 )
برنامه شما باید DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) را فراخوانی کند. RotaryService تشخیص می دهد که کاربر در حالت DM است و هنگامی که کاربر دکمه مرکز را فشار می دهد در حالی که یک نما فوکوس شده است وارد حالت DM می شود. در حالت DM، چرخش‌ها ACTION_SCROLL_FORWARD یا ACTION_SCROLL_BACKWARD را انجام می‌دهند و وقتی کاربر دکمه برگشت را فشار می‌دهد از حالت DM خارج می‌شود. مکانیسم ساده حالت انتخاب شده نما را هنگام ورود و خروج از حالت DM تغییر می دهد.

برای ارائه یک نشانه بصری مبنی بر اینکه کاربر در حالت DM است، هنگام انتخاب نمای خود را متفاوت نشان دهید. برای مثال، زمانی که android:state_selected true است، پس‌زمینه را تغییر دهید.

مکانیزم پیشرفته

برنامه تعیین می‌کند که RotaryService چه زمانی وارد حالت DM شود و از آن خارج شود. برای تجربه کاربری ثابت، فشار دادن دکمه مرکز با نمای DM متمرکز باید وارد حالت DM شود و دکمه برگشت باید از حالت DM خارج شود. اگر از دکمه مرکزی و/یا تلنگر استفاده نمی‌شود، می‌توانند راه‌های جایگزینی برای خروج از حالت DM باشند. برای برنامه هایی مانند Maps، می توان از دکمه ای برای نشان دادن DM برای ورود به حالت DM استفاده کرد.

برای پشتیبانی از حالت DM پیشرفته، یک نما:

  1. ( Android 11 QPR3, Android 11 Car, Android 12 ) برای ورود به حالت DM باید به رویداد KEYCODE_DPAD_CENTER گوش دهید و برای خروج از حالت DM به رویداد KEYCODE_BACK گوش دهید و در هر مورد DirectManipulationHelper.enableDirectManipulationMode() فراخوانی کنید. برای گوش دادن به این رویدادها، یکی از موارد زیر را انجام دهید:
    • یک OnKeyListener ثبت کنید.
    • یا،
    • View را گسترش دهید و سپس متد dispatchKeyEvent() آن را لغو کنید.
  2. اگر نما باید با تلنگرها برخورد کند، باید به رویدادهای نوج گوش دهید ( KEYCODE_DPAD_UP ، KEYCODE_DPAD_DOWN ، KEYCODE_DPAD_LEFT ، یا KEYCODE_DPAD_RIGHT ).
  3. اگر نمای می‌خواهد چرخش را مدیریت کند، باید به MotionEvent گوش دهید و تعداد چرخش را در AXIS_SCROLL دریافت کنید. راه های مختلفی برای این کار وجود دارد:
    1. یک OnGenericMotionListener ثبت کنید.
    2. نمایش را گسترش دهید و متد dispatchTouchEvent() آن را لغو کنید.
  4. برای جلوگیری از گیر افتادن در حالت DM، باید از حالت DM خارج شوید زمانی که بخش یا فعالیتی که نمای به آن تعلق دارد تعاملی نیست.
  5. باید یک نشانه بصری برای نشان دادن اینکه نما در حالت DM است ارائه دهد.

نمونه ای از نمای سفارشی که از حالت 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 یافت.

ActivityView

هنگام استفاده از ActivityView:

  • ActivityView نباید قابل تمرکز باشد.
  • ( Android 11 QPR3، Android 11 Car، منسوخ شده در Android 11 )
    محتویات ActivityView باید حاوی FocusParkingView به عنوان اولین نمای قابل فوکوس باشد و ویژگی app:shouldRestoreFocus باید false باشد.
  • محتویات ActivityView نباید نماهای android:focusByDefault داشته باشند.

برای کاربر، ActivityViews نباید هیچ تأثیری در مسیریابی داشته باشد، به جز اینکه مناطق فوکوس نمی توانند ActivityViews را پوشش دهند. به عبارت دیگر، نمی‌توانید یک ناحیه فوکوس واحد داشته باشید که دارای محتوای داخل و خارج از ActivityView باشد. اگر هیچ FocusAreas را به ActivityView خود اضافه نکنید، ریشه سلسله مراتب view در ActivityView یک ناحیه تمرکز ضمنی در نظر گرفته می شود.

دکمه هایی که با نگه داشتن آن عمل می کنند

اکثر دکمه‌ها هنگام کلیک کردن باعث ایجاد برخی عملکردها می‌شوند. در عوض برخی از دکمه ها با نگه داشتن آن کار می کنند. به عنوان مثال، دکمه‌های Fast Forward و Rewind معمولاً زمانی کار می‌کنند که پایین نگه داشته می‌شوند. برای اینکه چنین دکمه‌هایی از چرخش پشتیبانی کنند، به 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 عملی را انجام می دهد (مثلاً به عقب) و برنامه ریزی می کند تا پس از تأخیر اجرا شود.

حالت لمسی

کاربران می توانند از یک کنترلر چرخشی برای تعامل با هد یونیت در خودرو به دو روش استفاده کنند، یا با استفاده از کنترلر چرخشی یا با لمس صفحه نمایش. هنگام استفاده از کنترلر چرخشی، یکی از نماهای قابل فوکوس برجسته می شود. هنگام لمس صفحه، هیچ برجسته فوکوس ظاهر نمی شود. کاربر می تواند در هر زمانی بین این حالت های ورودی جابجا شود:

  • چرخشی ← لمسی. هنگامی که کاربر صفحه را لمس می کند، برجسته شدن فوکوس ناپدید می شود.
  • ← چرخشی را لمس کنید. هنگامی که کاربر دکمه مرکزی را تکان می دهد، می چرخد ​​یا فشار می دهد، برجسته شدن فوکوس ظاهر می شود.

دکمه های Back و Home هیچ تاثیری روی حالت ورودی ندارند.

Piggybacks چرخشی در مفهوم موجود اندروید از حالت لمسی . می توانید از View.isInTouchMode() استفاده کنید تا مشخص کنید کاربر از کدام حالت ورودی استفاده می کند. برای گوش دادن به تغییرات می توانید از OnTouchModeChangeListener استفاده کنید. در حالی که این می تواند برای سفارشی کردن رابط کاربری شما برای حالت ورودی فعلی استفاده شود، از هر گونه تغییر عمده اجتناب کنید زیرا ممکن است نگران کننده باشد.

عیب یابی

در اپلیکیشنی که برای لمس طراحی شده است، داشتن نماهای قابل فوکوس تودرتو معمول است. برای مثال، ممکن است یک FrameLayout در اطراف یک ImageButton وجود داشته باشد که هر دو قابل فوکوس هستند. این برای لمس ضرری ندارد اما می تواند منجر به تجربه کاربری ضعیف برای چرخش شود زیرا کاربر باید کنترلر را دو بار بچرخاند تا به نمای تعاملی بعدی برود. برای یک تجربه کاربری خوب، گوگل توصیه می کند که نمای بیرونی یا نمای داخلی را قابل فوکوس کنید، اما نه هر دو.

اگر یک دکمه یا سوئیچ با فشار دادن از طریق کنترلر چرخشی فوکوس خود را از دست بدهد، ممکن است یکی از این شرایط اعمال شود:

  • دکمه یا سوئیچ به دلیل فشار دادن دکمه (به طور خلاصه یا نامحدود) غیرفعال می شود. در هر صورت، دو راه برای رفع این مشکل وجود دارد:
    • حالت android:enabled را true بگذارید و از یک حالت سفارشی برای خاکستری کردن دکمه یا سوئیچ همانطور که در حالت سفارشی توضیح داده شده است استفاده کنید.
    • از یک ظرف برای احاطه کردن دکمه یا سوئیچ استفاده کنید و ظرف را به جای دکمه یا سوئیچ قابل فوکوس کنید. (شنونده کلیک باید روی ظرف باشد.)
  • دکمه یا سوئیچ در حال تعویض است. به عنوان مثال، اقدامی که هنگام فشار دادن دکمه یا جابجایی سوئیچ انجام می‌شود، ممکن است باعث به‌روزرسانی عملکردهای موجود شود و باعث شود دکمه‌های جدید جایگزین دکمه‌های موجود شوند. برای رفع این مشکل دو راه وجود دارد:
    • به جای ایجاد یک دکمه یا سوئیچ جدید، نماد و/یا متن دکمه یا سوئیچ موجود را تنظیم کنید.
    • مانند بالا، یک ظرف قابل فوکوس در اطراف دکمه یا سوئیچ اضافه کنید.

زمین بازی روتاری

RotaryPlayground یک برنامه مرجع برای چرخش است. از آن برای یادگیری نحوه ادغام ویژگی های چرخشی در برنامه های خود استفاده کنید. RotaryPlayground در ساخت‌های شبیه‌ساز و در ساخت‌های دستگاه‌هایی که سیستم‌عامل Android Automotive (AAOS) را اجرا می‌کنند گنجانده شده است.

  • مخزن RotaryPlayground : packages/apps/Car/tests/RotaryPlayground/
  • نسخه ها: Android 11 QPR3، Android 11 Car و Android 12

برنامه RotaryPlayground برگه های زیر را در سمت چپ نشان می دهد:

  • کارت ها پیمایش در مناطق فوکوس، نادیده گرفتن عناصر غیرقابل تمرکز و ورودی متن را آزمایش کنید.
  • دستکاری مستقیم ویجت هایی را تست کنید که از حالت دستکاری مستقیم ساده و پیشرفته پشتیبانی می کنند. این تب به طور خاص برای دستکاری مستقیم در پنجره برنامه است.
  • دستکاری UI Sys. ویجت‌هایی را تست کنید که از دستکاری مستقیم در ویندوزهای سیستم پشتیبانی می‌کنند که در آن فقط حالت دستکاری مستقیم ساده پشتیبانی می‌شود.
  • توری. ناوبری چرخشی الگوی z را با اسکرول تست کنید.
  • اطلاع. اعلان‌های هدآپ را تست کنید.
  • طومار. پیمایش را در ترکیبی از محتوای قابل تمرکز و غیر قابل تمرکز آزمایش کنید.
  • WebView. پیمایش از طریق پیوندها را در WebView آزمایش کنید.
  • FocusArea سفارشی. تست سفارشی سازی FocusArea :
    • بپیچید.
    • android:focusedByDefault و app:defaultFocus
    • .
    • اهداف تلنگر آشکار
    • میانبرهای تلنگر.
    • FocusArea بدون نماهای قابل فوکوس.