Dans mon projet, j'ai trois fragments attachés à une activité, et l'un de ces fragments, encore une fois, des fragments qui affichent des textes à l'aide de vues personnalisées. Ce sont donc essentiellement des fragments dans un fragment.
Dans le fragment principal, j'ai mis ces codes pour basculer entre les fragments d'affichage de texte. Il est déclenché sur les codes passés par ses fragments enfants.
class TypeWriterView: AppCompatTextView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
suspend fun commence(txt: CharSequence?, delay: Long, animOnOff: Boolean) {
if (txt != null) {
if(animOnOff) {
var index = 0
while (index < txt.length) {
text = txt.subSequence(0, ++index)
delay(delay)
}
} else {text = txt}
} else return
}
fun commenceOnLifecycle(owner: LifecycleOwner, txt: CharSequence?, delay: Long, animOnOff: Boolean): Job =
owner.lifecycleScope.launch { commence(txt, delay, animOnOff) }
}
Et les fragments d'affichage de texte ont des vues personnalisées - AppCompatTextView - qui affiche des textes.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/x2Layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.textia1.TypeWriterView
android:id="@+id/x2Twv01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent" />
<TextView
android:id="@+id/x2Choice01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/X2toX1" />
<TextView
android:id="@+id/x2Choice02"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/X2toX3" />
</LinearLayout>
J'ai trois fragments d'affichage de texte identiques pour l'instant et le premier fragment d'affichage de texte apparaît bien. Mais lorsque j'essaie de transmettre la valeur au fragment principal et de déclencher diagCommence (), l'application se bloque. Ce qui était étrange, c'est que lorsque j'essaie d'accéder au deuxième fragment d'affichage de texte, cela me donne une exception de pointeur nul.
Selon le journal, l'erreur a été invoquée dans la méthode commenceOnLifecycle (), qui appelle le AppCompatTextView que j'ai créé. Le déplacer vers différents cycles de vie tels que onCreate (), onViewCreated () ne semble pas résoudre ce problème. Je me demande ce que je manque?
Edit: Le XML de mise en page de SceneX2, qui est un fragment d'affichage de texte:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.layoutx2, container, false)
}
override fun onStart() {
super.onStart()
val scene = getString(R.string.sceneX2)
tv01.commenceOnLifecycle(SceneX2(), scene, textanimspeed.toLong(), textanim) // the custom view that displays texts, triggers NPE
}
et le TextView personnalisé qui affiche le texte avec une animation de frappe:
private fun diagCommence(target: Fragment) {
val transaction = activity?.supportFragmentManager?.beginTransaction()
if (transaction != null) {
transaction.replace(R.id.ig1_Diag_Layout, target)
transaction.disallowAddToBackStack()
transaction.commit()
}
}
3 Réponses :
Si vous êtes en activité, vous devez utiliser fragmentManager. veuillez changer cette ligne
val nextScene = fragmentManager?.beginTransaction()
à
val nextScene = activity?.supportFragmentManager?.beginTransaction()
Essayez de remplacer votre code de fonction diagCommence par
class TypeWriterView(
context: Context,
attrs: AttributeSet
) : AppCompatTextView(context, attrs) {
Vous devez également initialiser votre vue onCreateView dans onCreateView . Tout d'abord, déclarez une variable globale
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.layoutx2, container, false)
tv01 = view.findViewById(R.id.x2Twv01)
val scene = requireActivity().getString(R.string.sceneX2)
tv01?.commenceOnLifecycle(SceneX2(), scene, textanimspeed.toLong(), textanim) // the custom view that displays texts
return view
}
et éditez votre méthode onCreateView
private var tv01: TypeWriterView? = null
ÉDITER
Modifiez votre déclaration TypeWriterView comme
activity?.supportFragmentManager?.beginTransaction()
?.replace(R.id.ig1_Diag_Layout, target)
?.addToBackStack(null)
?.commit()
Merci pour votre aimable aide. J'ai utilisé le deuxième code comme: private var tv01: AppCompatTextView? = null ai-je bien fait? Le suivant est également devenu comme ceci: tv01 = view?.findViewById(R.id.Sc_X2_tv01) Il y avait une erreur sans appel sécurisé. J'ai remplacé diagCommence et déplacé les codes dans onStart vers onCreate comme vous l'avez dit, mais cela ne fonctionne toujours pas et me donne NPE.
Essayez de déplacer le code dans onCreateView comme dans la réponse modifiée, notez également que j'appelle requireActivity() pour obtenir la chaîne à partir des ressources. Les variables globales textanimspeed et textanim sont- textanimspeed dans votre fragment?
Oui, ils le sont, et j'ai modifié le code, mais mettre AppCompatTextView dans <> AppCompatTextView erreur "Propriété getter ou setter attendue" et "Pas assez d'informations pour déduire la variable de type T" sur findViewById . Et aussi tv01?.commenceOnLifecycle() fait une erreur de "Référence non tv01?.commenceOnLifecycle() ", donc j'ai dû le laisser être ( Tv01.commenceOnLifecycle mais Tv01 est l'ID de mise en page). L'application lance toujours NPE lors de l'appel de commenceOnLifecycle() .
J'ai oublié de supprimer le <> wrapping AppCompatTextView . Pouvez-vous publier votre XML layoutx2?
D'accord, je l'ai posté ainsi que la vue de texte appcompat, juste au cas où.
Assurez-vous d'utiliser childFragmentManager car childFragmentManager est associé à des fragments tels que supportFragmentManager est associé à une activity
private fun diagCommence(target: Fragment) {
val transaction = childFragmentManager.beginTransaction()
if (transaction != null) {
transaction.replace(R.id.ig1_Diag_Layout, target)
transaction.disallowAddToBackStack()
transaction.commit()
}
}
Désolé mais il a tout fait, y compris pour afficher le prochain fragment, tout simplement pas fonctionner sur clic.