يعد رسم واجهة مستخدم جزءًا واحدًا فقط من إنشاء طريقة عرض مخصصة. يجب عليك أيضًا جعل طريقة العرض تستجيب لإدخال المستخدم بطريقة تشبه إلى حد كبير حركة العالم الحقيقي التي تحاكيها.
جعل العناصر في تطبيقك تعمل مثل العناصر الحقيقية على سبيل المثال، لا تدع الصور في تطبيقك تظهر خارج الوجود ثم تظهر مرة أخرى في مكان آخر، نظرًا لأن الكائنات في العالم الحقيقي لا تفعل ذلك. بدلاً من ذلك، انقل صورك من مكان إلى البعض
يشعر المستخدمون بسلوكيات خفية أو شعور تجاه واجهة ما ويتفاعلون بشكل أفضل مع التفاصيل الدقيقة التي تحاكي العالم الحقيقي. فعلى سبيل المثال، عندما يتنقل المستخدمون كائن واجهة مستخدم، ويمنحهم إحساسًا بالقصور الذاتي في البداية مما يؤخر الحركة. في النهاية من الحركة، يمنحهم إحساسًا بالزخم الذي يحمل الكائن إلى ما وراء قذف
توضح هذه الصفحة كيفية استخدام ميزات إطار عمل Android لإضافة هذه السلوكيات في العالم الحقيقي إلى طريقة العرض المخصّصة لديك
يمكنك العثور على معلومات إضافية ذات صلة في نظرة عامة على أحداث الإدخال تحريك الموقع نظرة عامة.
التعامل مع إيماءات الإدخال
على غرار العديد من أطر عمل واجهة المستخدم الأخرى، يتيح Android نموذج إدخال الأحداث. مستخدِم
تتحول إلى أحداث تؤدي إلى استدعاءات، ويمكنك إلغاء
لطلبات معاودة الاتصال لتخصيص كيفية استجابة تطبيقك للمستخدم. الإدخال الأكثر شيوعًا
الحدث في نظام Android وهو حدث Touch، ما يؤدي إلى تشغيل
onTouchEvent(android.view.MotionEvent)
يمكنك تجاهُل هذه الطريقة للتعامل مع الحدث، كما يلي:
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return super.onTouchEvent(event) }
Java
@Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
أحداث اللمس وحدها ليست مفيدة بشكل خاص. واجهات مستخدم بلمسة عصرية
تحديد التفاعلات من حيث الإيماءات مثل النقر والسحب والدفع
والقفز والتكبير. لتحويل أحداث اللمس الأولية إلى إيماءات، يستخدم Android
توفّر
GestureDetector
إنشاء GestureDetector
بتمريرها في نسخة افتراضية من فئة معيّنة
تنفّذ
GestureDetector.OnGestureListener
إذا كنت تريد معالجة بعض الإيماءات فقط، فيمكنك تمديد
GestureDetector.SimpleOnGestureListener
بدلاً من تنفيذ سياسة "GestureDetector.OnGestureListener
"
من واجهة pyplot. على سبيل المثال، تُنشئ هذه التعليمة البرمجية فئة تمتد
GestureDetector.SimpleOnGestureListener
وعمليات الإلغاء
onDown(MotionEvent)
Kotlin
private val myListener = object : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { return true } } private val detector: GestureDetector = GestureDetector(context, myListener)
Java
class MyListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } } detector = new GestureDetector(getContext(), new MyListener());
سواء كنت تستخدم GestureDetector.SimpleOnGestureListener
أم لا
تنفيذ
onDown()
التي تُرجع true
. يعد ذلك ضروريًا لأن جميع الإيماءات
تبدأ برسالة onDown()
. في حال إرجاع مبلغ false
من onDown()
، باسم
يفعل GestureDetector.SimpleOnGestureListener
ذلك، ويفترض النظام
تريد تجاهل بقية الإيماءة، والطرق الأخرى
لا يتم استدعاء GestureDetector.OnGestureListener
. الإرجاع فقط
false
من onDown()
إذا كنت تريد تجاهل مجموعة
إيماءة.
بعد تنفيذ GestureDetector.OnGestureListener
وإنشاء
وهي مثيل لـ GestureDetector
، يمكنك استخدام
GestureDetector
لتفسير أحداث اللمس التي تتلقاها
onTouchEvent()
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return detector.onTouchEvent(event).let { result -> if (!result) { if (event.action == MotionEvent.ACTION_UP) { stopScrolling() true } else false } else true } }
Java
@Override public boolean onTouchEvent(MotionEvent event) { boolean result = detector.onTouchEvent(event); if (!result) { if (event.getAction() == MotionEvent.ACTION_UP) { stopScrolling(); result = true; } } return result; }
عند تجاوز onTouchEvent()
حدث لمس غير صحيح
يتم التعرف عليها كجزء من الإيماءة، ويتم عرض false
. يمكنك بعد ذلك تنفيذ
الرمز المخصص الخاص باكتشاف الإيماءات.
إنشاء حركة معقولة جسديًا
الإيماءات هي طريقة فعالة للتحكم في الأجهزة ذات الشاشات التي تعمل باللمس، إلا أنه يمكن بعكس البديهية ويصعب تذكرها ما لم تنتج جسدًا نتائج معقولة.
على سبيل المثال، لنفترض أنك تريد تنفيذ إيماءة التنقُّل الأفقي لتعيين العنصر المرسوم في طريقة العرض مع الدوران حول محوره الرأسي. هذه الإيماءة منطقية إذا استجابت واجهة المستخدم بالتحرك بسرعة في اتجاه الاتجاه، ثم البطء، كما لو كان المستخدم يدفع دولاب العجلة ويجعلها تدور.
المستندات التي تتناول كيفية
تحريك التمرير
الإيماءة تقدّم شرحًا تفصيليًا حول كيفية تنفيذ جمجمتك الخاصة
السلوك. لكن محاكاة إحساس الحدافة ليس أمرًا تافهًا. الكثير من الفيزياء
والرياضيات لكي يعمل نموذج الحدافة بشكل صحيح. لحسن الحظ،
ويوفّر Android صفوفًا مساعدة لمحاكاة هذا السلوك وغيره من السلوكيات. تشير رسالة الأشكال البيانية
Scroller
الفئة هو الأساس للتعامل مع إيماءات التنقل بنمط حدافة.
لبدء الانتقال السريع، يُرجى الاتصال
fling()
مع سرعة البدء والحد الأدنى والأقصى س وص
قيم الانتقال. بالنسبة لقيمة السرعة، يمكنك استخدام القيمة المحسوبة بواسطة
GestureDetector
Kotlin
fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { scroller.fling( currentX, currentY, (velocityX / SCALE).toInt(), (velocityY / SCALE).toInt(), minX, minY, maxX, maxY ) postInvalidate() return true }
Java
@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY); postInvalidate(); return true; }
تساعد استدعاء "fling()
" في إعداد النموذج الفيزيائي للقفز.
إيماءة. بعد ذلك، يمكنك تعديل "Scroller
" من خلال الاتصال.
Scroller.computeScrollOffset()
على فترات منتظمة. يعدّل computeScrollOffset()
الحالة الداخلية لكائن Scroller
من خلال قراءة الوقت الحالي
استخدام النموذج الفيزيائي لحساب الموضعَين س وص عند ذلك
الوقت. اتصل
getCurrX()
أو
getCurrY()
لاسترداد هذه القيم.
تتجاوز معظم المشاهدات الرمزين x وy للكائن Scroller
.
المناصب مباشرة إلى
scrollTo()
يختلف هذا المثال قليلاً، إذ يستخدِم الموضع الحالي للتمرير x
لتعيين زاوية الدوران للعرض.
Kotlin
scroller.apply { if (!isFinished) { computeScrollOffset() setItemRotation(currX) } }
Java
if (!scroller.isFinished()) { scroller.computeScrollOffset(); setItemRotation(scroller.getCurrX()); }
تحسب الفئة Scroller
مواضع التمرير نيابة عنك، لكنها
لا يطبق هذه المواضع تلقائيًا على العرض. تطبيق الإحداثيات الجديدة
غالبًا بما يكفي لجعل الرسوم المتحركة المتحركة تبدو سلسة. هناك طريقتان
إجراء ذلك:
- فرض إعادة الرسم عن طريق الاتصال
postInvalidate()
بعد الاتصال بـfling()
. يتطلب هذا الأسلوب احتساب إزاحة التمرير فيonDraw()
واستدعاءpostInvalidate()
في كل مرة تساوي قيمة الانتقال التغييرات. - إعداد
ValueAnimator
الرسوم المتحركة طوال مدة الانتقال وإضافة مستمع لمعالجته تحديثات الرسوم المتحركة من خلال الاتصالaddUpdateListener()
تتيح لك هذه التقنية تحريك خصائصView
تسهيل الانتقالات
يتوقع المستخدمون أن تنتقل واجهة المستخدم الحديثة بسلاسة بين الحالات التالية: عناصر واجهة المستخدم يتلاشى للداخل والخارج بدلاً من الظهور ويختفي، وتبدأ الحركات وينتهي بسلاسة بدلاً من البدء والتوقف فجأة. نظام التشغيل Android صورة متحركة للخصائص إطار عمل جديد يجعل عمليات الانتقال السلسة أسهل.
لاستخدام نظام الرسوم المتحركة، كلما تغيرت خاصية ما يؤثر في
مظهر الملف الشخصي، فلا تغيِّر الموقع مباشرةً. بدلاً من ذلك، استخدم
ValueAnimator
لإجراء التغيير. في المثال التالي،
يؤدي تعديل العنصر الثانوي المحدد في طريقة العرض إلى جعل الجزء المعروض بالكامل
تدوير العرض بحيث يتم توسيط مؤشر التحديد.
تغيّر الدالة ValueAnimator
الدوران على مدى عدة مئات.
بالمللي ثانية، بدلاً من تعيين قيمة التدوير الجديدة على الفور.
Kotlin
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply { setIntValues(targetAngle) duration = AUTOCENTER_ANIM_DURATION start() }
Java
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0); autoCenterAnimator.setIntValues(targetAngle); autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION); autoCenterAnimator.start();
إذا كانت القيمة التي تريد تغييرها هي إحدى قيم View
الأساسية
الخصائص، فإن تنفيذ الرسوم المتحركة يكون أسهل، نظرًا لأن طرق العرض تشتمل على
ViewPropertyAnimator
التي تم تحسينها للحركة المتزامنة لخصائص متعددة، كما هو الحال في
المثال التالي:
Kotlin
animate() .rotation(targetAngle) .duration = ANIM_DURATION .start()
Java
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();