Anlaşılması gereken birkaç terim ve kavram vardır harekete geçme olasılığının daha yüksek olduğunu gördük. Bu sayfada, geçerli olan ve farklı soyutlamayı tanıtıyor. hareketler için düzeyler. Ayrıca etkinlik tüketimi ve yayılımıdır.
Tanımlar
Bu sayfadaki çeşitli kavramları anlamak için bazı kavramları anlamanız gerekir. tam olarak aynısı:
- İşaretçi: Uygulamanızla etkileşimde bulunmak için kullanabileceğiniz fiziksel bir nesne.
Mobil cihazlarda, en yaygın işaretçi parmağınızın
dokunun. Alternatif olarak, parmağınızın yerine ekran kalemi de kullanabilirsiniz.
Büyük ekranlarda ise mobil cihazlarla dolaylı olarak etkileşim kurmak için
görebilirsiniz. Giriş cihazı, "işaretleme" özelliğini kullanabilmelidir. koordineli olacak şekilde
dolayısıyla, örneğin klavye bir işaretçi olarak
tıklayın. Oluşturma sekmesinde işaretçi türü,
PointerType
. - İşaretçi etkinliği: Bir veya daha fazla işaretçinin alt düzey etkileşimini tanımlar
ilişkili olması gerekir. Her bir işaretçi etkileşimi (örneğin,
veya fareyi sürüklemek bir etkinliği tetikler. İçinde
Oluşturma, bu tür bir olaya ilişkin tüm bilgilerin
PointerEvent
sınıfı. - Hareket: Tek bir hareket olarak yorumlanabilecek işaretçi etkinlikleri dizisi eyleme dökülebilir. Örneğin, dokunma hareketi bir aşağı hareket dizisi olarak kabul edilebilir ardından bir yukarı etkinlik vardır. Pek çok kişi tarafından kullanılan yaygın hareketler vardır. dokunma, sürükleme veya dönüştürme gibi uygulamaların yanı sıra kendi özel klasörlerinizi de oluşturabilirsiniz. hareket ettirebilirsiniz.
Farklı soyutlama düzeyleri
Jetpack Compose, hareketleri kullanmak için farklı soyutlama düzeyleri sunar.
Üst düzeyde bileşen desteği bulunur. Button
gibi besteler
hareket desteğini otomatik olarak dahil eder. Özel öğeye hareket desteği eklemek için
bileşenlerine odaklanmak yerine clickable
gibi hareket değiştiriciler ekleyebilirsiniz
composables. Son olarak, özel bir harekete ihtiyacınız varsa
pointerInput
değiştiricisi.
Kural olarak, soruyu çözen en üst düzey soyutlamanın üzerine
işlevlerinden yararlanabilirsiniz. Böylece, buradaki en iyi uygulamalardan yararlanabilirsiniz
var. Örneğin, Button
daha fazla anlamsal bilgi içerir,
daha fazla bilgi içeren clickable
değerine kıyasla daha yüksek
pointerInput
uygulaması.
Bileşen desteği
Oluşturma'daki kullanıma hazır bileşenlerin çoğunda bir tür dahili hareket bulunur
ele alacağız. Örneğin, bir LazyColumn
sürükleme hareketlerine şu şekilde yanıt verir:
içeriğini kaydırdığınızda, Button
içeriğe bastığınızda bir dalga
SwipeToDismiss
bileşeni bir öğeyi kapatmak için kaydırma mantığı
öğesine dokunun. Bu tür hareket işleme otomatik olarak çalışır.
Dahili hareket işlemenin yanı sıra, birçok bileşen için çağrı yapan kullanıcının
hareketi kullan. Örneğin, bir Button
dokunmaları otomatik olarak algılar
ve bir tıklama etkinliğini tetikler. Button
yönüne giden onClick
lambdayı
harekete tepki verebilir. Benzer şekilde, onValueChange
Kullanıcının kaydırma çubuğu tutma yerini sürüklemesine tepki vermek için Slider
.
Kullanım alanınıza uyduğunda, bileşenlere dahil edilen hareketleri tercih edin.
odak ve erişilebilirlik için kullanıma hazır destek içerir.
olarak test edilmiştir. Örneğin, bir Button
özel bir şekilde işaretlenir;
erişilebilirlik hizmetlerinin bunu yalnızca herhangi bir öğe yerine bir düğme olarak tanımlaması
tıklanabilir öğe:
// Talkback: "Click me!, Button, double tap to activate" Button(onClick = { /* TODO */ }) { Text("Click me!") } // Talkback: "Click me!, double tap to activate" Box(Modifier.clickable { /* TODO */ }) { Text("Click me!") }
Compose'da erişilebilirlik hakkında daha fazla bilgi edinmek için Erişilebilirlik Oluştur'u tıklayın.
Değiştiricilerle rastgele composable'lara belirli hareketler ekleme
Rastgele istediğiniz composable'a hareket değiştiricileri uygulayarak
hareketleri dinleyebilirsiniz. Örneğin, genel bir Box
dokunma hareketlerini clickable
yaparak tutun veya Column
dikey kaydırmayı yönetmek için verticalScroll
uygulayın.
Farklı hareket türlerini işlemek için birçok değiştirici vardır:
- Dokunma ve basma işlemlerini
clickable
ile yapın.combinedClickable
,selectable
,toggleable
vetriStateToggleable
değiştiricileri kullanın. horizontalScroll
ile kaydırma tutma yerini tutmaverticalScroll
ve daha genelscrollable
değiştiricileri içerir.draggable
veswipeable
ile sürükleme işlemini gerçekleştirme kullanabilirsiniz.- Kaydırma, döndürme ve yakınlaştırma gibi çoklu dokunma hareketlerini
transformable
değiştiricisine basın.
Kural olarak, özel hareket işleme yerine kullanıma hazır hareket değiştiricileri tercih edin.
Değiştiriciler, işaretçi etkinlik işlemenin yanı sıra daha fazla işlev sunar.
Örneğin, clickable
değiştiricisi yalnızca basmaları algılamayı değil, aynı zamanda
dokunmaların yanı sıra anlamsal bilgiler ve
etkileşimlerle ilgili görsel işaretler de
fareyle üzerine gelme, odaklanma ve klavye desteği. Kaynak kodunu kontrol edebilirsiniz
inceleyin, işlevselliğin nasıl olduğunu görmek için clickable
ekleniyor.
pointerInput
değiştiriciyle rastgele composable'lara özel hareket ekleyin
Her hareket, kullanıma hazır bir hareket değiştiriciyle uygulanmaz. Örneğin,
Örneğin, uzun bastıktan sonra sürüklemeye tepki vermek için bir değiştirici
kontrol tuşunu basılı tutarken tıklamanızı veya üç parmakla dokunmanızı öneririz. Bunun yerine kendi hareketinizi yazabilirsiniz
işleyiciyi kullanarak bu özel hareketleri tanımlayabilirsiniz. Hareket işleyici oluşturmak için
Ham işaretçiye erişmenizi sağlayan pointerInput
değiştiricisi
etkinlikler.
Aşağıdaki kod, ham işaretçi etkinliklerini dinler:
@Composable private fun LogPointerEvents(filter: PointerEventType? = null) { var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(filter) { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() // handle pointer event if (filter == null || event.type == filter) { log = "${event.type}, ${event.changes.first().position}" } } } } ) } }
Bu snippet'i bölerseniz temel bileşenler şu şekilde olur:
pointerInput
değiştiricisi. Bir veya daha fazla anahtar geçirirsiniz. değeri değişirse, değiştirici içeriği lambda'sı yeniden yürütülür. Örnek, composable'a isteğe bağlı bir filtre iletir. Eğer değeri değişirse işaretçi etkinlik işleyicinin yeniden yürütülür.awaitPointerEventScope
, şunları yapmak için kullanılabilecek, eş değer bir kapsam oluşturur: işaretçi etkinliklerini bekleyin.awaitPointerEvent
, eş yordamı sonraki işaretçi etkinliğine kadar askıya alır gerçekleşir.
Ham giriş etkinliklerini dinlemek güçlü olsa da yazmak da karmaşıktır. bu ham verilere dayalı özel bir harekettir. Özel öğeler oluşturulmasını kolaylaştırmak için hareketlerinde birçok yardımcı yöntem kullanılabilir.
Tüm hareketleri algıla
Ham işaretçi etkinliklerini işlemek yerine belirli hareketleri dinleyebilirsiniz.
ve uygun şekilde yanıt vermesi gerekir. AwaitPointerEventScope
,
dinleme yöntemleri:
- Basın, dokunun, iki kez dokunun ve uzun basın:
detectTapGestures
- Sürüklemeler:
detectHorizontalDragGestures
,detectVerticalDragGestures
,detectDragGestures
vedetectDragGesturesAfterLongPress
- Dönüşümler:
detectTransformGestures
Bunlar üst düzey algılayıcılardır. Dolayısıyla, tek bir algılayıcıya birden çok algılayıcı ekleyemezsiniz.
pointerInput
değiştiricisi. Aşağıdaki snippet yalnızca dokunmaları algılar,
sürükler:
var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(Unit) { detectTapGestures { log = "Tap!" } // Never reached detectDragGestures { _, _ -> log = "Dragging" } } ) }
Dahili olarak detectTapGestures
yöntemi eş yordamı engeller ve ikinci
algılayıcıya hiçbir zaman ulaşılmadı. Görüşmeye birden fazla hareket işleyici eklemeniz gerekiyorsa
bunun yerine ayrı pointerInput
değiştirici örnekleri kullanın:
var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(Unit) { detectTapGestures { log = "Tap!" } } .pointerInput(Unit) { // These drag events will correctly be triggered detectDragGestures { _, _ -> log = "Dragging" } } ) }
Hareket başına etkinlik işleme
Hareketler, tanımı gereği aşağı işaretçi etkinliğiyle başlar. URL parametrelerinin Google tarafından nasıl ele alınmasını istediğinizi belirtmek için
Bu durumda while(true)
döngüsü yerine awaitEachGesture
yardımcı yöntemi
her bir ham etkinlikten geçer. awaitEachGesture
yöntemi, yeniden başlatılacak
tüm işaretçiler kaldırıldığında hareketin "yapıldığını" belirten blok
tamamlandı:
@Composable private fun SimpleClickable(onClick: () -> Unit) { Box( Modifier .size(100.dp) .pointerInput(onClick) { awaitEachGesture { awaitFirstDown().also { it.consume() } val up = waitForUpOrCancellation() if (up != null) { up.consume() onClick() } } } ) }
Pratikte, kullanmadığınız sürece neredeyse her zaman awaitEachGesture
Hareketleri tanımlamadan işaretçi etkinliklerine yanıt verme. Buna örnek olarak
hoverable
: İşaretçi aşağı veya yukarı hareketlerine yanıt vermez. Yalnızca
bilmesi gerekir.
Belirli bir etkinliği veya alt hareketi bekleme
Hareketlerin yaygın kısımlarını tanımlamaya yardımcı olan bir dizi yöntem vardır:
awaitFirstDown
ile işaretçi aşağılanana kadar askıya alın veya tüm uyarıları bekleyin daha iyi sonuçlar elde etmek içinwaitForUpOrCancellation
kullanabilirsiniz.awaitTouchSlopOrCancellation
kullanarak alt düzey bir sürükleme işleyici oluşturun veawaitDragOrCancellation
. Hareket işleyici ilk olarak şu zamana kadar askıya alınır: İşaretçi dokunma açısına ulaşır ve ardından ilk sürükleme etkinliğine kadar askıya alınır ortaya çıkıyor. Yalnızca tek bir eksen üzerinde sürüklemeyle ilgileniyorsanızawaitHorizontalTouchSlopOrCancellation
artıawaitHorizontalDragOrCancellation
veyaawaitVerticalTouchSlopOrCancellation
artıawaitVerticalDragOrCancellation
tıklayın.awaitLongPressOrCancellation
ile uzun basılana kadar askıya alma.- Sürükleme etkinliklerini sürekli olarak dinlemek için
drag
yöntemini kullanın veya Birindeki etkinlikleri sürüklemek içinhorizontalDrag
veyaverticalDrag
eksenini seçin.
Çok noktalı etkinliklere ilişkin hesaplamaları uygulama
Bir kullanıcı birden fazla işaretçi kullanarak çoklu dokunma hareketi yaptığında
ham değerlere göre gerekli dönüşümün anlaşılması karmaşıktır.
transformable
değiştiricisi veya detectTransformGestures
yöntemlerinin kullanım alanınız için yeterince ayrıntılı kontrol sağlamadığını
ham etkinlikleri dinleyip bunlara hesaplamalar yapabilirsiniz. Bu yardımcı yöntemler
şunlardır: calculateCentroid
, calculateCentroidSize
,
calculatePan
, calculateRotation
ve calculateZoom
.
Etkinlik gönderme ve isabet testi
Her işaretçi etkinliği her pointerInput
değiştiriciye gönderilmez. Etkinlik
işlevi şu şekilde çalışır:
- İşaretçi etkinlikleri bir composable hiyerarşiye gönderilir. Bir kullanıcının yeni işaretçi ilk işaretçi etkinliğini tetikler. Sistem, isabet testine "uygun" composables. Bir composable aşağıdaki durumlarda uygun kabul edilir: İşaretçi girişi işleme özellikleri. Kullanıcı arayüzünün üst kısmından isabet testi akışları bir plan yapın. Bir composable, "isabet"tir. İşaretçi etkinliği gerçekleştiğinde emin olmanız gerekir. Bu işlem, her öğenin composable'ların olumlu sonuçlar verdiğini görüyor.
- Varsayılan olarak
yalnızca en yüksek Z-endeksine sahip composable "isabet"tir. Örneğin,
Örneğin, bir
Box
öğesine çakışan ikiButton
composable eklediğinizde, bu işlem yalnızca en üste çizilen etkinlik, tüm işaretçi etkinliklerini alır. Teorik olarak KendiPointerInputModifierNode
öğenizi oluşturarak bu davranışı geçersiz kılın uygulama vesharePointerInputWithSiblings
değerini "doğru" olarak ayarlama. - Aynı işaretçi için diğer etkinlikler aynı işaretleyiciye composable'ların yanı sıra etkinlik yayılım mantığına göre akış gösterir. Sistem artık bu işaretçi için isabet testi yapmaz. Bunun anlamı, her bir composable, zincirdeki composable, bunlar, composable'ın sınırlarının dışında gerçekleşir. Özelleştirilebilir zincirinde işaretçi etkin olmasa bile hiçbir zaman işaretçi dışına çıkamazlar.
Fareyle veya ekran kaleminin üzerine gelmesiyle tetiklenen fareyle üzerine gelme etkinlikleri, kurallarından birini seçin. Fareyle üzerine gelme etkinlikleri, isabet ettikleri composable'lara gönderilir. ODK Kullanıcı işaretçiyi bir composable'ın sınırlarından diğerine geçtiğinde, etkinlikler, bu ilk composable'a gönderilmek yerine yeni composable.
Etkinlik tüketimi
Birden fazla composable'a hareket işleyici atanmışsa çakışmamalıdır. Örneğin, şu kullanıcı arayüzüne bir göz atın:
Kullanıcı yer işareti düğmesine dokunduğunda, düğmenin onClick
lambda'sı bunu işler
hareketi yapın. Kullanıcı, liste öğesinin başka bir bölümüne dokunduğunda ListItem
Ardından bu hareketi gerçekleştirir ve makaleye gider. İşaretçi girdisi olarak,
Düğmenin bu etkinliği kullanması gerekir. Böylece, ebeveynin
tepki verebilir. Kullanıma hazır bileşenlerde bulunan hareketler
genel hareket değiştiriciler bu tüketim davranışını içerir, ancak
hareketinizi yazarken etkinlikleri manuel olarak kullanmanız gerekir. Şunu yapacaksınız:
PointerInputChange.consume
yöntemiyle:
Modifier.pointerInput(Unit) { awaitEachGesture { while (true) { val event = awaitPointerEvent() // consume all changes event.changes.forEach { it.consume() } } } }
Bir etkinliğin kullanılması, etkinliğin diğer composable'lara yayılmasını durdurmaz. CEVAP composable'ın, tüketilen etkinlikleri açıkça yoksayması gerekir. Yazarken bir etkinliğin başka bir etkinlik tarafından kullanılıp kullanılmadığını öğe:
Modifier.pointerInput(Unit) { awaitEachGesture { while (true) { val event = awaitPointerEvent() if (event.changes.any { it.isConsumed }) { // A pointer is consumed by another gesture handler } else { // Handle unconsumed event } } } }
Etkinlik yayılımı
Daha önce de belirtildiği gibi, işaretçi değişiklikleri, ulaştığı her composable'a iletilir.
Peki, böyle birden fazla composable varsa etkinlikler hangi sırayla
yayılır mı? Son bölümdeki örneği alırsak bu kullanıcı arayüzü,
yalnızca ListItem
ve Button
öğesinin yanıt verdiği aşağıdaki kullanıcı arayüzü ağacı
işaretçi etkinlikleri:
İşaretçi etkinlikleri, bu composable'ların her birinden üç kez, üçüncü sırada "passes":
- İlk geçişte etkinlik, kullanıcı arayüzü ağacının tepesinden başlayıp
tıklayın. Bu akış, çocuk henüz müdahale etmeden bir ebeveynin etkinliğe müdahale etmesine olanak tanır.
onu tüketirim. Örneğin, ipuçlarının bir meta veri içeriğini
çocuklara uzun basmak yerine Şurada:
örnek olarak
ListItem
, etkinliğiButton
öncesinde alır. - Ana kartta etkinlik, kullanıcı arayüzü ağacının yaprak düğümlerinden
kök olacaktır. Bu aşamada normalde hareketleri tüketirsiniz ve
varsayılan geçiş kartıdır. Bu karttaki hareketler işleniyor
yaprak düğümlerinin, üst düğümlerine göre öncelikli olduğu anlamına gelir.
çoğu hareket için en mantıklı davranıştır. Örneğimizde
Button
,ListItem
öncesindeki etkinliğe. - Son geçişte, etkinlik kullanıcı arayüzünün üst tarafından bir kez daha akar. yaprak düğümlerine taşımaya başladı. Bu akış, yığında daha yüksek olan öğelerin ve ebeveynleri tarafından tüketimlerine yanıt vermelerine yardımcı olur. Örneğin, bir düğme kaydırma çubuğu, kaydırılabilir üst öğesinin sürüklemesine dönüştüğünde dalga göstergesi.
Etkinlik akışı görsel olarak aşağıdaki gibi gösterilebilir:
Bir giriş değişikliği kullanıldığında, bu bilgi yeni bir noktada:
Kodda, ilgilendiğiniz kartı belirtebilirsiniz:
Modifier.pointerInput(Unit) { awaitPointerEventScope { val eventOnInitialPass = awaitPointerEvent(PointerEventPass.Initial) val eventOnMainPass = awaitPointerEvent(PointerEventPass.Main) // default val eventOnFinalPass = awaitPointerEvent(PointerEventPass.Final) } }
Bu kod snippet'inde, her bir kod snippet'inde aynı etkinliği bunlar yöntem çağrılarını bekliyor, ancak tüketimle ilgili veriler değiştirildi.
Hareketleri test edin
Test yöntemlerinizde,
performTouchInput
yöntemini kullanabilirsiniz. Bu, ister üst düzey ister
tam hareketler (ör. sıkıştırma veya uzun tıklama) ya da düşük seviyeli hareketler (ör.
imleci belirli bir piksel kadar hareket ettirdiğinizde):
composeTestRule.onNodeWithTag("MyList").performTouchInput { swipeUp() swipeDown() click() }
Daha fazla örnek için performTouchInput
belgelerine bakın.
Daha fazla bilgi
Jetpack Compose'daki hareketler hakkında daha fazla bilgiyi aşağıdaki bölümlerde bulabilirsiniz. kaynaklar:
ziyaret edin.Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Compose'da erişilebilirlik
- Kaydırma
- Dokunup basma