Jetpack Compose ile Gesture

Ömer Durmaz
5 min readOct 13, 2023

Merhaba! Bu yazımızda Jetpack compose ile ekrana dokunma hareketlerinin genel kullanımlarından ve ileri seviye kullanımlarından bahsedeceğiz. Öncelikle belirtmek isterim ki aşağıda anlatılacaklar kaynakçada gösterdiğim Google dökümanının Türkçeleştirilmiş, konu başlıkları daha basit şekilde açıklanmış ve örneklerle zengileştirilmiş hali olarak düşünebilirsiniz.

Tanımlar

Pointer: Pointer dediğimiz şey telefonlar için parmaklarımızdır. Tabletler gibi daha büyük ekranlar için de parmaklarımız dışında kalem kullanılabilir. Daha da büyük ekranlar için ise mouse ya da trackpad kullanılabilir. Buradaki önemli konu bir inputun pointer olabilmesi için ekranda bir koordinatı işaret ediyor olması gerekir. Yani bir klavye pointer sayılmaz. Bu pointer tipleri için PointerType classına bakabilirsiniz.

Pointer event: Pointer event kullanıcının ekrana olan etkileşimleridir. Pointerin tıklama esnasında z ekseninde önce aşağı sonra yukarı hareket etmesi, x ve y eksenlerinde hareket etmesi bu etkileşimlere örneklerdir. Bu etkileşimler eventleri tetikler ve bu eventler sayesinde biz kullanıcının amacını yorumlarız. En çok kullanılan eventlere de PointerEvents classı içinden erişebilirsiniz.

Gesture: Bir dizi eventin bir araya gelmesiyle bir gesture (davranış) oluşur. Yukarıda da verdiğimiz örnekteki gibi tıklama davranışında pointer z ekseninde aşağı ve yukarı hareket eder. Bu davranışın her bir hareketi bir event tetikler ve bu eventleri bir araya getirerek kullanıcının o nesneye tıklamaya çalıştığını yorumlarız.

Davranışların Farklı Seviyeleri

Burada yine tıklanma gesture’ ini örnek olarak alacağız. Bildiğiniz gibi Button componentinin kendi içinde dokunma davranışını dinleyen bir onClick methodu bulunmaktadır. Bu sayede kendimiz ek bir geliştirme yapmadan kullanıcı butona tıkladığında bunu anlayabiliriz. Ama farzedelim ki buton kullanmak istemiyoruz, Image componentini kullanacağız ve kullanıcı image’ e tıkladığında anlamak istiyoruz. Bunun için image’ e .clickable modifierı ekleyerek tıklanmayı dinleyebiliriz. Son olarak .clickable kullanmak istemiyoruz ama tıklanmayı dinlemek istiyoruz diyelim. Bu sefer de .pointerInput modifierı ekleyerek ve içine düşen eventleri kontrol ederek de tıklanmayı dinleyebiliriz. Gördüğünüz üzere üç farklı seviyede gesture dinleme yönteminden bahsettik. Ancak burada dikkat çekmek istenilen konu Buttonun içinde hazır gelen ve stabil olan onClick methodunu dinlemek varken .clickable ya da .pointerInput modifierlarını gerekmedikçe kullanmamalıyız. Çünkü button içine geliştirilen onClick methodu çok kez test edilmiş ve onaylamış bir yöntem iken pointerInput kullandığınızda içine yazacağınız kod performans ve güvenilirlik açısından ne kadar stabil emin olamazsınız. Ayrıca okunabilirlik açısından çok daha az kodla işinizi halletmek varken fazladan kod yazmak gereksizdir.

Componentların Desteklediği Bazı Dokunma Davranışları

Yukarıda bahsettiğimiz Button gibi bir çok Componentin kendi içinde bir gesture dinleyen özelliği vardır. Bunlardan bir tane olan LazyColumn içerisinde yatay ya da dikey kaydırmaları dinler. Ya da bir başka Component olan Slider da yine yatay kaydırmayı dinler. Bu kaydırma hareketine göre kendi içerisindeki değerleri günceller. Tüm bu gesture dinleyen componentler, kullanıldıkları yerlerde callback methodlar aracılığıyla bizi bilgilendirirler.

Not: Kullanımınıza göre eğer kendi içerisinde gesture dinleyen componentlar işinizi görüyorsa modifier olarak dokunma davranışını dinlemekten kaçının. Tüm bu erişilebilirlik methodlarını incelemek için buraya tıklayabilirsiniz.

        // 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!") }

Kendi oluşturduğumuz bir Composable’ a modifier ekleyerek gesture dinleme

Herhangi bir Composable methodda modifier ekleyerek gesture dinleyebileceğimizden bahsetmiştik. Örnek verecek olursak Image’ e .clickable modifier ekleyerek tıklanabilir yapabiliriz. Ya da Column’ a .verticalScroll modifier ekleyerek dikey kaydırılabilir yapabiliriz.

Tıklama özelliği modifierları:

clickable: Oluşturduğumuz composable methoda tıklanma özelliği getirir.

combinedClickable: Bu modifierı clickable modifierının gelişmiş versiyonu gibi düşünebiliriz. İçerisinde sadece tıklama kontrolünü değil ayrıca uzun basma ve çift tıklama kontrollerini de bize sunar.

selectable: Bu modifier ise bir composable listesi içinde sadece bir eleman seçilmesi gerekiyorsa kullanılabilecek özelliktir.

toggleable: Selectable gibi bir composable listesi içinde item seçilmesi isteniyorsa kullanılabilir.

triStateToggleable: Bu modifierın bir önceki modiferdan farkı üçüncü bir state’ i olmasıdır. toggleable içerisinde “seçili/seçili değil” stateleri var iken, bunun içerisinde üçüncü bir state olan belirsiz vardır. Bu sayede bu itemın seçili-seçili değil arasında değişirken ki anlık durumuna bağlı bir arayüz işlemi varsa kolayca kontrol edilip güncellenebilir. Aşağıda bir örneğini görebilirsiniz;

    var checked by remember { mutableStateOf(ToggleableState.Indeterminate) }
Text(
modifier = Modifier.triStateToggleable(
state = checked,
onClick = {
checked =
if (checked == ToggleableState.On) ToggleableState.Off else ToggleableState.On
}
),
text = checked.toString()
)

Kaydırma özelliği modifierları:

horizontalScroll: Oluşturulan composable layoutun içindeki itemların yatay olarak sürüklenmesini sağlar.

verticalScroll: Oluşturulan composable layoutun içindeki itemların dikey olarak sürüklenmesini sağlar.

scrollable: Orientation parametresi ile içindeki itemların yatay ya da dikey kaydırılabilmesini sağlar. Diğer scrollable modifierlarda sadece tek bir yöne yapıyorken bu modifier isteğe göre herhangi bir yöne kaydırma için kullanılabilir. ayrıca içerisine yazdığımız rememberScrollableState methoduna consumeScrollDelta parametresine vereceğimiz değer ile ne kadar uzunluktan sonra kaydırma işlemine izin vereceğimizi belirleyebiliriz.

Sürükleme özelliği modifierları:

draggable: Scrollable’ ın aksine yatay ve dikey yönde içerisindeki viewlerin değil de kendisinin kaydırılmasına yarar.

swipeable: Draggable modifierı gibi nesnenin yatay ya da dikey yönde kaydırılmasına yarar.

draggable modifier aynı anda yatay ve dikey kullanım örneği
Yukarıdaki kodun çıktısı

Çoklu dokunma dinleme modifierı:

transformable: Yakınlaştırma ya da döndürme gibi iki parmak gerektiren işlerde bu modifier kullanılabilir.

Aynı anda birden fazla gesture dinleme

Yukarıda pointerInput modifierı ile direkt dokunma eventlerini dinleyebiliriz demiştik. Birkaç kontrol ile bu eventleri bir araya getirerek kullanıcının hangi dokunma davranışını yaptığını anlayabiliriz. Bunun yanında pointerInput modifierı kendi içerisinde kullanabilmemiz için bir çok detect methodu oluşturmuş ve bunlardan birini seçerek de beklediğimiz gesture’ i dinleyebiliriz. Bu detect methodlardan bazıları şunlardır;

detectTapGestures: tıklama, çift tıklama ve uzun dokunmayı dinler ve çağırıldığı yer tetiklenir.

detectHorizontalDragGestures, detectVerticalDragGestures, detectDragGestures, detectDragGesturesAfterLongPress: Bu methodlar gesturelerini yakalayabilir.

detectTransformGestures: bu method sayesinde çoklu dokunma gesturelerini dinleyebiliriz.

Not: Bunlar üst seviye dinleyiciler oldukları için bunları aşağıdaki şekilde tek bir pointerInput modifier içinde kullanamazsınız.

var log by remember { mutableStateOf("") }
Column {
Text(log)
Box(
Modifier
.size(100.dp)
.background(Color.Red)
.pointerInput(Unit) {
detectTapGestures { log = "Tap!" }
// ikinci method asla çalışmaz
detectDragGestures { _, _ -> log = "Dragging" }
}
)
}

İkinci yazılan listener method hiçbir zaman tetiklenmeyecektir. Bunun yerine ikinci bir listener eklemek için aşağıdaki şekilde kullanmak gerekmektedir.

var log by remember { mutableStateOf("") }
Column {
Text(log)
Box(
Modifier
.size(100.dp)
.background(Color.Red)
.pointerInput(Unit) {
detectTapGestures { log = "Tap!" }
}
.pointerInput(Unit) {
// ikinci method da çalışır
detectDragGestures { _, _ -> log = "Dragging" }
}
)
}

Ayrıca bu detect methodları dışında direkt pointerInput içine gelen değerleri de kullanabilirsiniz.

Aynı anda birden fazla gesture dinleme örneği

Aynı anda tıklama, sürükleme, büyütme ve döndürme gesturelerinin dinlenmesi kod örneği
Yukarıdaki kodun çıktısı.

Evet bu yazımızda da genel Dokunma davranışını açıklamaya ve ilgili örnekler ile pekiştirmeye çalıştık. Umarım yazı sizin için de faydalı olur ve kendi geliştirmelerinizde takıldığınız yerleri çözebilirsiniz. Bir sonraki yazımda görüşmek üzere.

--

--