خلق حوار لاختيار نغمة رنين

استغرق الأمر مني هنا لمشروع واحد لجعل حواري مع اختيار نغمة الرنين في الإعدادات. على الفور لسببين - أولاً ، لا يوجد RingtonePreference في مكتبة الدعم ، لذلك سيفشل استخدام مربع الحوار القياسي في PreferenceFragmentCompat . وثانيًا ، بالإضافة إلى الألحان القياسية ، كان عليّ إضافة بعض الأصوات من الموارد هناك. لذلك تقرر كتابة حوارك.


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



لن أصف إنشاء هاتين الشاشتين - كل شيء موجود كما هو الحال دائمًا. فقط في الحالة ، في النهاية سيكون هناك رابط إلى المستودع برمز التطبيق.


لذا ، لنبدأ بملف xml مع وصف شاشة الإعدادات. ضع ملف settings.xml في res/xml بالمحتويات التالية:


 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <Preference android:key="ringtone" android:title="Ringtone"/> </PreferenceScreen> 

والآن دعنا نضيف هذه الإعدادات إلى الجزء الخاص بنا:


 class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings, rootKey) } } 

قم بتشغيل ، افتح شاشة الإعدادات ، انظر ما يلي:



المقدمة تنتهي هنا ، ننتقل إلى الغرض من المقالة. الخطة هي: عند النقر على "نغمة الرنين" ، يفتح مربع حوار بقائمة من نغمات الرنين وأزرار "موافق" و "إلغاء" ، عند تحديد نغمة رنين ، يتم تشغيلها (كما في حالة RingtonePreference القياسية) ، عند النقر فوق "موافق" ، يتم حفظها في الإعدادات.


لذا ، قم بإنشاء جزء حوار:


 class RingtonePreferenceDialog : DialogFragment() { private val prefKey: String get() = arguments?.getString(ARG_PREF_KEY) ?: throw IllegalArgumentException("ARG_PREF_KEY not set") companion object { private const val ARG_PREF_KEY = "ARG_PREF_KEY" fun create(prefKey: String): RingtonePreferenceDialog { val fragment = RingtonePreferenceDialog() fragment.arguments = Bundle().apply { putString(ARG_PREF_KEY, prefKey) } return fragment } } } 

في prefKey نقوم بنقل المفتاح الذي سيتم من خلاله استخراج نغمة الرنين الحالية ، وسيتم تسجيله بالضغط على الزر موافق.


لمزيد من العمل ، نحن بحاجة إلى Ringtone الدرجة المساعدة ، نعلنها داخل الجزء الخاص بنا:


 private data class Ringtone(val title: String, val uri: Uri) 

وكتابة وظيفة مساعدة ستسحب جميع نغمات الرنين المدمجة في Android ، وتعيد القائمة من Ringtone :


 private fun getAndroidRingtones(): List<Ringtone> { val ringtoneManager = RingtoneManager(context) val cursor = ringtoneManager.cursor return (0 until cursor.count).map { cursor.moveToPosition(it) Ringtone( title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX), uri = ringtoneManager.getRingtoneUri(it) ) } } 

هنا ringtoneManager.cursor سيعيد المؤشر مع جميع النغمات المتاحة ، ننتقل فقط عبر جميع العناصر ونعينها إلى فئة Ringtone المساعد لدينا (إنه أكثر ملاءمة للعمل معها).


أولاً ، دعنا ننظم العمل مع قائمة نغمات الرنين المدمجة - إضافة مواردنا لاحقًا ستكون بسيطة للغاية. للقيام بذلك ، قم بإنشاء مربع حوار عن طريق تجاوز طريقة onCreateDialog :


 private var ringtones: List<Ringtone> = emptyList() private var currentUri: Uri? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { ringtones = getAndroidRingtones() currentUri = getCurrentRingtoneUri() val currentPosition = ringtones.indexOfFirst { currentUri == it.uri } return AlertDialog.Builder(context!!) .setPositiveButton(android.R.string.ok) { _, _ -> saveCurrentUri() } .setNegativeButton(android.R.string.cancel) { _, _ -> dialog.dismiss() } .setSingleChoiceItems(adapter, currentPosition) { _, which -> currentUri = ringtones[which].uri } .create() } 

مطلوب محول لعرض قائمة بالعناصر في مربع حوار ؛ يمكن تعريفه على النحو التالي:


 private val adapter by lazy { SimpleAdapter( context, ringtones.map { mapOf("title" to it.title) }, R.layout.simple_list_item_single_choice, arrayOf("title"), intArrayOf(R.id.text1) ) } 

وتحتاج إلى طريقة مساعدة أخرى لحفظ الوضع المحدد (سيتم استدعاؤها عند النقر فوق الزر موافق):


 private fun saveCurrentUri() { PreferenceManager.getDefaultSharedPreferences(context) .edit() .putString(prefKey, currentUri?.toString()) .apply() } 

يبقى ربط عنصرنا بمربع الحوار ، لذلك نحدد وظيفة مساعدة في الملف مع مربع الحوار:


 fun Preference.connectRingtoneDialog(fragmentManager: FragmentManager?) = setOnPreferenceClickListener { RingtonePreferenceDialog.create(key).apply { fragmentManager?.let { show(it, "SOUND") } } true } 

وأضف findPreference("ringtone").connectRingtoneDialog(fragmentManager) إلى SettingsFragment ، الآن يجب أن يبدو findPreference("ringtone").connectRingtoneDialog(fragmentManager) :


 class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings, rootKey) findPreference("ringtone").connectRingtoneDialog(fragmentManager) } } 

إذا انتقلنا الآن إلى شاشة الإعدادات ونقرنا على "نغمة الرنين" ، فسوف نرى شيئًا مثل هذا:



أضف الآن نغمات من الموارد إلى حوارنا. على سبيل المثال ، لدينا نغمة رنين sample.mp3 في المجلد res/raw ، ونريد عرضها في أعلى القائمة. أضف طريقة أخرى إلى فئة الحوار:


 private fun getResourceRingtones(): List<Ringtone> = listOf( Ringtone( title = "Sample ringtone", uri = Uri.parse("${ContentResolver.SCHEME_ANDROID_RESOURCE}://${context!!.packageName}/raw/sample") ) ) 

وتغيير السطر الأول في طريقة onCreateDialog :


 ringtones = getResourceRingtones() + getAndroidRingtones() 

نبدأ ، انظر ، نفرح بأن كل شيء بسيط للغاية:



يبقى إضافة "معاينة" لنغمات الرنين. للقيام بذلك ، أدخل حقلًا إضافيًا:


 private var playingRingtone: android.media.Ringtone? = null 

setSingleChoiceItems بتغيير طريقة رد الاتصال قليلاً لـ setSingleChoiceItems :


 playingRingtone?.stop() ringtones[which].also { currentUri = it.uri playingRingtone = it.uri?.let { RingtoneManager.getRingtone(context, it) } playingRingtone?.play() } 

ما يحدث هنا: نتوقف عن تشغيل نغمة الرنين الحالية (إذا لم تكن فارغة) ، قم بتعيين النغمة المحددة كنغمة الرنين الحالية ، وبدء التشغيل. الآن عند تحديد نغمة رنين في الحوار ، سيتم تشغيلها. لإيقاف التشغيل عند إغلاق مربع الحوار ، onPause تعريف طريقة onPause :


 override fun onPause() { super.onPause() playingRingtone?.stop() } 

حسنًا ، كل ما تبقى هو إرفاق الزر على الشاشة الرئيسية بنغمة الرنين ، على سبيل المثال ، مثل:


 findViewById<Button>(R.id.playRingtone).setOnClickListener { val ringtone = PreferenceManager.getDefaultSharedPreferences(this) .getString("ringtone", null) ?.let { RingtoneManager.getRingtone(this, Uri.parse(it)) } if (ringtone == null) { Toast.makeText(this, "Select ringtone in settings", Toast.LENGTH_SHORT).show() } else { ringtone.play() } } 

هذا كل شيء. كما وعدت ، يمكن أن تؤخذ التعليمات البرمجية المصدر هنا .

Source: https://habr.com/ru/post/ar417883/


All Articles