Android ve ChromeOS, kullanıcılara olağanüstü bir ekran kalemi deneyimi sunan uygulamalar oluşturmanıza yardımcı olacak çeşitli API'ler sunar. MotionEvent
sınıfı; ekran kalemi basıncı, yön, yatırma, fareyle üzerine gelme ve avuç içi algılama da dahil olmak üzere ekran kaleminin ekranla etkileşimi hakkında bilgi gösterir. Düşük gecikmeli grafikler ve hareket tahmini kitaplıkları, doğal, kalem ve kağıt benzeri bir deneyim sağlamak için ekran kalemini ekranda oluşturur.
MotionEvent
MotionEvent
sınıfı, ekrandaki dokunma işaretçilerinin konumu ve hareketi gibi kullanıcı girişi etkileşimlerini temsil eder. MotionEvent
, ekran kalemi girişi için basınç, yön, yatırma ve fareyle üzerine gelme verilerini de gösterir.
Etkinlik verileri
MotionEvent
verilerine erişmek için bileşenlere pointerInput
değiştirici ekleyin:
@Composable
fun Greeting() {
Text(
text = "Hello, Android!", textAlign = TextAlign.Center, style = TextStyle(fontSize = 5.em),
modifier = Modifier
.pointerInput(Unit) {
awaitEachGesture {
while (true) {
val event = awaitPointerEvent()
event.changes.forEach { println(it) }
}
}
},
)
}
MotionEvent
nesnesi, bir kullanıcı arayüzü etkinliğinin aşağıdaki yönleriyle ilgili veriler sağlar:
- İşlemler: Cihazla fiziksel etkileşim (ekrana dokunma, işaretçiyi ekran yüzeyinde hareket ettirme, bir işaretçiyi ekran yüzeyinin üzerine getirme)
- İşaretçiler: Ekranla etkileşimde bulunan nesnelerin tanımlayıcıları (parmak, ekran kalemi, fare)
- Eksen: Veri türü—x ve y koordinatları, basınç, yatırma, yön ve fareyle üzerine gelme (mesafe)
İşlemler
Ekran kalemi desteğini uygulamak için kullanıcının hangi işlemi gerçekleştirdiğini anlamanız gerekir.
MotionEvent
, hareket etkinliklerini tanımlayan çok çeşitli ACTION
sabitleri sağlar. Ekran kalemiyle ilgili en önemli işlemler şunlardır:
İşlem | Açıklama |
---|---|
ACTION_DOWN ACTION_POINTER_DOWN |
İşaretçi ekranla temas kurdu. |
İŞLEM | İşaretçi ekranda hareket ediyor. |
ACTION_UP ACTION_POINTER_UP |
İşaretçi artık ekranla temas halinde değil |
İŞLEM_İPTAL | Önceki veya geçerli hareket setinin iptal edilmesi gerektiğinde. |
Uygulamanız, ACTION_DOWN
olduğunda yeni bir çizgi başlatma, çizgiyi ACTION_MOVE,
ile çizme ve ACTION_UP
tetiklendiğinde fırçayı tamamlama gibi görevleri gerçekleştirebilir.
Belirli bir işaretçi için ACTION_DOWN
ile ACTION_UP
arasındaki MotionEvent
işlemleri grubuna hareket grubu adı verilir.
İşaretçiler
Çoğu ekran çoklu dokunma özelliğine sahiptir: Sistem, her parmak, ekran kalemi, fare veya ekranla etkileşimde bulunan diğer işaret nesneleri için bir işaretçi atar. İşaretçi dizini, belirli bir işaretçiyle ilgili eksen bilgilerini almanızı sağlar (ör. ekrana dokunan ilk parmağın veya ikinci parmağın konumu).
İşaretçi dizinleri, sıfırdan MotionEvent#pointerCount()
ile döndürülen işaretçi sayısı eksi 1 aralığında değişir.
İşaretçilerin eksen değerlerine getAxisValue(axis,
pointerIndex)
yöntemiyle erişilebilir.
İşaretçi dizini çıkarıldığında sistem, ilk işaretçi olan işaretçi sıfır (0) değerini döndürür.
MotionEvent
nesneleri, kullanılan işaretçi türüyle ilgili bilgiler içerir. İşaretçi dizinlerini tekrarlayarak ve getToolType(pointerIndex)
yöntemini çağırarak işaretçi türünü elde edebilirsiniz.
İşaretçiler hakkında daha fazla bilgi edinmek için Çoklu dokunma hareketlerini işleme bölümüne bakın.
Ekran kalemi girişleri
TOOL_TYPE_STYLUS
kullanarak ekran kalemi girişlerini filtreleyebilirsiniz:
val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)
Ekran kalemi ayrıca TOOL_TYPE_ERASER
ile birlikte silgi olarak kullanıldığını da bildirebilir:
val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)
Ekran kalemi ekseni verileri
ACTION_DOWN
ve ACTION_MOVE
, ekran kalemi hakkında eksen verileri (x ve y koordinatları, basınç, yön, yatırma ve fareyle üzerine gelme) sağlar.
MotionEvent
API, bu verilere erişimi sağlamak için getAxisValue(int)
değerini sunar. Burada parametre, aşağıdaki eksen tanımlayıcılarından herhangi biridir:
Axis | Döndürülen değer: getAxisValue() |
---|---|
AXIS_X |
Bir hareket etkinliğinin X koordinatı. |
AXIS_Y |
Bir hareket etkinliğinin Y koordinatı. |
AXIS_PRESSURE |
Dokunmatik ekran veya dokunmatik alanda parmak, ekran kalemi ya da başka bir işaretçi tarafından uygulanan basınç. Fare veya izleme topu için birincil düğmeye basıldıysa 1, birincil düğmeye basıldıysa 0. |
AXIS_ORIENTATION |
Dokunmatik ekran veya dokunmatik alan söz konusu olduğunda parmak, ekran kalemi veya başka bir işaretçinin cihazın dikey düzlemine göre yönü. |
AXIS_TILT |
Ekran kaleminin radyan cinsinden yatırma açısı. |
AXIS_DISTANCE |
Ekran kaleminin ekrandan uzaklığı. |
Örneğin, MotionEvent.getAxisValue(AXIS_X)
ilk işaretçi için x koordinatını döndürür.
Ayrıca bkz. Çoklu dokunma hareketlerini işleme.
Konum
Aşağıdaki çağrıları kullanarak bir işaretçinin x ve y koordinatlarını alabilirsiniz:
MotionEvent#getAxisValue(AXIS_X)
veyaMotionEvent#getX()
MotionEvent#getAxisValue(AXIS_Y)
veyaMotionEvent#getY()
Basınç
İşaretçi baskısını MotionEvent#getAxisValue(AXIS_PRESSURE)
veya ilk işaretçi için MotionEvent#getPressure()
ile alabilirsiniz.
Dokunmatik ekranlar veya dokunmatik alanlar için basınç değeri 0 (basınç yok) ile 1 arasında bir değerdir ancak ekran kalibrasyonuna bağlı olarak daha yüksek değerler döndürülebilir.
Yön
Yön, ekran kaleminin hangi yönü gösterdiğini belirtir.
İşaretçi yönü, getAxisValue(AXIS_ORIENTATION)
veya getOrientation()
kullanılarak alınabilir (ilk işaretçi için).
Ekran kaleminde yön, saat yönünde 0 ile pi (Parametreler) arasında veya saat yönünün tersine 0 ile -pi arasında bir radyan değeri olarak döndürülür.
Yön, gerçek hayattan bir fırça uygulamanıza olanak tanır. Örneğin, ekran kalemi düz bir fırçayı temsil ediyorsa düz fırçanın genişliği, ekran kaleminin yönüne bağlıdır.
Eğme
Eğme, ekran kaleminin ekrana göre eğimini ölçer.
Eğme, ekran kaleminin pozitif açısını radyan cinsinden döndürür. Burada sıfırın ekrana dik, ÷/2 değeri yüzeyin üzerinde düzdür.
Eğme açısı getAxisValue(AXIS_TILT)
kullanılarak alınabilir (ilk işaretçi için kısayol yoktur).
Eğme özelliği, eğik bir kalemle gölgelendirmeyi taklit etme gibi gerçek hayattaki araçları mümkün olduğunca birbirine yaklaştırmak için kullanılabilir.
İmleçle üzerine gelin
Ekran kaleminin ekrandan uzaklığı getAxisValue(AXIS_DISTANCE)
ile elde edilebilir. Yöntem, ekran kalemi ekrandan uzaklaştıkça 0,0'dan (ekranla temas) daha yüksek değerlere kadar bir değer döndürür. Ekran ve ekran kaleminin ucu (nokta) arasındaki fareyle üzerine gelme mesafesi, hem ekranın hem de ekran kaleminin üreticisine bağlıdır. Uygulamalar değişiklik gösterebileceğinden, uygulama açısından kritik işlevler için kesin değerlere güvenmeyin.
Fırçanın boyutunu önizlemek veya bir düğmenin seçileceğini belirtmek için ekran kalemiyle üzerine gelin.
Not: Oluştur, kullanıcı arayüzü öğelerinin etkileşimli durumunu etkileyen değiştiriciler sağlar:
hoverable
: Bileşeni, işaretçi giriş ve çıkış etkinliklerini kullanarak üzerine getirilebilir olacak şekilde yapılandırın.indication
: Etkileşim gerçekleştiğinde bu bileşen için görsel efektler çizer.
Avuç içi reddi, gezinme ve istenmeyen girişler
Çok dokunmalı ekranlar bazen istenmeyen dokunmaları kaydedebilir. Örneğin, bir kullanıcı el yazısı sırasında destek için elini doğal olarak ekrana koyduğunda.
Avuç içi reddi, bu davranışı algılayan ve son MotionEvent
grubunun iptal edilmesi gerektiğini bildiren bir mekanizmadır.
Sonuç olarak, istenmeyen dokunmaların ekrandan kaldırılabilmesi ve meşru kullanıcı girişlerinin yeniden oluşturulabilmesi için kullanıcı girişlerinin kaydını tutmanız gerekir.
ACTION_CANCEL ve FLAG_CANCELED
Hem ACTION_CANCEL
hem de FLAG_CANCELED
, önceki MotionEvent
grubunun son ACTION_DOWN
tarihinden itibaren iptal edilmesi gerektiğini bildirmek için tasarlanmıştır. Böylece, örneğin, belirli bir işaretçi için bir çizim uygulamasındaki son vuruş işlemini geri alabilirsiniz.
İŞLEM_İPTAL
Android 1.0'a eklendi (API düzeyi 1)
ACTION_CANCEL
, önceki hareket etkinlikleri grubunun iptal edilmesi gerektiğini belirtir.
Aşağıdakilerden herhangi biri algılandığında ACTION_CANCEL
tetiklenir:
- Gezinme hareketleri
- Avuç içi reddi
ACTION_CANCEL
tetiklendiğinde etkin işaretçiyi getPointerId(getActionIndex())
ile tanımlamanız gerekir. Ardından, bu işaretçiyle oluşturulan fırçayı giriş geçmişinden kaldırıp sahneyi yeniden oluşturun.
İŞARET_İPTAL EDİLDİ
Android 13'e eklendi (API düzeyi 33)
FLAG_CANCELED
, yukarı çıkan işaretçinin yanlışlıkla kullanıcı tarafından yapıldığını gösterir. Bayrak, genellikle kullanıcı yanlışlıkla ekrana dokunduğunda (ör. cihazı tutup avucunu ekrana koyduğunda) ayarlanır.
İşaret değerine şu şekilde erişebilirsiniz:
val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED
İşaret ayarlandıysa bu işaretçiden son ACTION_DOWN
sonrasındaki son MotionEvent
ayarını geri almanız gerekir.
ACTION_CANCEL
gibi, işaretçi de getPointerId(actionIndex)
ile bulunabilir.
Tam ekran, uçtan uca ve gezinme hareketleri
Bir uygulama tam ekransa ve kenarı çizim veya not alma uygulamasının tuvali gibi işlem yapılabilir öğeler içeriyorsa, gezinmeyi görüntülemek için ekranın altından kaydırmak veya uygulamayı arka plana taşımak tuvale istenmeyen dokunmaya neden olabilir.
Hareketlerin uygulamanızda istenmeyen dokunmaları tetiklemesini önlemek için ek'lerden ve ACTION_CANCEL
özelliklerinden yararlanabilirsiniz.
Ayrıca Palm reddi, gezinme ve istenmeyen girişler bölümüne bakın.
Gezinme hareketlerinin istenmeyen dokunma etkinliklerine neden olmasını önlemek için setSystemBarsBehavior()
yöntemini ve WindowInsetsController
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
yöntemini kullanın:
// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
Inset ve hareket yönetimi hakkında daha fazla bilgi edinmek için aşağıdaki konulara bakın:
- Yoğun içerik modu için sistem çubuklarını gizle
- Hareketle gezinmeyle uyumluluğu sağlama
- Uygulamanızda içeriği uçtan uca görüntüleme
Düşük gecikme
Gecikme; donanım, sistem ve uygulamanın kullanıcı girişini işlemek ve oluşturmak için ihtiyaç duyduğu süredir.
Gecikme = donanım ve işletim sistemi giriş işleme + uygulama işleme + sistem birleştirme
- donanım oluşturma
Gecikme kaynağı
- Dokunmatik ekranla (donanım) ekran kalemi kaydettirme: Ekran kalemi ve işletim sistemi kaydedilip senkronize edilmek üzere iletişim kurduğunda ilk kablosuz bağlantı.
- Dokunmatik örnekleme hızı (donanım): Dokunmatik ekranın, bir işaretçinin yüzeye dokunup dokunmadığını saniye başına kontrol etme sayısı (60 ile 1000 Hz arasında değişir).
- Giriş işleme (uygulama): Kullanıcı girişine renk, grafik efektleri ve dönüştürme uygulama.
- Grafik oluşturma (OS + donanım): Arabellek değiştirme, donanım işleme.
Düşük gecikmeli grafikler
Jetpack düşük gecikmeli grafik kitaplığı, kullanıcı girişi ve ekranda oluşturma arasındaki işleme süresini azaltır.
Kitaplık, çoklu arabellek oluşturmayı önleyip ön arabellek oluşturma tekniğinden yararlanarak işlem süresini kısaltır. Bu teknik, doğrudan ekrana yazma anlamına gelir.
Ön arabellek oluşturma
Ön arabellek, ekranın oluşturma için kullandığı bellektir. Doğrudan ekrana çizim yapmaya en yakın uygulamalar budur. Düşük gecikmeli kitaplık, uygulamaların doğrudan ön arabellekte oluşturulmasını sağlar. Bu, normal çoklu arabellek oluşturma veya çift arabellek oluşturma (en yaygın durum) için gerçekleşebilecek arabellek değişimini önleyerek performansı artırır.
Ön arabellek oluşturma, ekranın küçük bir alanını oluşturmak için harika bir teknik olsa da tüm ekranı yenilemek için tasarlanmamıştır. Ön arabellek oluşturma ile uygulama, içeriği ekranın okuduğu bir arabelleğe alır. Sonuç olarak, yapıların oluşturulma veya yırtılma (aşağıya bakın) olasılığı söz konusudur.
Düşük gecikme kitaplığı, Android 10 (API düzeyi 29) ve sonraki sürümlerin yanı sıra Android 10 (API düzeyi 29) ve sonraki sürümleri çalıştıran ChromeOS cihazlarda kullanılabilir.
Bağımlılıklar
Düşük gecikmeli kitaplık, ön arabellek oluşturma uygulaması için bileşenleri sağlar. Kitaplık, uygulamanın modül build.gradle
dosyasına bir bağımlılık olarak eklenir:
dependencies {
implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}
GLFrontBufferRenderer geri çağırmaları
Düşük gecikmeli kitaplık, aşağıdaki yöntemleri tanımlayan GLFrontBufferRenderer.Callback
arayüzünü içerir:
Düşük gecikmeli kitaplık, GLFrontBufferRenderer
ile kullandığınız verinin türü konusunda değerlendirilmez.
Ancak kitaplık, verileri yüzlerce veri noktasından oluşan bir akış olarak işler. Bu nedenle verilerinizi, bellek kullanımını ve ayırmayı optimize edecek şekilde tasarlayın.
Geri çağırma işlevleri
Geri çağırma işlevleri oluşturmayı etkinleştirmek için GLFrontBufferedRenderer.Callback
öğesini uygulayın ve onDrawFrontBufferedLayer()
ile onDrawDoubleBufferedLayer()
değerlerini geçersiz kılın.
GLFrontBufferedRenderer
, verilerinizi mümkün olan en optimize şekilde oluşturmak için geri çağırmaları kullanır.
val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> {
override fun onDrawFrontBufferedLayer(
eglManager: EGLManager,
bufferInfo: BufferInfo,
transform: FloatArray,
param: DATA_TYPE
) {
// OpenGL for front buffer, short, affecting small area of the screen.
}
override fun onDrawMultiDoubleBufferedLayer(
eglManager: EGLManager,
bufferInfo: BufferInfo,
transform: FloatArray,
params: Collection<DATA_TYPE>
) {
// OpenGL full scene rendering.
}
}
GLFrontBufferedRenderer örneği tanımlama
Daha önce oluşturduğunuz SurfaceView
ve geri çağırmaları sağlayarak GLFrontBufferedRenderer
hazırlayın. GLFrontBufferedRenderer
, geri çağırmalarınızı kullanarak oluşturmayı ön ve çift arabelleğe göre optimize eder:
var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)
Oluşturma
Ön arabellek oluşturma işlemi, onDrawFrontBufferedLayer()
geri çağırmasını tetikleyen renderFrontBufferedLayer()
yöntemini çağırdığınızda başlar.
Çift arabellek oluşturma işlemi, onDrawMultiDoubleBufferedLayer()
geri çağırmasını tetikleyen commit()
işlevini çağırdığınızda devam eder.
Aşağıdaki örnekte, kullanıcı ekranda çizim yapmaya başladığında (ACTION_DOWN
) ve işaretçiyi etrafta hareket ettirdiğinde (ACTION_MOVE
) işlem ön arabelleğe (hızlı oluşturma) oluşturulur. İşaretçi ekran yüzeyinden (ACTION_UP
) ayrıldığında işlem çift arabelleğe oluşturulur.
Giriş sisteminin hareket etkinliklerini toplu olarak değil, kullanılabilir hale gelir gelmez yayınlamasını istemek için requestUnbufferedDispatch()
kullanabilirsiniz:
when (motionEvent.action) {
MotionEvent.ACTION_DOWN -> {
// Deliver input events as soon as they arrive.
view.requestUnbufferedDispatch(motionEvent)
// Pointer is in contact with the screen.
glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
}
MotionEvent.ACTION_MOVE -> {
// Pointer is moving.
glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
}
MotionEvent.ACTION_UP -> {
// Pointer is not in contact in the screen.
glFrontBufferRenderer.commit()
}
MotionEvent.CANCEL -> {
// Cancel front buffer; remove last motion set from the screen.
glFrontBufferRenderer.cancel()
}
}
Oluşturmayla ilgili yapılması ve yapılmaması gerekenler
Ekranın küçük bölümleri, el yazısı, çizim, eskiz.
Tam ekran güncelleme, kaydırma, yakınlaştırma. Yırtılmaya neden olabilir.
Yırtılma
Ekran arabelleği aynı anda değiştirilirken ekran yenilendiğinde yırtılma meydana gelir. Ekranın bir kısmında yeni veriler, bir başka bölümde ise eski veriler gösteriliyor.
Hareket tahmini
Jetpack hareket tahmini kitaplığı kullanıcının çizgi yolunu tahmin ederek ve oluşturucuya geçici, yapay noktalar sağlayarak algılanan gecikmeyi azaltır.
Hareket tahmini kitaplığı, gerçek kullanıcı girişlerini MotionEvent
nesneleri olarak alır.
Nesneler, hareket tahmincisi tarafından gelecekteki MotionEvent
nesnelerini tahmin etmek için kullanılan x ve y koordinatları, basınç ve zaman hakkında bilgiler içerir.
Tahmin edilen MotionEvent
nesneleri yalnızca tahminidir. Tahmin edilen etkinlikler, algılanan gecikmeyi azaltabilir. Ancak tahmin edilen veriler alındıktan sonra gerçek MotionEvent
verileri ile değiştirilmelidir.
Hareket tahmini kitaplığı, Android 4.4 (API düzeyi 19) ve sonraki sürümlerin yanı sıra Android 9 (API düzeyi 28) ve sonraki sürümleri çalıştıran ChromeOS cihazlarda kullanılabilir.
Bağımlılıklar
Hareket tahmini kitaplığı, tahminin uygulanmasını sağlar. Kitaplık, uygulamanın build.gradle
modülü dosyasına bir bağımlılık olarak eklenir:
dependencies {
implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}
Uygulama
Hareket tahmini kitaplığı, aşağıdaki yöntemleri tanımlayan MotionEventPredictor
arayüzünü içerir:
record()
: Kullanıcı işlemlerinin kaydı olarakMotionEvent
nesne depolarpredict()
: Tahmin edilen birMotionEvent
döndürür
MotionEventPredictor
örneği bildir
var motionEventPredictor = MotionEventPredictor.newInstance(view)
Tahminciye veri sağlayın
motionEventPredictor.record(motionEvent)
Tahmin
when (motionEvent.action) {
MotionEvent.ACTION_MOVE -> {
val predictedMotionEvent = motionEventPredictor?.predict()
if(predictedMotionEvent != null) {
// use predicted MotionEvent to inject a new artificial point
}
}
}
Hareket tahmininde yapılması ve yapılmaması gerekenler
Tahmin edilen yeni bir nokta eklendiğinde tahmin noktalarını kaldırır.
Nihai oluşturma işlemi için tahmin noktalarını kullanmayın.
Not alma uygulamaları
ChromeOS, uygulamanızın bazı not alma işlemlerini bildirmesine olanak tanır.
Bir uygulamayı ChromeOS'te not alma uygulaması olarak kaydetmek için Giriş uyumluluğu bölümüne bakın.
Bir uygulamayı Android'de not alma uygulaması olarak kaydetmek için Not alma uygulaması oluşturma bölümüne bakın.
Android 14 (API düzeyi 34), uygulamanızın kilit ekranında not alma etkinliği başlatmasını sağlayan ACTION_CREATE_NOTE
amacını kullanıma sundu.
ML Kit ile dijital mürekkep tanıma
ML Kit dijital mürekkep tanıma sayesinde uygulamanız, el yazısı metinleri dijital bir yüzeyde yüzlerce dilde tanıyabilir. Çizimleri de sınıflandırabilirsiniz.
ML Kit, el yazısını metne dönüştürmek için makine öğrenimi modelleri tarafından işlenebilecek Ink
nesne oluşturmak amacıyla Ink.Stroke.Builder
sınıfını sağlar.
Model, el yazısı tanımanın yanı sıra silme ve daire içine alma gibi hareketleri de tanıyabilir.
Daha fazla bilgi edinmek için Dijital mürekkep tanıma bölümüne bakın.