Dokunma ve işaretçi hareketlerini izleme

"Oluştur" yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Oluşturma'da dokunma ve giriş özelliklerini nasıl kullanacağınızı öğrenin.

Bu derste, dokunma etkinliklerinde hareketin nasıl izleneceği açıklanmaktadır.

Mevcut dokunma temas konumu, basınç veya boyut değiştiğinde bir ACTION_MOVE etkinliğiyle yeni bir onTouchEvent() tetiklenir. Genel hareketleri algılama bölümünde açıklandığı gibi, tüm bu etkinlikler onTouchEvent() MotionEvent parametresine kaydedilir.

Parmakla dokunma her zaman en kesin etkileşim biçimi olmadığı için dokunma olaylarını tespit etmek, genellikle basit temastan çok harekete dayalı olur. Android, uygulamaların harekete dayalı hareketleri (ör. kaydırma) ve hareket olmayan hareketleri (tek dokunma gibi) ayırt etmesine yardımcı olmak için dokunma açısı kavramını içerir. Dokunma eğimi, harekete dayalı bir hareket olarak yorumlanmadan önce kullanıcının dokunduğu alanın piksel cinsinden gidebileceği mesafeyi ifade eder. Bu konu hakkında daha fazla bilgi için ViewGroup'taki dokunma etkinliklerini yönetme konusuna bakın.

Uygulamanızın ihtiyaçlarına bağlı olarak, bir hareketteki hareketi izlemenin çeşitli yolları vardır. Aşağıda bazı örnekler verilmiştir:

  • Bir işaretçinin başlangıç ve bitiş konumu (ör. ekrandaki bir nesneyi A noktasından B noktasına taşımak).
  • İşaretçinin hareket ettiği yön, X ve Y koordinatlarıyla belirlenir.
  • Geçmiş'e dokunun. MotionEvent yöntemini getHistorySize() çağırarak hareket geçmişinin boyutunu bulabilirsiniz. Ardından, hareket etkinliğinin getHistorical<Value> yöntemlerini kullanarak geçmiş etkinliklerin her birinin konumlarını, boyutlarını, zamanını ve basınçlarını elde edebilirsiniz. Geçmişe kayıt, dokunarak çizimde olduğu gibi kullanıcının parmağının izi oluşturulurken kullanışlı olur. Ayrıntılar için MotionEvent referansına bakın.
  • İşaretçinin dokunmatik ekranda hareket ederken hızı.

Aşağıdaki ilgili kaynaklara bakın:

Hız izleme

İşaretçinin katettiği mesafeye veya yöne dayalı, harekete dayalı bir hareketiniz olabilir. Bununla birlikte, hız genellikle bir hareketin özelliklerinin izlenmesinde veya hareketin gerçekleşip gerçekleşmediğine karar verilirken belirleyici bir faktördür. Hız hesaplamasını kolaylaştırmak için Android, VelocityTracker sınıfını sağlar. VelocityTracker, dokunma etkinliklerinin hızını izlemenize yardımcı olur. Bu, hızla kaydırma gibi hızın hareket ölçütünün bir parçası olduğu hareketler için yararlıdır.

VelocityTracker API'deki yöntemlerin amacını gösteren bir örneği aşağıda bulabilirsiniz:

Kotlin

private const val DEBUG_TAG = "Velocity"

class MainActivity : Activity() {
    private var mVelocityTracker: VelocityTracker? = null

    override fun onTouchEvent(event: MotionEvent): Boolean {

        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                // Reset the velocity tracker back to its initial state.
                mVelocityTracker?.clear()
                // If necessary, retrieve a new VelocityTracker object to watch
                // the velocity of a motion.
                mVelocityTracker = mVelocityTracker ?: VelocityTracker.obtain()
                // Add a user's movement to the tracker.
                mVelocityTracker?.addMovement(event)
            }
            MotionEvent.ACTION_MOVE -> {
                mVelocityTracker?.apply {
                    val pointerId: Int = event.getPointerId(event.actionIndex)
                    addMovement(event)
                    // When you want to determine the velocity, call
                    // computeCurrentVelocity(). Then, call getXVelocity() and
                    // getYVelocity() to retrieve the velocity for each pointer
                    // ID.
                    computeCurrentVelocity(1000)
                    // Log velocity of pixels per second. It's best practice to
                    // use VelocityTrackerCompat where possible.
                    Log.d("", "X velocity: ${getXVelocity(pointerId)}")
                    Log.d("", "Y velocity: ${getYVelocity(pointerId)}")
                }
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker?.recycle()
                mVelocityTracker = null
            }
        }
        return true
    }
}

Java

public class MainActivity extends Activity {
    private static final String DEBUG_TAG = "Velocity";
        ...
    private VelocityTracker mVelocityTracker = null;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);

        switch(action) {
            case MotionEvent.ACTION_DOWN:
                if(mVelocityTracker == null) {
                    // Retrieve a new VelocityTracker object to watch the
                    // velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                }
                else {
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                }
                // Add a user's movement to the tracker.
                mVelocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.addMovement(event);
                // When you want to determine the velocity, call
                // computeCurrentVelocity(). Then call getXVelocity() and
                // getYVelocity() to retrieve the velocity for each pointer ID.
                mVelocityTracker.computeCurrentVelocity(1000);
                // Log velocity of pixels per second. It's best practice to use
                // VelocityTrackerCompat where possible.
                Log.d("", "X velocity: " + mVelocityTracker.getXVelocity(pointerId));
                Log.d("", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId));
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // Return a VelocityTracker object back to be re-used by others.
                mVelocityTracker.recycle();
                break;
        }
        return true;
    }
}

İşaretçi yakalamayı kullan

Oyunlar, uzaktan masaüstü ve sanallaştırma istemcileri gibi bazı uygulamalar, fare işaretçisi üzerinde kontrol sahibi olmanın avantajlarından faydalanır. İşaretçi yakalama, Android 8.0 (API düzeyi 26) ve sonraki sürümlerde kullanılabilen ve tüm fare etkinliklerini uygulamanızdaki odaklanmış bir görünüme göndererek bu kontrolü sağlayan bir özelliktir.

İşaretçi yakalama isteğinde bulun

Uygulamanızdaki bir görünüm, yalnızca onu içeren görünüm hiyerarşisinde odağı varsa işaretçi yakalama isteğinde bulunabilir. Bu nedenle, görünümde belirli bir kullanıcı işlemi olduğunda (ör. bir onClick() etkinliği veya etkinliğinizin onWindowFocusChanged() etkinlik işleyicisi sırasında) işaretçi yakalama isteği gönderin.

İşaretçi yakalama isteğinde bulunmak için görünümde requestPointerCapture() yöntemini çağırın. Aşağıdaki kod örneğinde, kullanıcı bir görünümü tıkladığında işaretçi yakalamanın nasıl isteneceği gösterilmektedir:

Kotlin

fun onClick(view: View) {
    view.requestPointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.requestPointerCapture();
}

İşaretçiyi yakalama isteği başarılı olduktan sonra Android, onPointerCaptureChange(true) numarasını çağırır. Sistem, fare etkinliklerini, yakalamayı isteyen görünümle aynı görünüm hiyerarşisinde olduğu sürece uygulamanızdaki odaklanmış görünüme sunar. Diğer uygulamalar, ACTION_OUTSIDE etkinlikleri de dahil olmak üzere, yakalama yayınlanana kadar fare etkinlikleri almayı durdurur. Android, fare dışındaki kaynaklardan işaretçi etkinliklerini normal olarak sunar ancak fare işaretçisi artık görünür değildir.

Yakalanan işaretçi etkinliklerini işleme

Görünüm, işaretçi yakalamayı başarıyla aldıktan sonra Android, fare etkinliklerini sunar. Odaklanmış görünümünüz aşağıdaki görevlerden birini gerçekleştirerek etkinlikleri yönetebilir:

Aşağıdaki kod örneğinde onCapturedPointerEvent(MotionEvent) kodunun nasıl uygulanacağı gösterilmektedir:

Kotlin

override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean {
    // Get the coordinates required by your app.
    val verticalOffset: Float = motionEvent.y
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true
}

Java

@Override
public boolean onCapturedPointerEvent(MotionEvent motionEvent) {
  // Get the coordinates required by your app.
  float verticalOffset = motionEvent.getY();
  // Use the coordinates to update your view and return true if the event is
  // successfully processed.
  return true;
}

Aşağıdaki kod örneğinde OnCapturedPointerListener alanının nasıl kaydedileceği gösterilmektedir:

Kotlin

myView.setOnCapturedPointerListener { view, motionEvent ->
    // Get the coordinates required by your app.
    val horizontalOffset: Float = motionEvent.x
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    true
}

Java

myView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() {
  @Override
  public boolean onCapturedPointer (View view, MotionEvent motionEvent) {
    // Get the coordinates required by your app.
    float horizontalOffset = motionEvent.getX();
    // Use the coordinates to update your view and return true if the event is
    // successfully processed.
    return true;
  }
});

İster özel bir görünüm kullanın ister bir işleyici kaydedin, görünümünüz bir iztopu cihazı tarafından gönderilen koordinatlara benzer şekilde X veya Y delta gibi göreli hareketleri belirten işaretçi koordinatları içeren bir MotionEvent alır. getX() ve getY() kullanarak koordinatları alabilirsiniz.

İşaretçi yakalamayı bırakın

Uygulamanızdaki görünüm, aşağıdaki kod örneğinde gösterildiği gibi releasePointerCapture() çağrısı yaparak işaretçi yakalamayı serbest bırakabilir:

Kotlin

override fun onClick(view: View) {
    view.releasePointerCapture()
}

Java

@Override
public void onClick(View view) {
    view.releasePointerCapture();
}

Sistem, genellikle releasePointerCapture() öğesini çağırmadan yakalamayı görünümden kaldırabilir. Bunun nedeni, genellikle yakalama isteğinde bulunan görünümü içeren görünüm hiyerarşisinin odağı kaybetmesidir.