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

الخطة هي:
- مبادئ نهج التنمية في Badoo.
- دراسات الحالة.
- نظام التصميم.
- متى يتم تطبيق المبادئ الموصوفة.
هذه المقالة هي نسخة نصية من تقريري حول AppsConf ، يمكن مشاهدة الفيديو
هنا .
مبادئ نهج التنمية
يستخدم مئات الملايين من الأشخاص Badoo ، لذا لا يمكننا طرح وظائف جديدة إذا لم نكن متأكدين من أن المستخدمين سيحبونها ويثبتوا أنها مفيدة.
يتأثر نهجنا التنموي بعدة عوامل.
باستخدام اختبارات A / B
لدينا العشرات من اختبارات A / B النشطة على منصات الأجهزة المحمولة اليوم ، في حين تم الانتهاء من عدة مئات. وفقًا لذلك ، إذا أخذت تطبيق Badoo على جهازين مختلفين ، فمع وجود درجة عالية من الاحتمالية ، ستكون هناك بعض الاختلافات بينهما ، وربما تكون غير محسوسة للوهلة الأولى.
لماذا نحتاج إلى اختبارات A / B؟ من المهم أن نفهم أن ما يعتبره مديرو المنتجات ضروريًا ، وحتى ما يبدو واضحًا لنا ، ليس مفيدًا دائمًا في الواقع. في بعض الأحيان يتعين علينا حذف الكود الذي كتبناه قبل شهر أو شهرين فقط. في بعض الأحيان يكون من المنطقي اختبار فكرة وظيفية جديدة لفهم ما إذا كانت مناسبة أم لا. وإذا أحب المستخدمون الوظيفة ، فيمكننا بالفعل استثمار الوقت في تطويرها.
تقليل تكاليف التطوير
بالطبع ، نريد كل شيء للعمل بسرعة وتكون جميلة. ومع ذلك ، ليس من الممكن دائمًا تحقيق ذلك في وقت قصير. في بعض الأحيان يستغرق الكثير من الأيام. لتجنب هذه المشكلات ، نحاول مساعدة مديري المنتجات من خلال التقييم المسبق لتكلفة المهام والإشارة إلى ما يصعب علينا القيام به وما هو سهل.
معظم قاعدة المستخدم
تخيل أن لديك وظيفة وظيفية تعمل بشكل مثالي في جميع السيناريوهات على جميع الأجهزة ، ولكن في نفس الوقت هناك مجموعة من المستخدمين مع الأجهزة الصينية ، حيث لا يعمل كما هو متوقع تمامًا. في هذه الحالة ، قد لا يكون من المفيد حل المشكلة في أسرع وقت ممكن ، نظرًا لأن لديك على الأرجح مهام أكثر أهمية.
كيف يمكننا تسريع التنمية
دعونا نلقي نظرة على بعض الأمثلة التي توضح كيفية عمل هذه المبادئ. سنقدم هنا حالات حقيقية واجهناها في عملنا ، بالإضافة إلى خيارات حلول مدروسة.
بادئ ذي بدء ، أقترح عليك أن تفكر بنفسك في كيفية حل هذه الحالة. ثم سأدرس كل خيار من الخيارات مع توضيح سبب ظهوره / عدم ملاءمته لحالتنا.
مثال 1. زر تراكم التقدم
نحتاج إلى أن نظهر للمستخدم عملية تجميع القروض مع تقدم البطارية مع زوايا مدورة من 0 إلى 1.

ما هي خيارات الحل؟

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

الخيار ج: فقط خذ بضعة أيقونات وقم بتثبيتها على العميل وأظهر أحدها.

في حالتنا ، توصلنا إلى حلول B و C. وسوف نناقش بمزيد من التفصيل.

لماذا لا
خيار A ؟ يمكننا حل هذه المشكلة بالذات ، ليست معقدة. نستخدم نفس التصميم في نظام iOS وشبكة الجوال. وفقًا لذلك ، لا يوجد سبب للرفض والقول إننا لا نفعل ذلك ونحتاج إلى تصميم مختلف.

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

في الكود ، يبدو كالتالي:
data class GoalInProgress(val progress: Float) private val unchargedPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY) } private fun mixChargedAndUncharged(canvas: Canvas) { drawFullyCharged(canvas) drawUnchargedPart(canvas) }
لقد حذفت معظم الكود. اقرأ المزيد حول أقنعة الصورة النقطية في المقالة:
https://habr.com/ru/company/badoo/blog/310618/ . سوف تتعلم أيضًا منه كيفية مزج الأقنعة ، الآثار التي يجب تحقيقها وكيف تعمل من حيث الأداء.
يفي هذا الحل بنسبة 100 ٪ بمتطلباتنا ، أي أنه يجعل من الممكن إظهار التقدم من 0 إلى 1.
السلبية الوحيدة: إذا لم تقم بذلك من قبل ، فستضطر إلى قضاء بعض الوقت في اكتشاف أقنعة الصورة النقطية. بالإضافة إلى ذلك ، لا يزال يتعين عليك اللعب معهم ومشاهدة حالات الحواف والاختبار. أعتقد أنه في مجمل الأمر سيستغرق حوالي أربع ساعات.
الخيار C. نأخذ بضعة أنواع ثابتة من الأيقونات وحسب التقدم الذي نظهره واحدًا منها. على سبيل المثال ، إذا كان تقدم المستخدم أقل من 0.5 ، فسيتم عرض رمز فارغ. من الواضح أن هذا الحل لا يلبي 100 ٪ من المتطلبات. ولكن لتنفيذه ، تحتاج إلى كتابة خمسة سطور فقط من التعليمات البرمجية والحصول على ثلاثة أيقونات من المصمم.
fun getBackground(goal: GoalInProgress) = when (goal.progress) { in 0.0..0.5 -> R.drawable.ic_not_filled in 0.5..0.99 -> R.drawable.ic_half_filled else -> R.drawable.ic_full_filled }
علاوة على ذلك ، فإن هذا الحل هو الأمثل في ظروف النقص الشديد في الوقت (كما كان لدينا عندما أصدرنا وظيفة البث المباشر). لا يستغرق الأمر وقتًا طويلاً - يمكنك فقط طرحه واستبداله بالحل الجميل الصحيح في الإصدار التالي. في الواقع ، كما فعلنا في عصرنا.
مثال 2. خط لإدخال رقم هاتف
المثال التالي هو إدخال رقم الهاتف. ميزات مميزة:
- بادئة البلد إلى اليسار ؛
- لا يمكن حذف البادئة ؛
- هناك مسافة بادئة ؛
- البادئة غير قابلة للنقر.

دعونا نفكر في كيفية تنفيذ ذلك.

الخيار أ: اكتب TextWatcher مخصص يقوم بتنفيذ المنطق المطلوب. سوف تعقد هذه البادئة ، تشغل مساحة ، تتحكم في موضع المؤشر.
الخيار ب: تقسيم هذا المكون إلى حقلين مستقلين. من وجهة نظر واجهة المستخدم ، سيكون نفس المكون.
الخيار جيم: اسأل عن تصميم مختلف لجعله أسهل بالنسبة لنا.

قررنا تنفيذ الخيار B. النظر في مزيد من التفاصيل.

أن نسأل عن تصميم مختلف (الخيار C) هو أول شيء حاولنا القيام به. ومع ذلك ، أصرت المنتجات على الفكرة الأولية. وإذا كانت الشركة تصر على نوع من الوظائف ، فإن مهمتنا هي تنفيذها.
يبدو Custom TextWatcher (الخيار A) للوهلة الأولى فقط كحل بسيط ، ولكن في الواقع هناك العديد من حالات الحافة التي يجب معالجتها. على سبيل المثال ، تحتاج إلى:
- اعتراض النقرات على البادئة بطريقة ما ، ثم لتغيير موضع المؤشر ؛
- مسافة بادئة إضافية ؛
- حظر الحذف بحيث لا يمكن للمستخدم حذف المساحة أو بادئة البلد.
للقيام بكل هذا ، بالطبع ، أمر ممكن ، لكنه صعب إلى حد ما. يبدو أن هناك خيار أسهل.
وقد وجد حقا:
<merge xmlns:android="http://schemas.android.com/apk/res/android" tools:parentTag="android.widget.LinearLayout"> <TextView android:id="@+id/country_code" /> <EditText android:id="@+id/phone_number" /> </merge>
لقد قمنا ببساطة بتقسيم هذا المكون إلى جزأين: TextView و EditText. برمجياً ، على TextView ، وضعنا الخلفية بطريقة تحصل على التصميم الذي تتوقعه المنتجات تمامًا.
الشيء الوحيد الذي يستحق النظر هو أنه في Android ، بشكل افتراضي ، يزيد عرض الخط السفلي عندما يكون EditText في التركيز. لكننا نشترك بسهولة في تغيير في التركيز ونغير الخلفية في البادئة. لا شيء معقد:
phoneNumber.setOnFocusChangeListener { _, hasFocus -> countryCode.setBackgroundResource(background(hasFocus)) } private fun background(hasFocus: Boolean) = when (hasFocus) { true -> R.drawable.phone_input_active false -> R.drawable.phone_input_inactive }
هذا الحل له العديد من المزايا:
- لا حاجة للتعامل مع النقرات على البادئة ؛
- لا حاجة للعمل مع موضع المؤشر - إنه دائمًا في حقل منفصل.
- حالات حافة أقل بكثير والمشاكل تنشأ مع مثل هذا التنفيذ.
مثال 3. مشكلة الإكمال التلقائي
كما ترى في الرسوم المتحركة على اليسار ، الإكمال التلقائي لا يعمل كما نود. نود أن يبدو كل شيء كرسوم متحركة على اليمين.


دعونا نفكر فيما يمكننا القيام به حيال ذلك.

الخيار أ: يبدو أن هذه حالة نادرة لا يصلح أحد. لماذا لا نفعل الشيء نفسه؟
الخيار ب: سوف يعمل TextWatcher المخصص بشكل أفضل ويحل جميع مشاكلنا.
الخيار ج: إزالة الحد الأقصى لعدد الأحرف (كما هو موضح في الرسوم المتحركة ، لدينا عدد معين من الأحرف في هذا المكون). سنرسل رقم الهاتف بالكامل مع البادئة إلى الخادم ، ثم ندع الخادم يقرر ما إذا كان الرقم صحيحًا أم لا.
الخيار د: خذ أحرف N من النهاية.
استقرنا على الخيار د.

الخيار A. نظرت في العديد من التطبيقات الكبيرة. لا أحد يبدو لإصلاحها.
ومع ذلك ، في المستقبل سيتم ملء المزيد والمزيد من الحقول مع autophile. وكلما أسرعتم في حل هذه المشكلة ، كلما كان مستخدموك أكثر ولاءً وأكثر متعة في استخدام التطبيق بنفسك. على سبيل المثال ، أنا مسرور جدًا عندما أتصفح الشاشة بأكملها بنقرتين.
الخيار ب. من الأسهل حقًا تنفيذ TextWatcher المخصص ، نظرًا لعدم وجود العديد من البرامج النصية للحافة كما في المثال السابق. يمكنك بسهولة اعتراض النص المدرج. هناك مشكلة صغيرة واحدة فقط: في بعض البلدان توجد أسماء مستعارة محلية. على سبيل المثال ، يعني +44 و 0 نفس الشيء.
TextWatcher مخصص لا يمكن أن يساعد هنا. في هذه الحالة ، تحتاج إلى كتابة منطق إضافي ، وكذلك مطالبة الخادم بإرجاع جميع الأسماء المستعارة المحلية المحتملة لهذا البلد. لحل هذه المشكلة ، سيكون عليك إجراء تغييرات على بروتوكول الاتصال مع الخادم ثم تنفيذ هذه الوظيفة على الخادم. سيستغرق ذلك وقتًا أطول من القيام بشيء ما على العميل. يبدو أن هناك حلًا أبسط (وسوف نأتي إليه).
الخيار C. نزيل الحد الأقصى لعدد الأحرف - ثم يتحقق الخادم. هذا هو خيار كبير. لا بأس أن يتم عرض البادئة مرتين. إذا استمر المستخدم في الخطوة التالية وتم تحديد رقم الهاتف بشكل صحيح ، فلن تواجه أي مشكلة من حيث المبدأ.
ولكن لا يزال هناك عقبة واحدة. تخيل أن المستخدم لا يستخدم الإكمال التلقائي ، ولكن ببساطة يدخل رقم هاتفه. في هذه الحالة ، إذا كان هناك حد لعدد الأحرف ، فسيكون من الصعب عليه تكرار رقم عن طريق الخطأ - في النهاية سوف يرى أنه لم تتم طباعة الرقم الأخير. لذلك ، قررنا عدم استخدام هذه الطريقة.
الخيار دال. استخدام الأحرف N من النهاية بدا لنا حلاً مناسبًا.
class DigitsTrimStartFilter(private val max: Int) : InputFilter { override fun filter(...): CharSequence? { val s = source.subSequence(start, end).filter { it.isDigit() } val keep = max - (dest.length - (dend - dstart)) return when { keep <= 0 -> "" keep >= s.length -> null
لدينا الحد الأقصى لطول رقم الهاتف الذي يمكن إدراجه. نكتب فصلًا بسيطًا ، وهو مغلف ويمكن إعادة استخدامه في أماكن أخرى. بالإضافة إلى ذلك ، عندما يرى أي مطور آخر الرمز ، فسوف يحدد بسرعة ما هو. ولكن هناك مشكلتين أخريين.
أولاً ، هناك بلدان بها أرقام هواتف مختلفة. في مثل هذه الحالات ، سيعرض حلنا رقمًا إضافيًا من البادئة. ثانياً ، إذا قام المستخدم بإدراج بادئة لبلد آخر بملف تلقائي ، فقد يحدث نفس الموقف. تبدو الحالة الثانية نادرة بالنسبة لنا ، لأن الخادم يُرجع في البداية رقم الهاتف اعتمادًا على البلد الذي يوجد به المستخدم. ومع ذلك ، إذا فهمنا أن هذه مشكلة ، فسيتعين علينا تغيير البروتوكول الموجود على الخادم بحيث يُرجع قائمة بجميع الأرقام مرة واحدة ، وكتابة منطق إضافي (الآن لا نعتبر ذلك ضروريًا).
مثال 4. مكون إدخال التاريخ
يريد المصممون والمنتجات رؤية قناع لإدخال تاريخ كما يلي:

دعونا نفكر في كيفية تنفيذ ذلك.

الخيار أ: فقط تفعل ذلك. تبدو المهمة بسيطة ، فهي سهلة الحل ، ولا ينبغي أن تنشأ أي مشاكل.
الخيار ب: استخدم مكتبة القناع. إنها تناسبنا في هذا الموقف.
الخيار ج: تعطيل السيطرة على موقف المؤشر. وبالتالي ، نقوم بتبسيط المتطلبات قليلاً وسيكون من الأسهل بالنسبة لنا تنفيذ هذه الوظيفة.
الخيار د: استخدم مكون إدخال التاريخ القياسي الموجود على نظام Android والذي شاهدناه جميعًا.
لقد جئنا إلى الخيار C.

الخيار أ. المهمة تبدو بسيطة. بالتأكيد لسنا أول من يقوم بتنفيذ هذه الوظيفة. لماذا لا ترى ما إذا كان هناك حل مناسب على الإنترنت.

نأخذ هذا الحل ، نضيفه إلى الكود ، ونشغله. نبدأ في اختبار:
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { if (edited) { edited = false return } var working = getEditText() working = manageDateDivider(working, 2, start, before) working = manageDateDivider(working, 5, start, before) edited = true input.setText(working) input.setSelection(input.text.length) }
للوهلة الأولى يبدو أنه يناسبنا أكثر أو أقل. صحيح ، هناك مشاكل في حقيقة أن موضع المؤشر ينتقل إلى النهاية بعد كل تغيير. ثم نبدأ في الاختبار بعناية أكبر ونفهم أن كل شيء ليس جيدًا وأن هناك سيناريوهات غير معروفة.

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

هذا يبدو وكأنه أذكى الحل. كل شيء على ما يرام معه ، باستثناء عيب واحد صغير. عندما تفتح هذا المكون ، يكون لديك بالفعل بعض القيمة المحددة مسبقًا ، وبعض التاريخ الصحيح. إذا قمت بتعيين تاريخ صالح للانتقال إلى الخطوة التالية ، على سبيل المثال ، 1 يناير 1980 ، فستتلقى ملايين المستخدمين الذين ولدوا في ذلك اليوم. وإلا ، فسوف تحصل على العديد من الأخطاء المتطابقة: لا يمكن للمستخدم التسجيل لأنه كبير السن أو صغير جدًا.
لهذا السبب ، تخلينا في وقت واحد عن الحوار القياسي لإدخال التواريخ في نموذج التسجيل في Badoo. تم تقليل عدد الأخطاء المتعلقة بتاريخ غير صالح ثلاث مرات.

وآخر ناقص صغير. يبدو أن المستخدمين المتقدمين فقط يمكنهم الانتقال من الحالة الأولى إلى الثانية:

إذا لم يكن المستخدمون المتقدمون يستخدمون التطبيق الخاص بك فقط ، فسيتم الفرز من شهر إلى آخر بحثًا عن التاريخ المطلوب.
لذلك ، قررنا أن الخيار A ليس سيئًا للغاية. تحتاج فقط إلى تحسينه وتبسيطه قليلاً:
class DateEditText : AppCompatEditText(context, attrs, defStyleAttr) { private var canChange: Boolean = false private var actualText: StringBuilder = StringBuilder() override fun onSelectionChanged(selStart: Int, selEnd: Int) { super.onSelectionChanged(selStart, selEnd) if (!canChange) return canChange = false setSelection(actualText.length) canChange = true } }
عيوب الخيار A بدأت تظهر عندما يقوم المستخدم بتغيير موضع المؤشر. وفكرنا: "لماذا نعطي الفرصة لتحريك هذا المؤشر؟" وممنوع ببساطة من القيام بذلك.

لذلك نحن حل جميع المشاكل. حصلت المنتجات على تطبيق يناسبهم. وإذا قرروا في المستقبل أنك لا تزال بحاجة إلى منح الفرصة لإزالة شخصيات من الوسط ، فسنقوم بذلك.
مثال 5. الأدوات على شاشة تدفق الفيديو
عند بدء تشغيل دفق الفيديو ، أرادت المنتجات إظهار تلميحات الأدوات لتعليم المستخدمين كيفية استخدام الوظيفة.
في وقت تنفيذ الميزة ، كان لدينا ستة أنواع من تلميحات الأدوات. في الوقت نفسه ، يجب ألا يكون هناك أكثر من واحد على الشاشة. تلميحات الأدوات وصلت ديناميكيًا في أوقات عشوائية من الخادم. كان لا بد من تكرارها. إذا ظهرت تلميح الأدوات ، لكن المستخدم لم ينقر عليه ، فبعد N دقيقة يجب أن يظهر مرة أخرى.

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

لقد طلبنا دعم المؤقت فقط للحصول على تلميح الأولوية القصوى:

وفقًا لذلك ، عمل الموقت من أجلنا فقط من أجل تلميح الأدوات 1. بمجرد ظهور تلميح الأدوات 1 ، تمت إزالته وبدأت العملية التالية.

وبالتالي ، قمنا بتبسيط المتطلبات: لقد أصبح من الأسهل بالنسبة لنا تطبيق الميزة ، وبالنسبة للمختبرين كان من الأسهل اختبارها. في النهاية ، أدركنا أن هذا القرار يناسب الجميع.
مثال 6. إعادة ترتيب الصور
جاء هذا التصميم لنا:

لقد توصلنا إلى استنتاج مفاده أنه من الصعب جدًا تنفيذه ، وسنضطر إلى قضاء ثلاثة أيام في التطوير ، وفكرنا: "لماذا يجب علينا القيام بذلك إذا كنا لا نعرف ما إذا كان المستخدم يحتاج إليه؟" اقترحنا البدء بإصدار مبسط وتقييم مقدار طلب هذه الميزة.

اتضح أن المستخدمين مهتمون بهذه الوظيفة. بعد ذلك ، قمنا بتحسين إعادة تقديم الحالة إلى التصميم الأصلي.
المجموع:
- لقد قمنا بحماية أنفسنا والشركة من خطر إنفاق الكثير من وقت العمل على ميزة قد تكون عديمة الفائدة ؛
- تم تنفيذ متطلبات المنتج كنتيجة كاملة.
مثال 7. مكون إدخال PIN
نحن نعمل على تطوير ليس فقط تطبيق Badoo - لدينا أيضًا تطبيقات أخرى بتصميم مختلف تمامًا. وفي جميع التطبيقات الثلاثة ، نستخدم نفس المكون لإدخال رمز PIN:

من منظور UX ، يجب أن يتصرف المكون كما هو. ومع ذلك ، في تطبيقات مختلفة ، خطوط مختلفة ، المسافات البادئة ، وحتى خلفيات مختلفة. لا أود نسخ هذا في كل تطبيق ، ولكن لإعادة استخدامه. نظام التصميم يمكن أن يساعدنا في هذا.
نظام التصميم عبارة عن مجموعة من قواعد UX حول كيفية سلوك مكونات معينة. على سبيل المثال ، ذكرنا بوضوح أن كل زر يجب أن يكون له حالات معينة ويجب أن يتصرف بطريقة معينة.



يمكنك معرفة المزيد عن نظام التصميم من تقرير
Rudy Artyom .
في غضون ذلك ، عد إلى مكون إدخال PIN. ماذا نود؟
- سلوك لوحة المفاتيح الصحيح ؛
- القدرة على تخصيص واجهة المستخدم بالكامل بحيث تبدو مختلفة في التطبيقات المختلفة ؛
- تلقي دفق قياسي من البيانات من هذا المكون ، بدءًا من EditText العادي.

ما هي خيارات الحل لدينا؟

الخيار أ: استخدم أربعة أنواع منفصلة من نص EditText ، حيث سيكون كل عنصر من عناصر PIN عبارة عن تحرير نص منفصل.
الخيار ب: استخدم EditText واحدًا ، وأضف بعض الإبداع - واحصل على ما تحتاجه.
اخترنا الخيار ب.

الخيار أ. هناك مشاكل في أربعة تحرير منفصل. يضيف Android حشوة إضافية من جميع الجوانب ، وسنحتاج إلى معالجتها بشكل صحيح. بالإضافة إلى ذلك ، سوف تحتاج إلى تنفيذ نقرة طويلة مرة أخرى حتى يتمكن المستخدم من حذف رمز PIN بأكمله. سيتعين علينا العمل يدويًا مع التركيز والتعامل مع حذف الأحرف. يبدو معقدا إلى حد ما.
لذلك ، قررنا أن نغش قليلاً وأنشأنا نص تحرير غير مرئي بحجم 0 × 0 ، والذي سيكون مصدر البيانات:
private fun createActualInput(lengthCount: Int) = EditText(context) .apply { inputType = InputType.TYPE_CLASS_NUMBER isClickable = false maxHeight = 0 maxWidth = 0 alpha = 0F addOrUpdateFilter(InputFilter.LengthFilter(lengthCount)) } private fun createPinItems(count: Int) { actualText = createActualInput(count) actualText.textChanges() .subscribe { updatePins(it.toString()) pinChangesRelay.accept(it) } overlay.clicks().subscribe { focus() } }
ستتم إضافة كل رقم من رمز PIN برمجيًا. نتيجة لهذا ، يمكننا رسم أي نوع من واجهة المستخدم ، ووضع أي مسافة بادئة ، إلخ. بعد أن ينقر المستخدم على المكون ، نضع التركيز في EditText الخاص بنا. وبالتالي ، نحصل على لوحة مفاتيح تعمل بشكل صحيح.
بالإضافة إلى ذلك ، نحن نشترك في تغيير نص EditText غير المرئي وعرضه على واجهة المستخدم. بعد ذلك ، من السهل علينا الخروج من دفق البيانات من هذا المكون. في الواقع ، أعدنا استخدام Android EditText القياسي ، أضفنا المنطق اللازم فقط قليلاً.
النتائج
هذه المبادئ لا تنطبق دائما. سأعطيك الشروط التي سيعملون بموجبها بشكل جيد.
- المطور لديه القدرة على التأثير على الوظيفة . خلاف ذلك ، يحتاج فقط لإكمال المهمة.
- يعمل المطور لصالح شركة منتج ، حيث يتم مشاركة الميزات بنشاط والإفراج عنها بسرعة ، ويتم فحص الفرضيات المتعلقة بهذه الميزات بسرعة . في ظل هذه الظروف ، تتجلى هذه المبادئ في حيز التنفيذ الكامل ، لأنه مرة أخرى ، من البداية ، لا يمكننا أن نكون متأكدين بنسبة 100٪ من التحديثات التي ستُرضي المستخدمين وتلك التي لن تفعل ذلك.
- المطور لديه القدرة على تحليل المهام . هذه المبادئ هي حل منطقي في موقف يكون فيه لمديري المنتجات ومطوريها اتصال ثنائي الاتجاه ، مما يسمح لكلا الطرفين بالعثور على ما يمكن وينبغي إعادة بنائه.
- الاستعانة بمصادر خارجية . في حالات نادرة ، قد يكون العميل مهتمًا باقتراح ، على سبيل المثال ، لتقليل الوقت الذي يستغرقه لإكمال المهمة عن طريق تبسيط جزء من الوظيفة.
كيفية استخدام هذه المبادئ؟ لسوء الحظ ، خارج السياق ، من الصعب تقديم أي توصيات. ومع ذلك ، يمكنني أن أنصحك أن تولي اهتماما للأمور التالية.
قد تواجه مشكلات مع واجهة المستخدم / UX ، كما هو الحال في معظم الأمثلة ، أو قد تواجه مشكلات في منطق الأعمال ، كما في مثال تلميح الأدوات. تحتاج إلى محاولة تحليل مهمتك إلى عدة مهام فرعية صغيرة ، ثم تقييمها.
بعد ذلك ، يمكنك معرفة بالضبط أين ستكون المشاكل. بعد ذلك ، تناقش مع الزملاء كيفية حلها. ربما يمكن تبسيط شيء ما. أو ربما لا تعرف بعض الحلول البسيطة التي يعرفها زملاؤك بالفعل. في المرحلة التالية ، تقوم بالتنسيق مع المنتجات حلاً بديلاً. إذا كانوا راضين ، فقم بتنفيذ عرضك.
أريد أن أضيف أن جميع الناس يرتكبون أخطاء في بعض الأحيان. , , . , iOS. , . , . . , Win-Win .
:
PS , . , , . — , . ? .