Dokunma ve işaretçi hareketlerini izleme

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

Bu derste, temas etkinliklerindeki hareketlerin nasıl izleneceği açıklanmaktadır.

Dokunmatik kişinin konumu, basıncı veya boyutu 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() öğesinin MotionEvent parametresine kaydedilir.

Parmakla dokunma her zaman en hassas etkileşim biçimi olmadığından, dokunma etkinliklerinin algılanması basit temastan ziyade genellikle harekete dayanır. Android, harekete dayalı hareketleri (ör. kaydırma) hareketsiz hareketleri (ör. tek bir dokunma) ayırt etmesine yardımcı olmak için dokunma kayması kavramını içerir. Dokunma eğimi, hareket, harekete dayalı bir hareket olarak yorumlanmadan önce kullanıcının dokunuşunun gezinebileceği piksel cinsinden mesafeyi ifade eder. Bu konu hakkında daha fazla bilgi için ViewGroup'ta dokunma etkinliklerini yönetme bölümüne bakın.

Uygulamanızın ihtiyaçlarına bağlı olarak, bir hareketle hareketi izlemenin birkaç yolu vardır. Aşağıda örnekler verilmiştir:

  • İşaretçinin başlangıç ve bitiş konumu. Örneğin, ekrandaki bir nesneyi A noktasından B noktasına hareket ettirir.
  • İşaretçinin ilerlediği yön (X ve Y koordinatlarıyla belirlenir).
  • Geçmiş'e dokunun. Bir hareket geçmişinin boyutunu MotionEvent yöntemini getHistorySize() çağırarak bulabilirsiniz. Daha sonra, hareket etkinliğinin getHistorical<Value> yöntemlerini kullanarak geçmiş etkinliklerin her birinin konumlarını, boyutlarını, zamanlarını ve basınçlarını elde edebilirsiniz. Geçmişe kayıt, kullanıcının parmağının izini oluştururken (dokunmatik çizimde olduğu gibi) yararlı olur. Ayrıntılar için MotionEvent referansına bakın.
  • İşaretçinin dokunmatik ekran boyunca hareket ettiği hız.

Aşağıdaki ilgili kaynakları inceleyin:

Hızı takip edin

İşaretçinin hareket ettiği mesafeye veya yöne dayalı, harekete dayalı bir hareket oluşturabilirsiniz. Bununla birlikte, hız genellikle bir hareketin özelliklerini izlemede veya hareketin gerçekleşip gerçekleşmediğine karar vermede belirleyici bir faktördür. Android, hız hesaplamasını kolaylaştırmak için VelocityTracker sınıfını sunar. VelocityTracker, dokunma etkinliklerinin hızını takip etmenize yardımcı olur. Bu, hızın hareket ölçütlerinin bir parçası olduğu hareketler (ör. hızla sallama) 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 yakalama özelliğini kullanma

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

İşaretçi yakalama isteğinde bulunma

Uygulamanızdaki bir görünüm, yalnızca söz konusu görünümü içeren görünüm hiyerarşisine odaklanıldığında 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şleyicisinde olduğu gibi) işaretçi yakalama isteğinde bulunun.

İş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ı olduğunda Android, onPointerCaptureChange(true) yöntemini çağırır. Sistem, yakalamayı isteyen görünümle aynı görünüm hiyerarşisinde olduğu sürece fare etkinliklerini uygulamanızdaki odaklanmış görünüme yayınlar. Diğer uygulamalar, yakalama yayınlanana kadar ACTION_OUTSIDE etkinlikleri gibi fare etkinliklerini almaz. Android, fare dışındaki kaynaklardan gelen işaretçi etkinliklerini normal gibi yayınlar, ancak fare işaretçisi artık görünmez.

Yakalanan işaretçi etkinliklerini işleme

Bir görünüm işaretçi yakalamayı başarılı bir şekilde edindikten sonra, Android fare etkinliklerini yayınlar. Odaklanılan görünümünüz, aşağıdaki görevlerden birini gerçekleştirerek etkinlikleri işleyebilir:

Aşağıdaki kod örneğinde onCapturedPointerEvent(MotionEvent) özelliğinin 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'in 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 dinleyiciyi kaydedin, görünümünüz, bir iztopu cihazının ilettiği koordinatlara benzer şekilde X veya Y delta gibi göreli hareketleri belirten işaretçi koordinatlarına sahip bir MotionEvent alır. Koordinatları almak için getX() ve getY() tuşlarını kullanabilirsiniz.

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

Aşağıdaki kod örneğinde gösterildiği gibi, uygulamanızdaki görünüm releasePointerCapture() yöntemini çağırarak 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, siz açıkça releasePointerCapture() çağrısı yapmadan yakalamayı görünümden kaldırabilir. Bunun nedeni genellikle, isteklerin yakaladığı görünümü içeren görünüm hiyerarşisinin odağı kaybetmesidir.