Uygulama Geliştirme

Aşağıdaki materyal, uygulama geliştiricileri içindir.

Uygulama desteğinizi döner hale getirmek için şunları YAPMALISINIZ:

  1. İlgili aktivite düzenine bir FocusParkingView yerleştirin.
  2. Odaklanabilir olan (veya olmayan) görünümlerden emin olun.
  3. FocusParkingView dışındaki tüm odaklanabilir görünümlerinizi sarmak için FocusArea s kullanın.

Döner özellikli uygulamalar geliştirmek için ortamınızı ayarladıktan sonra, bu görevlerin her biri aşağıda ayrıntılı olarak açıklanmıştır.

Döner bir kontrolör kurun

Döner özellikli uygulamalar geliştirmeye başlamadan önce, döner bir denetleyiciye veya yedek bir denetleyiciye ihtiyacınız vardır. Aşağıda açıklanan seçeneklere sahipsiniz.

öykünücü

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

Ayrıca aosp_car_x86_64-userdebug kullanabilirsiniz.

Öykünülmüş döner denetleyiciye erişmek için:

  1. Araç çubuğunun altındaki üç noktaya dokunun:

    Öykünülmüş döner denetleyiciye erişim
    Şekil 1. Öykünülmüş döner denetleyiciye erişim
  2. Genişletilmiş kontroller penceresinde Döner Araba'yı seçin:

    Araba döner seçin
    Şekil 2. Döner Araba'yı seçin

USB Klavye

  • Android Automotive OS (AAOS) çalıştıran cihazınıza bir USB klavye takın. Bazı durumlarda bu, ekran klavyesinin görünmesini engelleyebilir.
  • Bir userdebug veya eng derlemesi kullanın.
  • Anahtar olay filtrelemeyi etkinleştir:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • Her eyleme karşılık gelen anahtarı bulmak için aşağıdaki tabloya bakın:
    Anahtar Döner eylem
    Q Saat yönünün tersine çevirin
    E Saat yönünde döndür
    A Sola sürükle
    D Sağa sürükle
    W yukarı itmek
    S Aşağı itmek
    F veya Virgül orta düğme
    R veya Esc Geri düğmesi

ADB komutları

Döner giriş olaylarını enjekte etmek için car_service komutlarını kullanabilirsiniz. Bu komutlar, Android Automotive OS (AAOS) çalıştıran cihazlarda veya bir öykünücüde çalıştırılabilir.

car_service komutları Döner giriş
adb shell cmd car_service inject-rotary Saat yönünün tersine çevirin
adb shell cmd car_service inject-rotary -c true Saat yönünde döndür
adb shell cmd car_service inject-rotary -dt 100 50 Saat yönünün tersine birkaç kez döndürün (100 ms önce ve 50 ms önce)
adb shell cmd car_service inject-key 282 Sola sürükle
adb shell cmd car_service inject-key 283 Sağa sürükle
adb shell cmd car_service inject-key 280 yukarı itmek
adb shell cmd car_service inject-key 281 Aşağı itmek
adb shell cmd car_service inject-key 23 Orta düğme tıklaması
adb shell input keyevent inject-key 4 Geri düğmesi tıklaması

OEM döner kontrolör

Döner denetleyici donanımınız hazır ve çalışır durumdayken, bu en gerçekçi seçenektir. Özellikle hızlı dönüşü test etmek için kullanışlıdır.

OdakPark Görünümü

FocusParkingView , Araba UI Kitaplığındaki (araba-ui-kütüphanesi) şeffaf bir görünümdür. RotaryService bunu döner kontrolör navigasyonunu desteklemek için kullanır. FocusParkingView , yerleşimdeki ilk odaklanılabilir görünüm olmalıdır. Tüm FocusArea dışına yerleştirilmelidir. Her pencerede bir FocusParkingView olmalıdır. FocusParkingView içeren car-ui-library temel düzenini zaten kullanıyorsanız, başka bir FocusParkingView eklemeniz FocusParkingView . Aşağıda gösterilen, 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>

Bir FocusParkingView ihtiyaç duymanızın nedenleri şunlardır:

  1. Odak başka bir pencerede ayarlandığında Android odağı otomatik olarak temizlemez. Önceki pencerede odağı temizlemeye çalışırsanız, Android o penceredeki bir görünüme yeniden odaklanır ve bu, aynı anda iki pencereye odaklanmaya neden olur. Her pencereye bir FocusParkingView eklemek bu sorunu çözebilir. Bu görünüm şeffaftır ve varsayılan odak vurgusu devre dışıdır, böylece odaklanmış olsun ya da olmasın kullanıcı tarafından görünmez. RotaryService odak vurgusunu kaldırmak için odağı üzerine park edebilmesi için odak alabilir.
  2. Geçerli pencerede yalnızca bir FocusArea varsa, Controller'ın FocusArea döndürülmesi, RotaryService odağı sağdaki görünümden soldaki görünüme (ve tam tersi) kaydırmasına neden olur. Bu görünümü her pencereye eklemek sorunu çözebilir. RotaryService , odak hedefinin bir FocusParkingView olduğunu belirlediğinde, odağı hareket ettirmeyerek sarmayı önlediği noktada bir sarmanın meydana gelmek üzere olduğunu belirleyebilir.
  3. Döner kontrol bir uygulamayı başlattığında, Android her zaman FocusParkingView olan ilk odaklanabilir görünüme odaklanır. FocusParkingView , odaklanılacak en uygun görünümü belirler ve ardından odağı uygular.

Odaklanabilir görünümler

RotaryService , telefonların fiziksel klavyeleri ve D-pad'leri olduğu zamanlara dayanan, Android çerçevesinin mevcut görüş odağı konseptini temel alır. Varolan android:nextFocusForward özniteliği rotasyon için yeniden tasarlanmıştır (bkz. FocusArea özelleştirme ), ancak android:nextFocusLeft , android:nextFocusRight , android:nextFocusUp ve android:nextFocusDown değildir.

RotaryService yalnızca odaklanılabilir görünümlere odaklanır. Button s gibi bazı görünümler genellikle odaklanabilir. TextView s ve ViewGroup s gibi diğerleri genellikle değildir. Tıklanabilir görünümler otomatik olarak odaklanabilir ve tıklama dinleyicileri olduğunda görünümler otomatik olarak tıklanabilir. Bu otomatik mantık istenen odaklanabilirliği sağlıyorsa, görünümün odaklanabilirliğini açıkça ayarlamanız gerekmez. Otomatik mantık istenen odaklanabilirliği sağlamazsa, android:focusable niteliğini true veya false olarak ayarlayın veya görünümün View.setFocusable(boolean) ile programlı olarak ayarlayın. RotaryService buna odaklanması için, bir görünümün aşağıdaki gereksinimleri karşılaması ZORUNLUDUR:

  • Odaklanabilir
  • Etkinleştirilmiş
  • Gözle görülür
  • Genişlik ve yükseklik için sıfır olmayan değerlere sahip olun

Bir görünüm, örneğin odaklanabilir ancak devre dışı bırakılmış bir Düğme gibi tüm bu gereksinimleri karşılamıyorsa, kullanıcı buna odaklanmak için döner kontrolü kullanamaz. Devre dışı bırakılmış görünümlere odaklanmak istiyorsanız, Android'in devre dışı olduğunu düşünmesi gerektiğini belirtmeden görünümün nasıl görüneceğini kontrol etmek için android:state_enabled yerine özel bir durum kullanmayı düşünün. Uygulamanız, dokunulduğunda görünümün neden devre dışı bırakıldığını kullanıcıya bildirebilir. Bir sonraki bölümde bunun nasıl yapılacağı açıklanmaktadır.

Özel durum

Özel bir durum eklemek için:

  1. Görünümünüze özel bir nitelik eklemek için. Örneğin, CustomView görünüm sınıfına bir state_rotary_enabled özel durumu eklemek için şunu kullanın:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Bu durumu izlemek için, erişim yöntemleriyle birlikte görünümünüze bir örnek değişken ekleyin:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Görünümünüz oluşturulduğunda niteliğinizin değerini okumak için:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. Görünüm sınıfınızda, onCreateDrawableState() yöntemini geçersiz kılın ve uygun olduğunda özel durumu ekleyin. Örneğin:
    @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. Görünümünüzün tıklama işleyicisinin durumuna bağlı olarak farklı performans göstermesini sağlayın. Örneğin, tıklama işleyicisi hiçbir şey yapmayabilir veya mRotaryEnabled false olduğunda bir tost açabilir.
  6. Düğmenin devre dışı görünmesini sağlamak için görünümünüzün arka planında çizilebilir hale getirmek için android:state_enabled app:state_rotary_enabled kullanın. Henüz sahip değilseniz, şunu eklemeniz gerekir:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Görünümünüz herhangi bir düzende devre dışı bırakılmışsa, android:enabled="false" app:state_rotary_enabled="false" ile değiştirin ve ardından yukarıdaki gibi app ad alanını ekleyin.
  8. Görünümünüz programlı olarak devre dışı bırakılmışsa, setEnabled() setRotaryEnabled() değiştirin.

Odak Alanı

Navigasyonu kolaylaştırmak ve diğer uygulamalarla tutarlı olmak için odaklanabilir görünümleri bloklara ayırmak için FocusAreas kullanın. Örneğin, uygulamanızın bir araç çubuğu varsa, araç çubuğu uygulamanızın geri kalanından ayrı bir FocusArea olmalıdır. Sekme çubukları ve diğer gezinme öğeleri de uygulamanın geri kalanından ayrılmalıdır. Büyük listeler genellikle kendi FocusArea sahip olmalıdır. Değilse, kullanıcıların bazı görünümlere erişmek için tüm listeyi döndürmesi gerekir.

FocusArea , araba-ui-kütüphanesindeki LinearLayout bir alt sınıfıdır. Bu özellik etkinleştirildiğinde, bir FocusArea , torunlarından biri odaklandığında bir vurgu çizecektir. Daha fazla bilgi edinmek için bkz. Odak vurgusu özelleştirmesi .

Düzen dosyasında bir gezinme bloğu oluştururken, bu blok için bir kapsayıcı olarak bir LinearLayout kullanmayı düşünüyorsanız, bunun yerine bir FocusArea kullanın. Aksi takdirde, bloğu bir FocusArea .

Bir FocusArea başka bir FocusArea . Bunu yapmak, tanımsız gezinme davranışına yol açacaktır. Tüm odaklanabilir görünümlerin bir FocusArea içinde yuvalandığından emin olun.

RotaryPlayground bir FocusArea örneği aşağıda gösterilmiştir:

<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 aşağıdaki gibi çalışır:

  1. Döndürme ve dürtme eylemlerini işlerken, RotaryService , görünüm hiyerarşisinde FocusArea örneklerini arar.
  2. RotaryService , bir rotasyon olayı alırken, odağı aynı FocusArea odak alabilen başka bir Görünüme taşır.
  3. Bir dürtme olayı alırken, RotaryService , odağı başka bir (tipik olarak bitişik) FocusArea odak alabilen başka bir görünüme taşır.

Mizanpajınıza herhangi bir FocusAreas , kök görünüm örtük bir odak alanı olarak değerlendirilir. Kullanıcı, uygulamada gezinmek için dürtemez. Bunun yerine, diyaloglar için yeterli olabilecek tüm odaklanabilir görünümler arasında döneceklerdir.

FocusArea özelleştirmesi

Döner navigasyonu özelleştirmek için iki standart Görünüm özelliği kullanılabilir:

  • android:nextFocusForward , uygulama geliştiricilerinin bir odak alanında döndürme sırasını belirlemesine olanak tanır. Bu, klavye gezintisi için Sekme sırasını kontrol etmek için kullanılan özniteliğin aynısıdır. Bir döngü oluşturmak için bu özelliği KULLANMAYIN . Bunun yerine, bir döngü oluşturmak için app:wrapAround (aşağıya bakın) kullanın.
  • android:focusedByDefault , uygulama geliştiricilerinin pencerede varsayılan odak görünümünü belirlemesine olanak tanır. Bu özniteliği ve app:defaultFocus (aşağıya bakın) aynı FocusArea içinde KULLANMAYIN .

FocusArea ayrıca döner navigasyonu özelleştirmek için bazı öznitelikler tanımlar. Örtülü odak alanları bu niteliklerle özelleştirilemez.

  1. ( Android 11 QPR3, Android 11 Araba, Android 12 )
    app:defaultFocus , kullanıcı bu FocusArea odaklanması gereken, odaklanabilir bir alt görünümün kimliğini belirtmek için kullanılabilir.
  2. ( Android 11 QPR3, Android 11 Araba, Android 12 )
    app:defaultFocusOverridesHistory , bu FocusArea başka bir görünüme odaklanılmış olsa bile, yukarıda belirtilen görünümün odaklanmasını sağlamak için true olarak ayarlanabilir.
  3. ( Android 12 )
    app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcut ve app:nudgeDownShortcut kullanarak, kullanıcı belirli bir yönde dürttüğünde odaklanması gereken odaklanabilir bir alt görünümün kimliğini belirtin. Daha fazla bilgi edinmek için aşağıdaki dürtme kısayolları içeriğine bakın.

    ( Android 11 QPR3, Android 11 Car, Android 12'de kullanımdan kaldırıldı ) app:nudgeShortcut ve app:nudgeShortcutDirection yalnızca bir dürtme kısayolunu destekledi.

  4. ( Android 11 QPR3, Android 11 Araba, Android 12 )
    Bu FocusArea döndürmeyi etkinleştirmek için app:wrapAround , true olarak ayarlanabilir. Bu genellikle görünümler bir daire veya oval olarak düzenlendiğinde kullanılır.
  5. ( Android 11 QPR3, Android 11 Araba, Android 12 )
    Bu FocusArea dolgusunu ayarlamak için app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontal ve app:highlightPaddingVertical kullanın.
  6. ( Android 11 QPR3, Android 11 Araba, Android 12 )
    Bir dürtme hedefi bulmak üzere bu FocusArea algılanan sınırlarını ayarlamak için app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffset ve app:verticalBoundOffset kullanın.
  7. ( Android 11 QPR3, Android 11 Araba, Android 12 )
    Bitişik FocusArea (veya alanların) kimliğini verilen yönlerde açıkça belirtmek için app:nudgeLeft , app:nudgeRight , app:nudgeUp ve app:nudgeDown . Varsayılan olarak kullanılan geometrik arama istenen hedefi bulamadığında bunu kullanın.

Dürtme genellikle FocusAreas arasında gezinir. Ancak, dürtme kısayollarıyla, dürtme bazen önce bir FocusArea içinde gezinir, böylece kullanıcının bir sonraki FocusArea gitmek için iki kez dürtmesi gerekebilir. Sürükleme kısayolları, aşağıdaki örnekte olduğu gibi, FocusArea uzun bir liste ve ardından bir Kayan Eylem Düğmesi içerdiğinde kullanışlıdır:

Kısayolu sürükle
Şekil 3. Dürtme kısayolu

Dürtme kısayolu olmadan, kullanıcının FAB'ye ulaşmak için tüm listeyi döndürmesi gerekir.

Odak vurgulama özelleştirmesi

Yukarıda belirtildiği gibi, RotaryService , Android çerçevesinin mevcut görüş odağı konseptini temel alır. Kullanıcı dönüp dürttüğünde, RotaryService odağı hareket ettirerek bir görünüme odaklanır ve diğerinin odağını kaldırır. Android'de, bir görünüme odaklanıldığında, görünüm:

  • kendi odak vurgusunu belirledi, Android görünümün odak vurgusunu çiziyor.
  • bir odak vurgusu belirtmez ve varsayılan odak vurgusu devre dışı bırakılmaz, Android görünüm için varsayılan odak vurgusunu çizer.

Dokunma için tasarlanmış uygulamalar genellikle uygun odak vurgularını belirtmez.

Varsayılan odak vurgusu, Android çerçevesi tarafından sağlanır ve OEM tarafından geçersiz kılınabilir. Uygulama geliştiricileri, kullandıkları tema Theme.DeviceDefault türetildiğinde bunu alır.

Tutarlı bir kullanıcı deneyimi için, mümkün olduğunda varsayılan odak vurgusuna güvenin. Özel şekilli (örneğin, yuvarlak veya hap şeklinde) bir odak vurgusuna ihtiyacınız varsa veya Theme.DeviceDefault 'dan türetilmemiş bir tema kullanıyorsanız, kendi odak Theme.DeviceDefault belirtmek için car-ui-library kaynaklarını kullanın. her görünüm.

Bir görünüm için özel bir odak vurgusu belirtmek için, görünümün çizilebilir arka planını veya ön planını, görünüme odaklanıldığında farklılık gösteren bir çizilebilir olarak değiştirin. Tipik olarak, arka planı değiştirirsiniz. Aşağıdaki çizilebilir, kare bir görünüm için arka plan olarak kullanılırsa, yuvarlak bir odak vurgusu üretir:

<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 Araba, Android 12 ) Yukarıdaki örnekteki kalın kaynak referansları, araba-ui-kütüphanesi tarafından tanımlanan kaynakları tanımlar. OEM, belirttikleri varsayılan odak vurgusu ile tutarlı olması için bunları geçersiz kılar. Bu, kullanıcı özel odak vurgulu bir görünüm ile varsayılan odak vurgulu bir görünüm arasında gezinirken odak vurgu renginin, kontur genişliğinin vb. değişmemesini sağlar. Son öğe, dokunma için kullanılan bir dalgalanmadır. Kalın kaynaklar için kullanılan varsayılan değerler aşağıdaki gibi görünür:

Kalın kaynaklar için varsayılan değerler
Şekil 4. Kalın kaynaklar için varsayılan değerler

Ek olarak, aşağıdaki örnekte olduğu gibi, bir düğmeye kullanıcının dikkatine sunmak için düz bir arka plan rengi verildiğinde özel bir odak vurgusu çağrılır. Bu, odak vurgusunun görülmesini zorlaştırabilir. Bu durumda, ikincil renkleri kullanarak özel bir odak vurgusu belirleyin:

Düz arka plan rengi
  • ( Android 11 QPR3, Android 11 Araba, Android 12 )
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • ( Android 12 )
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

Örneğin:

Odaklanmış, basılmamışOdaklanmış, basılmış
Odaklanmış, basılmamış Odaklanmış, basılmış

Döner kaydırma

Uygulamanız RecyclerView s kullanıyorsa, bunun yerine CarUiRecyclerView s kullanmalısınız. Bu, bir OEM'in özelleştirmesi tüm CarUiRecyclerView s için geçerli olduğundan, kullanıcı arayüzünüzün diğerleriyle tutarlı olmasını sağlar.

Listenizdeki öğelerin tümü odaklanabilirse, başka bir şey yapmanıza gerek yoktur. Döner gezinme, odağı listedeki öğeler arasında hareket ettirir ve yeni odaklanılan öğeyi görünür kılmak için liste kaydırılır.

( Android 11 QPR3, Android 11 Araba, Android 12 )
Odaklanabilen ve odaklanamayan öğelerin bir karışımı varsa veya tüm öğeler odaklanamıyorsa, döner kaydırmayı etkinleştirebilirsiniz; bu, kullanıcının döner denetleyiciyi kullanarak odaklanamayan öğeleri atlamadan listede kademeli olarak kaydırmasını sağlar. Döner kaydırmayı etkinleştirmek için app:rotaryScrollEnabled niteliğini true olarak ayarlayın.

( Android 11 QPR3, Android 11 Araba, Android 12 )
CarUiUtils içindeki CarUiUtils setRotaryScrollEnabled() yöntemiyle, av CarUiRecyclerView dahil olmak üzere herhangi bir kaydırılabilir görünümde döner kaydırmayı etkinleştirebilirsiniz. Bunu yaparsanız, yapmanız gerekenler:

  • Kaydırılabilir görünümü, odaklanabilir alt görünümlerinin hiçbiri görünür olmadığında odaklanabilmesi için odaklanabilir yapın,
  • Kaydırılabilir görünümün odaklanmış görünmemesi için setDefaultFocusHighlightEnabled(false) çağırarak kaydırılabilir görünümde varsayılan odak vurgusunu devre dışı bırakın,
  • setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) çağırarak kaydırılabilir görünümün alt öğelerinden önce odaklandığından emin olun.
  • Kaydırılacak mesafeyi ve yönü (işaret boyunca) belirtmek için SOURCE_ROTARY_ENCODER ve AXIS_VSCROLL veya AXIS_HSCROLL ile MotionEvents'i dinleyin.

Bir CarUiRecyclerView döner kaydırma etkinleştirildiğinde ve kullanıcı odaklanabilir görünümlerin bulunmadığı bir alana döndüğünde, kaydırma çubuğu, odaklandığını belirtmek için, kaydırma çubuğu griden maviye değişir. İsterseniz benzer bir efekt uygulayabilirsiniz.

MotionEvent'ler, kaynak dışında faredeki kaydırma tekerleği tarafından oluşturulanlarla aynıdır.

Doğrudan manipülasyon modu

Normalde, dürtmeler ve döndürme kullanıcı arayüzünde gezinirken, ortadaki düğmeye basıldığında işlem yapılır, ancak bu her zaman böyle değildir. Örneğin, bir kullanıcı alarm ses düzeyini ayarlamak isterse, ses düzeyi kaydırıcısına gitmek için döner denetleyiciyi kullanabilir, ortadaki düğmeye basabilir, alarm ses düzeyini ayarlamak için denetleyiciyi döndürebilir ve ardından navigasyona geri dönmek için Geri düğmesine basabilir. . Bu, doğrudan manipülasyon (DM) modu olarak adlandırılır. Bu modda, döner kontrolör gezinmek yerine doğrudan görünümle etkileşim kurmak için kullanılır.

DM'yi iki yoldan biriyle uygulayın. Yalnızca döndürmeyi ve değiştirmek istediğiniz görünümü ACTION_SCROLL_FORWARD ve ACTION_SCROLL_BACKWARD AccessibilityEvent 'lere uygun şekilde yanıtlamanız gerekiyorsa, basit mekanizmayı kullanın. Aksi takdirde, gelişmiş mekanizmayı kullanın.

Basit mekanizma, sistem pencerelerinde tek seçenektir; uygulamalar her iki mekanizmayı da kullanabilir.

Basit mekanizma

( Android 11 QPR3, Android 11 Araba, Android 12 )
Uygulamanız DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) çağırmalıdır. RotaryService , kullanıcının DM modunda olduğunu tanır ve bir görünüme odaklanılırken kullanıcı ortadaki düğmeye bastığında DM moduna girer. DM modundayken, rotasyonlar ACTION_SCROLL_FORWARD veya ACTION_SCROLL_BACKWARD gerçekleştirir ve kullanıcı Geri düğmesine bastığında DM modundan çıkar. Basit mekanizma, DM moduna girerken ve çıkarken görünümün seçili durumunu değiştirir.

Kullanıcının DM modunda olduğuna dair görsel bir ipucu sağlamak için, seçildiğinde görünümünüzün farklı görünmesini sağlayın. Örneğin, android:state_selected true olduğunda arka planı değiştirin.

Gelişmiş mekanizma

Uygulama, RotaryService DM moduna ne zaman girip çıkacağını belirler. Tutarlı bir kullanıcı deneyimi için, DM görünümü odaklıyken Ortadaki düğmeye basmak, DM moduna girmeli ve Geri düğmesi DM modundan çıkmalıdır. Ortadaki düğme ve/veya dürtme kullanılmazsa, bunlar DM modundan çıkmanın alternatif yolları olabilir. Haritalar gibi uygulamalarda, DM moduna girmek için DM'yi temsil eden bir düğme kullanılabilir.

Gelişmiş DM modunu desteklemek için bir görünüm:

  1. ( Android 11 QPR3, Android 11 Car, Android 12 ) DM moduna girmek için bir KEYCODE_DPAD_CENTER olayını dinlemeli ve DM modundan çıkmak için bir KEYCODE_BACK olayını dinlemeli, her durumda DirectManipulationHelper.enableDirectManipulationMode() 'u çağırmalıdır. Bu olayları dinlemek için aşağıdakilerden birini yapın:
    • Bir OnKeyListener .
    • veya,
    • Görünümü genişletin ve ardından dispatchKeyEvent() yöntemini geçersiz kılın.
  2. Görünümün dürtüleri işlemesi gerekiyorsa, dürtme olaylarını ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT veya KEYCODE_DPAD_RIGHT ) dinlemeniz GEREKİR.
  3. Görünüm döndürmeyi işlemek istiyorsa MotionEvent s'yi dinlemeli ve AXIS_SCROLL içinde döndürme sayısını almalıdır. Bunu yapmanın birkaç yolu vardır:
    1. Bir OnGenericMotionListener .
    2. Görünümü genişletin ve onun dispatchTouchEvent() yöntemini geçersiz kılın.
  4. DM modunda takılıp kalmamak için, görünümün ait olduğu Fragment veya Activity etkileşimli olmadığında DM modundan çıkılmalıdır.
  5. Görünümün DM modunda olduğunu belirtmek için görsel bir ipucu SAĞLAMALIDIR.

Bir haritayı kaydırmak ve yakınlaştırmak için DM modunu kullanan bir özel görünüm örneği aşağıda verilmiştir:

/** 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 projesinde daha fazla örnek bulunabilir.

Etkinlik Görünümü

ActivityView kullanırken:

  • ActivityView odaklanabilir olmamalıdır.
  • ( Android 11 QPR3, Android 11 Araba, Android 11'de kullanımdan kaldırıldı )
    ActivityView içeriği, ilk odaklanılabilir görünüm olarak bir FocusParkingView içermelidir ZORUNLU ve bunun app:shouldRestoreFocus niteliği false olmalıdır.
  • ActivityView içeriğinde android:focusByDefault görünümü olmamalıdır.

Kullanıcı için, ActivityView'lerin, odak alanlarının ActivityView'leri kapsayamaması dışında gezinme üzerinde hiçbir etkisi olmamalıdır. Başka bir deyişle, ActivityView içinde ve dışında içeriğe sahip tek bir odak alanınız olamaz. ActivityView öğenize herhangi bir FocusAreas eklemezseniz, ActivityView görünüm hiyerarşisinin kökü, örtük bir odak alanı olarak kabul edilir.

Basılı tutulduğunda çalışan düğmeler

Çoğu düğme, tıklandığında bazı işlemlere neden olur. Bunun yerine basılı tutulduğunda bazı düğmeler çalışır. Örneğin, Hızlı İleri ve Geri Sar düğmeleri genellikle basılı tutulduğunda çalışır. Bu tür düğmelerin döndürmeyi desteklemesini sağlamak için KEYCODE_DPAD_CENTER KeyEvents gibi dinleyin:

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 bir eylemde bulunduğu (geri sarma gibi) ve kendisini bir gecikmeden sonra çalıştırılmak üzere zamanladığı.

Dokunma modu

Kullanıcılar, bir arabadaki ana ünite ile etkileşim kurmak için döner kontrol cihazını kullanarak veya ekrana dokunarak iki şekilde döner bir kontrolör kullanabilir. Döner denetleyiciyi kullanırken, odaklanabilir görünümlerden biri vurgulanacaktır. Ekrana dokunulduğunda odak vurgusu görünmez. Kullanıcı istediği zaman bu giriş modları arasında geçiş yapabilir:

  • Döner → dokunun. Kullanıcı ekrana dokunduğunda odak vurgusu kaybolur.
  • → döner seçeneğine dokunun. Kullanıcı dürttüğünde, döndürdüğünde veya Ortadaki düğmeye bastığında odak vurgusu görünür.

Geri ve Ana Sayfa düğmelerinin giriş modu üzerinde hiçbir etkisi yoktur.

Android'in mevcut dokunmatik modu konseptinde döner bindirmeler. Kullanıcının hangi giriş modunu kullandığını belirlemek için View.isInTouchMode() kullanabilirsiniz. Değişiklikleri dinlemek için OnTouchModeChangeListener kullanabilirsiniz. Bu, kullanıcı arayüzünüzü mevcut giriş modu için özelleştirmek için kullanılabilse de, rahatsız edici olabilecekleri için büyük değişikliklerden kaçının.

Sorun giderme

Dokunma için tasarlanmış bir uygulamada, iç içe odaklanabilir görünümlere sahip olmak nadir değildir. Örneğin, her ikisi de odaklanabilir olan bir ImageButton çevresinde bir FrameLayout olabilir. Bu, dokunmaya zarar vermez, ancak kullanıcının bir sonraki etkileşimli görünüme geçmek için kontrol cihazını iki kez döndürmesi gerektiğinden, döndürme için kötü bir kullanıcı deneyimine neden olabilir. Google, iyi bir kullanıcı deneyimi için dış görünümü veya iç görünümü odaklanabilir yapmanızı, ancak ikisini birden yapmamanızı önerir.

Döner kumanda ile basıldığında bir düğme veya anahtar odağı kaybederse, aşağıdaki koşullardan biri geçerli olabilir:

  • Düğmeye basıldığı için düğme veya anahtar (kısa veya süresiz olarak) devre dışı bırakılıyor. Her iki durumda da, bunu ele almanın iki yolu vardır:
    • android:enabled durumunu true olarak bırakın ve Custom State bölümünde açıklandığı gibi düğmeyi veya anahtarı devre dışı bırakmak için özel bir durum kullanın.
    • Düğmeyi veya anahtarı çevrelemek için bir kap kullanın ve kapsayıcıyı düğme veya anahtar yerine odaklanabilir hale getirin. (Tıklama dinleyicisi kapsayıcıda olmalıdır.)
  • Düğme veya anahtar değiştiriliyor. Örneğin, düğmeye basıldığında veya anahtar değiştirildiğinde gerçekleştirilen eylem, mevcut eylemlerin yenilenmesini tetikleyerek yeni düğmelerin mevcut düğmelerin yerini almasına neden olabilir. Bunu ele almanın iki yolu vardır:
    • Yeni bir düğme veya anahtar oluşturmak yerine, mevcut düğme veya anahtarın simgesini ve/veya metnini ayarlayın.
    • Yukarıdaki gibi, düğmenin veya anahtarın etrafına odaklanabilir bir kap ekleyin.

DönerOyun Alanı

RotaryPlayground , döner için bir referans uygulamasıdır. Döner özellikleri uygulamalarınıza nasıl entegre edeceğinizi öğrenmek için kullanın. RotaryPlayground , Android Automotive OS (AAOS) çalıştıran cihazlar için emülatör yapılarına ve yapılarına dahildir.

  • RotaryPlayground deposu: packages/apps/Car/tests/RotaryPlayground/
  • Sürümler: Android 11 QPR3, Android 11 Araba ve Android 12

RotaryPlayground uygulaması, solda aşağıdaki sekmeleri gösterir:

  • Kartlar. Odaklanma alanlarında gezinmeyi, odaklanamayan öğeleri ve metin girişini atlamayı test edin.
  • Doğrudan manipülasyon. Basit ve gelişmiş doğrudan manipülasyon modunu destekleyen widget'ları test edin. Bu sekme, özellikle uygulama penceresinde doğrudan manipülasyon içindir.
  • Sys UI Manipülasyonu. Yalnızca basit doğrudan manipülasyon modunun desteklendiği sistem pencerelerinde doğrudan manipülasyonu destekleyen widget'ları test edin.
  • Kafes. Kaydırma ile z-desenli döner gezinmeyi test edin.
  • Bildirim. Uyarı bildirimlerini içeri ve dışarı yönlendirmeyi test edin.
  • Taslak. Odaklanabilen ve odaklanamayan içeriğin bir karışımında kaydırmayı test edin.
  • Web Görünümü. Bir WebView içindeki bağlantılar arasında gezinmeyi test edin.
  • Özel FocusArea . FocusArea özelleştirmesini test edin:
    • Etrafına sarmak.
    • android:focusedByDefault ve app:defaultFocus
    • .
    • Açık dürtme hedefleri.
    • Kısayolları sürükleyin.
    • Odaklanabilir görünümleri olmayan FocusArea .