Chromebook'lar kullanıcılara klavye, fare, dokunmatik yüzey, dokunmatik ekran, kalem, MIDI ve gamepad/Bluetooth kumandalar gibi birçok farklı giriş seçeneği sunar. Bu sayede aynı cihaz, DJ'lerin istasyonu, sanatçıların tuvali veya oyuncuların AAA kalitesinde yayın oyunları için tercih ettiği platform haline gelebilir.
Geliştirici olarak bu özellik sayesinde, kullanıcılarınız için çok yönlü ve heyecan verici uygulama deneyimleri oluşturabilirsiniz. Bu deneyimlerde, kullanıcıların halihazırda kullandığı giriş cihazlarından (ör. bağlı klavye, kalem, Stadia oyun kumandası) yararlanabilirsiniz. Ancak tüm bu olasılıklar, uygulama deneyiminizin sorunsuz ve mantıklı olması için kullanıcı arayüzünüzü düşünmenizi de gerektirir. Bu durum, özellikle uygulamanız veya oyununuz cep telefonları için tasarlanmışsa geçerlidir. Örneğin, oyununuzda telefonlar için ekranda dokunmayla kontrol edilen bir joystick varsa kullanıcı klavye ile oynarken bunu gizlemek isteyebilirsiniz.
Bu sayfada, birden fazla giriş kaynağı ve bunları ele alma stratejileri hakkında düşünürken aklınızda bulundurmanız gereken temel sorunları bulabilirsiniz.
Desteklenen giriş yöntemlerinin kullanıcı tarafından keşfedilmesi
İdeal olarak, uygulamanız kullanıcının kullanmayı seçtiği girişe sorunsuz bir şekilde yanıt verir. Bu işlem genellikle basittir ve kullanıcıya ek bilgi vermenizi gerektirmez. Örneğin, kullanıcı fare, izleme dörtgeni, dokunmatik ekran, kalem vb. ile tıkladığında bir düğme çalışmalıdır ve kullanıcıya düğmeyi etkinleştirmek için bu farklı cihazları kullanabileceğini söylemeniz gerekmez.
Ancak, giriş yönteminin kullanıcı deneyimini iyileştirebileceği ve uygulamanızın bu yöntemi desteklediğini kullanıcılara bildirmenin mantıklı olabileceği durumlar vardır. Bazı örnekler:
- Bir medya oynatma uygulaması, kullanıcının kolayca tahmin edemeyeceği birçok kullanışlı klavye kısayolunu destekleyebilir.
- Bir DJ uygulaması oluşturduysanız kullanıcı başlangıçta dokunmatik ekranı kullanabilir ve klavyesini/izleme dörtgenini kullanarak bazı özelliklere dokunarak erişebileceğinin farkında olmayabilir. Ayrıca, çok sayıda MIDI DJ kontrol cihazını desteklediğinizi fark etmeyebilirler. Desteklenen donanımları kontrol etmelerini teşvik etmek, daha gerçekçi bir DJ deneyimi sunabilir.
- Oyununuz dokunmatik ekran ve klavye/fare ile harika olabilir ancak kullanıcılar, oyununuzun Bluetooth oyun kumandalarını da desteklediğini fark etmeyebilir. Bunlardan birini bağlamak kullanıcı memnuniyetini ve etkileşimini artırabilir.
Uygun zamanda mesaj göndererek kullanıcıların giriş seçeneklerini keşfetmesine yardımcı olabilirsiniz. Uygulama, her uygulamada farklı görünür. Bazı örnekler:
- İlk çalıştırma veya günün ipucu pop-up'ları
- Ayarlar panellerindeki yapılandırma seçenekleri, kullanıcılara destek olduğunu pasif olarak belirtebilir. Örneğin, bir oyunun ayarlar panelindeki "oyun kumandası" sekmesi, kumandaların desteklendiğini gösterir.
- Bağlamsal mesajlar. Örneğin, fiziksel bir klavye algıladığınızda ve kullanıcının fare veya dokunmatik ekran kullanarak bir işlemi tıkladığını tespit ettiğinizde, klavye kısayolu öneren faydalı bir ipucu göstermek isteyebilirsiniz.
- Klavye kısayolları listeleri. Fiziksel klavye algılandığında, kullanıcı arayüzünde kullanılabilir klavye kısayollarının listesini göstermenin bir yolunu sunmak, hem klavye desteğinin mevcut olduğunu duyurmak hem de kullanıcıların desteklenen kısayolları kolayca görmesini ve hatırlamasını sağlamak gibi iki amaca hizmet eder.
Giriş varyasyonu için kullanıcı arayüzü etiketleme/düzen
İdeal olarak, farklı bir giriş cihazı kullanıldığında görsel arayüzünüzün çok fazla değişmesi gerekmez. Mümkün olan tüm girişler "sadece çalışmalıdır". Ancak önemli istisnalar vardır. Bunlardan en önemlileri dokunmaya özel kullanıcı arayüzü ve ekrandaki istemlerdir.
Dokunmaya özel kullanıcı arayüzü
Uygulamanızda dokunmaya özel kullanıcı arayüzü öğeleri (ör. oyunda ekrandaki joystick) olduğunda, dokunma kullanılmadığında kullanıcı deneyiminin nasıl olacağını göz önünde bulundurmanız gerekir. Bazı mobil oyunlarda, ekranın önemli bir kısmı dokunmaya dayalı oyun için gerekli olan ancak kullanıcı oyun oynamak için oyun kumandası veya klavye kullanıyorsa gereksiz olan kontrollerle kaplıdır. Uygulamanız veya oyununuz, hangi giriş yönteminin etkin olarak kullanıldığını algılayacak ve kullanıcı arayüzünü buna göre ayarlayacak bir mantık sağlamalıdır. Bunu nasıl yapabileceğinize dair bazı örnekler için aşağıdaki Uygulama bölümüne bakın.
Ekrandaki istemler
Uygulamanız, kullanıcılarınıza ekranda faydalı istemler gösteriyor olabilir. Bunların giriş cihazına bağlı olmamasına dikkat edin. Örneğin:
- Şu yönde kaydırın:
- Kapatmak için herhangi bir yere dokunun
- Sıkıştırarak yakınlaştırma
- "X" tuşuna basarak…
- Etkinleştirmek için uzun basın
Bazı uygulamalar, kelimelerini girişe bağlı kalmayacak şekilde ayarlayabilir. Bu, mantıklı olduğu durumlarda tercih edilir ancak birçok durumda ayrıntı önemlidir ve özellikle uygulamaların ilk çalıştırılması gibi eğitici türdeki modlarda, kullanılan giriş yöntemine bağlı olarak farklı mesajlar göstermeniz gerekebilir.
Birden fazla dildeki dikkat edilmesi gereken noktalar
Uygulamanız birden fazla dili destekliyorsa dize mimarinizi dikkatlice planlamanız gerekir. Örneğin, 3 giriş modunu ve 5 dili destekliyorsanız bu, her kullanıcı arayüzü mesajının 15 farklı sürümü olabileceği anlamına gelir. Bu durum, yeni özellikler eklemek için gereken iş miktarını artıracak ve yazım hatalarının olasılığını yükseltecektir.
Bir yaklaşım, arayüz işlemlerini ayrı bir dize grubu olarak düşünmektir. Örneğin, "kapat" işlemini girişlere özel varyantlarla (ör. "Kapatmak için herhangi bir yere dokunun", "Kapatmak için "Esc" tuşuna basın", "Kapatmak için herhangi bir yeri tıklayın", "Kapatmak için herhangi bir düğmeye basın") kendi dize değişkeni olarak tanımlarsanız kullanıcıya bir şeyi nasıl kapatacağını söylemesi gereken tüm kullanıcı arayüzü mesajlarınız bu tek "kapat" dize değişkenini kullanabilir. Giriş yöntemi değiştiğinde bu tek değişkenin değerini değiştirmeniz yeterlidir.
Sanal klavye / IME girişi
Kullanıcılar, fiziksel klavyesi olmayan bir uygulamayı kullanıyorsa metin girişi ekran klavyesi üzerinden yapılabilir. Dokunmatik klavye göründüğünde gerekli kullanıcı arayüzü öğelerinin kapatılmadığını test edin. Daha fazla bilgi için Android IME görünürlüğü belgelerine bakın.
Uygulama
Çoğu durumda, uygulamalar veya oyunlar ekranda ne gösterildiğinden bağımsız olarak tüm geçerli girişlere doğru şekilde yanıt vermelidir. Bir kullanıcı 10 dakika boyunca dokunmatik ekranı kullandıktan sonra aniden klavyeyi kullanmaya başlarsa ekrandaki görsel istemlerden veya kontrollerden bağımsız olarak klavye girişi çalışmalıdır. Diğer bir deyişle, işlevsellik görsellerden/metinden öncelikli olmalıdır.Bu, giriş algılama mantığınızda bir hata olsa veya beklenmedik bir durum ortaya çıksa bile uygulamanızın/oyununuzun kullanılabilir olmasını sağlar.
Bir sonraki adım, şu anda kullanılan giriş yöntemi için doğru kullanıcı arayüzünü göstermektir. Bunu nasıl doğru şekilde tespit edersiniz? Kullanıcılar uygulamanızı kullanırken farklı giriş yöntemleri arasında geçiş yaparsa ne olur? Aynı anda birden fazla yöntem kullanılıyorsa ne olur?
Alınan etkinliklere dayalı olarak öncelik verilen durum makinesi
Bir yaklaşım, uygulamaya alınan gerçek giriş etkinliklerini takip ederek ve öncelikli mantık kullanarak durumlar arasında geçiş yaparak, ekranda kullanıcıya gösterilen giriş istemlerini temsil eden mevcut "etkin giriş durumunu" takip etmektir.
Öncelik
Neden giriş durumlarına öncelik verilir? Kullanıcılar cihazlarıyla her türlü etkileşime girer ve uygulamanız bu etkileşimleri desteklemelidir. Örneğin, bir kullanıcı aynı anda dokunmatik ekranı ve Bluetooth fareyi kullanmayı seçerse bu desteklenmelidir. Ancak hangi ekran içi giriş istemlerini ve kontrollerini göstermelisiniz? Fare mi dokunma mı?
Her istem grubunu "giriş durumu" olarak tanımlayıp önceliklendirmek, bu kararı tutarlı bir şekilde vermenize yardımcı olabilir.
Alınan giriş etkinlikleri durumu belirler
Neden yalnızca alınan giriş etkinliklerine göre işlem yapılıyor? Bluetooth kumandasının bağlı olup olmadığını belirtmek için Bluetooth bağlantılarını takip edebileceğinizi veya USB cihazlar için USB bağlantılarını izleyebileceğinizi düşünüyor olabilirsiniz. Bu yaklaşım iki temel nedenden dolayı önerilmez.
Öncelikle, API değişkenlerine göre bağlı cihazlar hakkında tahmin edebileceğiniz bilgiler tutarlı değildir ve Bluetooth/donanım/kalem cihazlarının sayısı sürekli olarak artmaktadır.
Bağlantı durumu yerine alınan etkinliklerin kullanılmasının ikinci nedeni, kullanıcıların fare, Bluetooth kumanda, MIDI kumanda vb. bağlı olmasına rağmen uygulamanız veya oyununuzla etkileşim kurmak için bunları aktif olarak kullanmıyor olabilmesidir.
Uygulamanız tarafından etkin bir şekilde alınan giriş etkinliklerine yanıt vererek kullanıcılarınızın gerçek işlemlerine gerçek zamanlı olarak yanıt verdiğinizden ve niyetlerini eksik bilgilerle tahmin etmeye çalışmadığınızdan emin olursunuz.
Örnek: Dokunma, klavye/fare ve kumanda desteği olan oyun
Dokunmatik tabanlı cep telefonları için bir araba yarışı oyunu geliştirdiğinizi düşünün. Oyuncular hızlanabilir, yavaşlayabilir, sağa veya sola dönebilir ya da hız artışı için nitro kullanabilir.
Mevcut dokunmatik ekran arayüzünde hız ve yön kontrolleri için ekranın sol alt kısmında bir ekran içi kontrol çubuğu, sağ alt kısmında ise nitro düğmesi bulunur. Kullanıcı, pistte nitro tüpleri toplayabilir ve ekranın alt kısmındaki nitro çubuğu dolduğunda düğmenin üzerinde "Nitro için basın!" mesajı görünür. Kullanıcının ilk oyunuysa veya bir süredir giriş yapılmadıysa, joystick'in üzerinde arabayı hareket ettirme talimatlarını gösteren "eğitim" metni görünür.
Klavye ve Bluetooth oyun kumandası desteği eklemek istiyorsunuz. Nereden başlamalısınız?
Giriş durumları
Oyununuzun çalışabileceği tüm giriş durumlarını belirleyerek ve ardından her durumda değiştirmek istediğiniz tüm parametreleri listeleyerek başlayın.
| Dokunma | Klavye/Fare | Oyun Denetleyici | |
|---|---|---|---|
|
Tepkiler |
Tüm girişler |
Tüm girişler |
Tüm girişler |
|
Ekrandaki kontroller |
- Dokunmatik gezinme çubuğu |
- Gezinme çubuğu yok |
- Gezinme çubuğu yok |
|
Metin |
Nitro için dokunun. |
Nitro için "N" tuşuna basın. |
Nitro için "A" tuşuna basın. |
|
Eğitim |
Hız/yön için kontrol çubuğunun resmi |
Hız/yön için ok tuşları ve WASD tuşlarının resmi |
Hız/yön için gamepad resmi |
"Etkin giriş" durumunu takip edin ve ardından bu duruma göre kullanıcı arayüzünü gerektiği gibi güncelleyin.
Not: Oyununuzun/uygulamanızın, durumdan bağımsız olarak tüm giriş yöntemlerine yanıt vermesi gerektiğini unutmayın. Örneğin, kullanıcı arabayı dokunmatik ekranla sürerken klavyede N tuşuna basarsa nitro işlemi tetiklenmelidir.
Öncelikli durum değişiklikleri
Bazı kullanıcılar dokunmatik ekranı ve klavye girişini aynı anda kullanabilir. Bazı kullanıcılar, tablet modunda kanepede oyununuzu/uygulamanızı kullanmaya başlayıp daha sonra masada klavyeyi kullanmaya geçebilir. Diğerleri ise oyun kumandalarını oyun ortasında bağlayabilir veya bağlantılarını kesebilir.
İdeal olarak, kullanıcıya dokunmatik ekranı kullanırken "n" tuşuna basmasını söylemek gibi yanlış kullanıcı arayüzü öğeleri kullanmak istemezsiniz. Aynı zamanda, dokunmatik ekran ve klavye gibi birden fazla giriş cihazını aynı anda kullanan kullanıcılar için kullanıcı arayüzünün iki durum arasında sürekli olarak değişmesini istemezsiniz.
Bunu ele almanın bir yolu, giriş türü öncelikleri belirlemek ve durum değişiklikleri arasında gecikme oluşturmaktır. Yukarıdaki araba oyununda, ekran dokunma etkinlikleri alındığı her an ekrandaki joystick'in görünür olmasını sağlamanız gerekir. Aksi takdirde oyun, kullanıcı için kullanılamaz gibi görünebilir. Bu durumda dokunmatik ekran en yüksek öncelikli cihaz olur.
Klavye ve dokunmatik ekran etkinlikleri aynı anda alınıyorsa oyun, klavye girişine tepki vermeye devam etse de dokunmatik ekran modunda kalmalıdır. 5 saniye boyunca dokunmatik ekran girişi alınmazsa ve klavye etkinlikleri alınmaya devam ederse ekran kontrolleri solabilir ve oyun klavye durumuna geçebilir.
Oyun kumandası girişi de benzer bir kalıbı takip eder: Kumanda kullanıcı arayüzü durumuna klavye/fare ve dokunmaya göre daha düşük bir öncelik verilir ve yalnızca oyun kumandası girişi alınıyorsa (diğer giriş biçimleri alınmıyorsa) görünür. Oyun her zaman kumanda girişine yanıt veriyordu.
Aşağıda, örnek için bir durum şeması ve geçiş tablosu verilmiştir. Fikri uygulamanıza veya oyununuza uyarlayın.
| #1 Touchscreen | #2 Klavye | #3 Oyun kumandası | |
|---|---|---|---|
|
1. seçeneğe taşıma |
Yok |
- Dokunmatik giriş alındı |
- Dokunmatik giriş alındı |
|
2. adıma geçin |
- 5 saniye dokunulmaması |
Yok |
- Klavye girişi alındı |
|
3. adıma geçin |
- 5 saniye boyunca dokunulmazsa |
- 5 saniye boyunca klavye kullanılmadı |
Yok |
Not: Önceliklendirmenin, hangi tür girdinin baskın olması gerektiğini netleştirmeye nasıl yardımcı olduğuna dikkat edin. Giriş durumu, öncelik sırasına göre anında "yukarı" taşınır:
3. Oyun kumandası -> 2. Klavye -> 1. Dokunma
Daha yüksek öncelikli bir cihaz kullanıldığı anda, ancak öncelikte yavaşça "aşağı" iner. Bu işlem yalnızca bir süre geciktirildikten sonra ve yalnızca daha düşük öncelikli cihaz aktif olarak kullanılıyorsa gerçekleşir.
Giriş etkinlikleri
Standart Android API'lerini kullanarak çeşitli giriş cihazlarından gelen giriş etkinliklerinin nasıl algılanacağına dair bazı örnek kodları aşağıda bulabilirsiniz. Durum makinenizi yukarıdaki örnekte olduğu gibi yönlendirmek için bu etkinlikleri kullanın. Genel konsepti, beklediğiniz giriş etkinliklerinin türlerine ve uygulamanıza ya da oyununuza göre uyarlamanız gerekir.
Klavye ve kontrol cihazı düğmeleri
// Drive the state machine based on the received input type // onKeyDown drives the state machine, but does not trigger game actions // Both keyboard and game controller events come through as key events override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (event != null) { // Check input source val outputMessage = when (event.source) { SOURCE_KEYBOARD -> { MyStateMachine.KeyboardEventReceived() "Keyboard event" } SOURCE_GAMEPAD -> { MyStateMachine.ControllerEventReceived() "Game controller event" } else -> "Other key event: ${event.source}" } // Do something based on source type findViewById(R.id.text_message).text = outputMessage } // Pass event up to system return super.onKeyDown(keyCode, event) }
// Trigger game events based on key release // Both keyboard and game controller events come through as key events override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { when(keyCode) { KeyEvent.KEYCODE_N -> { MyStateMachine.keyboardEventReceived() engageNitro() return true // event handled here, return true } } // If event not handled, pass up to system return super.onKeyUp(keyCode, event) }
Not: KeyEvents için onKeyDown() veya onKeyUp() kullanabilirsiniz. Burada, onKeyDown() durum makinesini kontrol etmek için, onKeyUp() ise oyun etkinliklerini tetiklemek için kullanılır.
Bir kullanıcı bir düğmeye basıp basılı tutarsa onKeyUp() yalnızca tuşa basma başına bir kez tetiklenirken onKeyDown() birden çok kez çağrılır. Aşağı basma işlemine tepki vermek istiyorsanız oyun etkinliklerini onKeyDown() içinde işlemeli ve tekrarlanan etkinlikleri ele almak için mantık uygulamalısınız. Daha fazla bilgi için Klavye İşlemlerini Yönetme dokümanını inceleyin.
Dokunma ve Ekran Kalemi
// Touch and stylus events come through as touch events override fun onTouchEvent(event: MotionEvent?): Boolean { if (event != null) { // Get tool type val pointerIndex = event.action and ACTION_POINTER_INDEX_MASK shr ACTION_POINTER_INDEX_SHIFT val toolType = event.getToolType(pointerIndex) // Check tool type val outputMessage = when (toolType) { TOOL_TYPE_FINGER -> { MyStateMachine.TouchEventReceived() "Touch event" } TOOL_TYPE_STYLUS -> { MyStateMachine.StylusEventReceived() "Stylus event" } else -> "Other touch event: ${toolType}" } // Do something based on tool type, return true if event handled findViewById(R.id.text_message).text = outputMessage } // If event not handled, pass up to system return super.onGenericMotionEvent(event) }
Fare ve kontrol çubuğu
// Mouse and joystick events come through as generic events override fun onGenericMotionEvent(event: MotionEvent?): Boolean { if (event != null) { // Check input source val outputMessage = when (event.source) { SOURCE_JOYSTICK -> { MyStateMachine.ControllerEventReceived() "Controller event" } SOURCE_MOUSE -> { MyStateMachine.MouseEventReceived() "Mouse event" } else -> "Other generic event: ${event.source}" } // Do something based on source type, return true if event handled findViewById(R.id.text_message).text = outputMessage } // If event not handled, pass up to system return super.onGenericMotionEvent(event) }