#android #kotlin #android-fragments
#Android #kotlin #android-фрагменты
Вопрос:
Я просто создаю простое приложение. У меня есть MainActivity, FragmentOne и FragmentTwo. На картинке вы можете видеть, что я могу использовать FragmentOne и FragmentTwo в любое время. И с помощью кнопки «Обновить Textview» я могу изменить textview во fragmentOne. Пример: когда я запускаю приложение, я просто переключаюсь на фрагмент один, затем на два, снова на один и так далее… И когда я нахожусь во FragmentOne, я нажимаю кнопку «Обновить», и текстовое представление изменяется. Проблем нет. И я перехожу к FragmentTwo и возвращаюсь к FragmentOne и пытаюсь снова нажать кнопку обновления, ничего не меняется.
Вкратце, вы можете видеть на картинке текстовое представление «СОЗДАННЫЙ ФРАГМЕНТ», я могу изменить его на один раз, я не могу изменить снова. Я не менял коды фрагмента. Это моя основная активность:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
goFragmentOne.setOnClickListener {
val myAction = supportFragmentManager.beginTransaction()
myAction.replace(R.id.myFrameLayout,FragmentOne()).commit()
}
goFragmentTwo.setOnClickListener {
val myAction = supportFragmentManager.beginTransaction()
myAction.replace(R.id.myFrameLayout,FragmentTwo()).commit()
}
btnUpdate.setOnClickListener {
textViewOne.text = "UPDATED"
}
}
}
Это мой MainActivity XML:
<FrameLayout>
<Button
android:id="@ id/goFragmentOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GO FRAGMENT ONE"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@ id/goFragmentTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GO FRAGMENT TWO"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="@ id/btnUpdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="UPDATE TEXTVIEW"
app:layout_constraintBottom_toTopOf="@ id/goFragmentOne"
app:layout_constraintStart_toStartOf="parent" />
<FrameLayout
android:id="@ id/myFrameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@ id/btnUpdate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</FrameLayout>
Комментарии:
1. Пожалуйста, добавьте код фрагмента.
2. Вероятно, вы меняете textview в методе onCreate.
3. Я не внес никаких изменений во фрагменты. В onCreate есть только это: «super.onCreate(savedInstanceState)». Я только что отредактировал MainActivity
4. Вы хотите изменить текстовое представление, которое находится внутри фрагмента, из действия. Лучший способ — изменить представления фрагмента изнутри фрагмента.
5. Создайте функцию внутри фрагмента, которая будет отвечать за изменение его представлений. Внутренняя активность пожалуйста, используйте следующий код для вызова функции внутри фрагмента. Фрагмент фрагмента = getFragmentManager().findFragmentByTag(FRAGMENT_TAG) фрагмент.functionHere();
Ответ №1:
Вы фиксируете старое текстовое представление внутри действия. После замены и воссоздания фрагментов старого объекта просмотра больше нет. то, что вы видите на экране, — это новое текстовое представление с новой ссылкой, но значение, которое вы записали в OnClick lambda, не соответствует этому новому значению. Попробуйте получить представление из фрагментов с помощью чего-то вроде
currentlyLoadedFragment.view.findViewById(R.id.theTextViewID) // or similar
Комментарии:
1. Я новичок в Kotlin, так что я должен написать в «currentlyLoadedFragment»?
2. Когда вы выполняете транзакцию фрагмента, сохраните последний размещенный фрагмент в локальной переменной вашего действия и назовите переменную
var currentlyLoadedFragment: Fragment? = null
, чтобы вы могли использовать ее в методе onClick. Обратите внимание, что перед помещением любого фрагмента в действие у вас не будет фрагмента для установки текста
Ответ №2:
Вам следует немного больше разделить свой код. То, как у вас это сейчас, — плохая практика. «Действия» для FragmentA -> ваш btnUpdate должен быть только во FragmentA, поскольку он предназначен только для вашего FragmentA. Используя архитектуру single activity, вы должны поместить в свой MainActivity onCreate только это
/*
You implement interfaces from FragmentA, and FragmentB
( interface Callbacks{....} that were written in FragmentA and FragmentB )
and then Android Studio will require you to implement methods defined in
those interfaces (methods are goToFragmentA() and goToFragmentB()
*/
class MainActivity : AppCompatActivity(), FragmentA.Callbacks, FragmentB.Callbacks {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//your starting layout, will put fragmentA as your starting layout if your fragment container is empty
val currentFragmentOnScreen = supportFragmentManager.findFragmentById(R.id.myFrameLayout)
if (currentFragmentOnScreen == null) {
val fragment = FragmentA()
supportFragmentManager.beginTransaction()
.add(R.id.myFrameLayout, fragment)
.commit()
}
}
//calls your function from FragmentB and goes to FragmentA on button click
override fun goToFragmentA(){
val fragment = FragmentA()
supportFragmentManager
.beginTransaction()
.replace(R.id.myFrameLayout, fragment)
.commit()
}
//calls your function from FragmentA and goes to FragmentB on button click
override fun goToFragmentB(){
val fragment = FragmentB()
supportFragmentManager
.beginTransaction()
.replace(R.id.myFrameLayout, fragment)
.commit()
}
затем в вашем FragmentA ()
class FragmentA() : Fragment() {
...
interface Callbacks {
fun goToFragmentB()
}
...
private var callbacks: Callbacks? = null
...
override fun onAttach(context: Context) {
super.onAttach(context)
callbacks = context as Callbacks?
}
...
override fun onStart() {
...
btn.OnClickListener{
callbacks?.goToFragmentB()
}
btnText.OnClickListener{
textViewOne.text = "UPDATED"
...
}
...
override fun onDetach() {
super.onDetach()
callbacks = null
}
...
И FragmentB
class FragmentB() : Fragment() {
...
interface Callbacks {
fun goToFragmentA()
}
...
private var callbacks: Callbacks? = null
...
override fun onAttach(context: Context) {
super.onAttach(context)
callbacks = context as Callbacks?
}
...
override fun onStart() {
...
btn.OnClickListener{
callbacks?.goToFragmentA()
}
...
}
...
override fun onDetach() {
super.onDetach()
callbacks = null
}
...
Комментарии:
1. Да, я могу это сделать, но нет никакого способа решить мою проблему? Например, что, если я создам таймер в MainActivity для изменения TextView каждую секунду. Если я использую таймер во фрагменте, таймер работает только при отображении фрагмента. Поэтому я хочу отказаться от своей деятельности.
Ответ №3:
Хорошо, я пишу этот код и работаю:
btnUpdate.setOnClickListener {
val tv = supportFragmentManager.findFragmentById(R.id.myFrameLayout)?.view?.findViewById<TextView>(R.id.textViewOne)
if (tv != null) {
tv.text = "UPDATED"
}
}
Спасибо, что помогли мне, ребята!