Création d'un dialogue pour choisir une sonnerie

Il m'a fallu ici un projet pour faire mon dialogue avec le choix de la sonnerie dans les paramètres. Immédiatement pour 2 raisons - tout d'abord, il n'y a pas de RingtonePreference dans la bibliothèque de support, donc l'utilisation de la boîte de dialogue standard dans PreferenceFragmentCompat échouera. Et deuxièmement, en plus des mélodies standard, j'ai dû ajouter quelques sons des ressources là-bas. Il a donc été décidé d'écrire votre dialogue.


Je vais démontrer la création d'un tel dialogue en utilisant un exemple d'une application simple: sur un écran il y a un bouton "Jouer la sonnerie", en cliquant sur lequel joue la sonnerie définie dans les paramètres, et un lien vers l'écran des paramètres:



Je ne décrirai pas la création de ces deux écrans - tout y est comme toujours. Juste au cas où, à la fin, il y aura un lien vers le référentiel avec le code d'application.


Commençons donc par le fichier xml avec la description de l'écran des paramètres. Placez le fichier settings.xml dans res/xml avec le contenu suivant:


 <?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> 

Et maintenant, ajoutons ces paramètres à notre fragment:


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

Lancez, ouvrez l'écran des paramètres, voir ce qui suit:



L'introduction se termine ici, nous passons au but de l'article. Le plan est le suivant: lorsque vous cliquez sur "Sonnerie", une boîte de dialogue s'ouvre avec une liste de sonneries et les boutons OK et Annuler, lorsque vous sélectionnez une sonnerie, elle joue (comme dans le cas de la RingtonePreference standard), lorsque vous cliquez sur OK, elle est enregistrée dans les paramètres.


Alors, créez un fragment de dialogue:


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

Dans prefKey nous transférons la clé par laquelle la sonnerie actuelle sera extraite, et là, elle sera enregistrée en appuyant sur le bouton OK.


Pour plus de travail, nous avons besoin de la classe auxiliaire Ringtone , déclarons-la dans notre fragment:


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

Et écrivez une fonction d'aide qui extraira toutes les sonneries intégrées dans Android et nous renverra la liste de 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) ) } } 

Ici, ringtoneManager.cursor renvoie le curseur avec toutes les sonneries disponibles, nous passons simplement en revue tous les éléments et les mappons à notre classe d'assistance Ringtone (il est plus pratique de travailler avec eux).


Tout d'abord, organisons le travail avec la liste de sonneries intégrée - l'ajout de nos ressources plus tard sera très simple. Pour ce faire, créez une boîte de dialogue en onCreateDialog méthode 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() } 

Un adaptateur est nécessaire pour afficher une liste d'éléments dans une boîte de dialogue; il peut être défini comme suit:


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

Et vous avez besoin d'une autre méthode d'aide pour enregistrer la position sélectionnée (elle sera appelée lorsque vous cliquez sur le bouton OK):


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

Il reste à lier notre élément au dialogue, pour cela nous définissons une fonction auxiliaire dans le fichier avec le dialogue:


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

Et ajoutez findPreference("ringtone").connectRingtoneDialog(fragmentManager) à notre SettingsFragment , maintenant il devrait ressembler à ceci:


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

Si nous allons maintenant à l'écran des paramètres et cliquez sur "Sonnerie", nous verrons quelque chose comme ceci:



Ajoutez maintenant les sonneries des ressources à notre dialogue. Par exemple, nous avons une sonnerie sample.mp3 dans le dossier res/raw , et nous voulons l'afficher en haut de la liste. Ajoutez une autre méthode à la classe de dialogue:


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

Et changez la première ligne de la méthode onCreateDialog :


 ringtones = getResourceRingtones() + getAndroidRingtones() 

Nous commençons, regardons, nous réjouissons que tout soit si simple:



Il reste à ajouter un "aperçu" pour les sonneries. Pour ce faire, entrez un champ supplémentaire:


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

Et modifiez légèrement la méthode de rappel pour setSingleChoiceItems :


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

Que se passe-t-il ici: nous arrêtons la lecture de la sonnerie actuelle (si elle n'est pas nulle), définissons celle sélectionnée comme actuelle et commençons la lecture. Maintenant, lorsque vous sélectionnez une sonnerie dans la boîte de dialogue, elle sera lue. Pour arrêter la lecture lorsque la boîte de dialogue est fermée, redéfinissez la méthode onPause :


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

Eh bien, il ne reste plus qu'à attacher le bouton de l'écran principal à la sonnerie, par exemple, comme ceci:


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

C’est tout. Comme promis, le code source peut être pris ici .

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


All Articles