تتبُّع حركات اللمس والمؤشر

تجربة طريقة ComposeAllowed
Jetpack Compose هي مجموعة أدوات واجهة المستخدم التي ننصح بها لنظام التشغيل Android. تعرَّف على كيفية استخدام اللمس والإدخال في ميزة "إنشاء".

يصف هذا الدرس كيفية تتبع الحركة في أحداث الاتصال.

تحوّل في onTouchEvent() باستخدام السمة حدث ACTION_MOVE كلما تغير موضع اتصال اللمس أو الضغط أو الحجم الحالي. بالنسبة كما هو موضح في اكتشاف الإيماءات الشائعة، كلها أن يتم تسجيل هذه الأحداث في معلَمة MotionEvent onTouchEvent()

لأن اللمس الذي يعتمد على الأصابع ليس دائمًا أكثر أشكال التفاعل دقة، غالبًا ما يعتمد اكتشاف أحداث اللمس على الحركة أكثر من الاعتماد على ملامسة بسيطة. لمساعدة التطبيقات في التمييز بين الإيماءات المستندة إلى الحركة (مثل التمرير السريع) الإيماءات غير المتحركة (مثل النقر مرة واحدة)، يتضمن Android مفهوم شريط اللمس. تشير نقطة الانزلاق باللمس إلى المسافة بالبكسل التي يمكن أن يلمسها المستخدم تجوَّل قبل أن يتم تفسير الإيماءة على أنها إيماءة قائمة على الحركة. لمزيد من المعلومات، معلومات حول هذا الموضوع، يُرجى الاطّلاع على مقالة إدارة أحداث اللمس في ViewGroup

هناك عدة طرق لتتبع الحركة في إيماءة، اعتمادًا على احتياجات تطبيقك. في ما يلي أمثلة على ذلك:

  • موضع بداية المؤشر ونهايته، مثل تحريك مؤشر على الشاشة كائنًا من النقطة أ إلى النقطة ب.
  • الاتجاه الذي يتحرك فيه المؤشر، كما هو محدد في X وY الإحداثيات.
  • السجلّ. يمكنك العثور على حجم سجل الإيماءة من خلال استدعاء طريقة واحدة (MotionEvent) getHistorySize() ويمكنك بعد ذلك الحصول على المواضع والأحجام والوقت والضغوط لكل أداة من الأحداث التاريخية باستخدام حدث الحركة getHistorical<Value> الطرق. يُعد السجل مفيدًا عند عرض مسار بإصبع المستخدم، مثل كما هو الحال مع الرسم باللمس. يُرجى الاطّلاع على مرجع "MotionEvent" للحصول على التفاصيل.
  • سرعة المؤشر أثناء تحركه على الشاشة التي تعمل باللمس

يمكنك الاطّلاع على المراجع التالية ذات الصلة:

تتبُّع السرعة

يمكنك استخدام إيماءة قائمة على الحركة تستند إلى المسافة أو الاتجاه. ينتقل المؤشر. ومع ذلك، غالبًا ما تكون السرعة عاملاً حاسمًا في التتبع خصائص الإيماءة أو تحديد ما إذا كانت الإيماءة قد حدثت. لإجراء سهولة حساب السرعة، ويوفر Android صف واحد (VelocityTracker). يساعدك VelocityTracker في تتبُّع سرعة أحداث اللمس. هذا مفيد للإيماءات التي تكون فيها السرعة جزءًا من معايير الإيماءة، مثل القفز.

فيما يلي مثال يوضح الغرض من الطرق في واجهة برمجة تطبيقات VelocityTracker:

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;
    }
}

استخدام ميزة التقاط المؤشر

تستفيد بعض التطبيقات، مثل الألعاب وبرامج سطح المكتب البعيد وبرامج المحاكاة الافتراضية، من التحكم في مؤشر الماوس. "التقاط المؤشر" هي ميزة متوفّرة في الإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) والإصدارات الأحدث التي توفِّر هذا التحكُّم من خلال مع عرض جميع أحداث الماوس في عرض مركّز في تطبيقك.

طلب التقاط مؤشر الماوس

ولا يمكن لأحد المشاهدة في تطبيقك طلب التقاط مؤشر الماوس إلا عندما يكون التسلسل الهرمي لطرق العرض يحتوي عليها التركيز. ولهذا السبب، يمكنك طلب التقاط المؤشر عندما يكون هناك إجراء مستخدم معين على المشاهدة، كما هو الحال أثناء onClick() الحدث أو في onWindowFocusChanged() معالج الأحداث لنشاطك.

لطلب التقاط المؤشر، اتصل requestPointerCapture() في طريقة العرض. يوضّح مثال الرمز التالي كيفية طلب المؤشر تسجيله عندما ينقر المستخدم على مرة مشاهدة:

Kotlin

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

Java

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

بعد نجاح طلب التقاط المؤشر، يطلب Android onPointerCaptureChange(true) يعرض النظام أحداث الماوس في العرض محل التركيز في تطبيقك طالما يكون في نفس التسلسل الهرمي للعرض مثل العرض الذي طلب الالتقاط. مشاكل أخرى تتوقف التطبيقات عن تلقّي أحداث الماوس إلى أن يتم إيقاف عملية الالتقاط، بما في ذلك ACTION_OUTSIDE أحداث. يوفر Android أحداث المؤشر من مصادر أخرى غير الماوس طبيعية، ولكن مؤشر الماوس لم يعد مرئيًا.

التعامل مع أحداث المؤشر التي تم التقاطها

وبعد حصول طريقة العرض على التقاط المؤشر بنجاح، يسلم Android أحداث الماوس. ويمكن لطريقة العرض محل التركيز التعامل مع الأحداث من خلال تنفيذ أحد المهام التالية:

يوضّح مثال الرمز التالي طريقة التنفيذ onCapturedPointerEvent(MotionEvent):

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;
}

يوضح مثال الرمز التالي كيفية تسجيل OnCapturedPointerListener:

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;
  }
});

وسواء كنت تستخدم طريقة عرض مخصّصة أو تسجّل مستمعًا، ستتلقّى طريقة العرض MotionEvent بإحداثيات مؤشر تحدّد الحركات النسبية مثل X أو دلتا ص، على نحو يشبه الإحداثيات التي يتم تقديمها بواسطة جهاز كرة تعقب. يمكنك استرجاع الإحداثيات باستخدام getX() و getY()

تحرير لقطة المؤشر

يمكن رفع مستوى عرض المؤشر في التطبيق من خلال إجراء مكالمة releasePointerCapture()، كما هو موضح في مثال الرمز التالي:

Kotlin

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

Java

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

يمكن للنظام أن يحجب الصورة تمامًا بدون صوتك يستدعي releasePointerCapture()، عادةً بسبب العرض الهرمي للعرض الهرمي يحتوي على العرض الذي يطلب الالتقاط يفقد التركيز.