#kotlin #android-fragments
#kotlin #android-фрагменты
Вопрос:
Я создал приложение с 4 фрагментами, каждый из которых представляет страницу приложения. Теперь внутри одного из фрагментов у меня есть кнопка переключения. Я пытаюсь получить OnClickListener, чтобы он менял цвет фона кнопки после нажатия. Я кодирую это в моем MainActivity.kt, а не во фрагментах. Однако это приводит к сбою приложения без logcat.
package com.example.myassignment
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.example.myassignment.Fragments.DestinationsFragment
import com.example.myassignment.Fragments.HelpFragment
import com.example.myassignment.Fragments.HomeFragment
import com.example.myassignment.Fragments.SettingsFragment
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_settings.*
class MainActivity : AppCompatActivity() {
private val helpFragment = HelpFragment()
private val settingsFragment = SettingsFragment()
private val homeFragment = HomeFragment()
private val destinationsFragment = DestinationsFragment()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
replaceFragment(homeFragment)
bottom_navigation.setOnNavigationItemSelectedListener{
when(it.itemId){
R.id.ic_home -> replaceFragment(homeFragment)
R.id.ic_destinations -> replaceFragment((destinationsFragment))
R.id.ic_help -> replaceFragment(helpFragment)
R.id.ic_settings -> replaceFragment(settingsFragment)
}
true
}
// This is the onclick for the button which is inside a fragment (SettingsFragment)
btnReset.setOnClickListener { resetColour() }
}
// Function for the onclick function
private fun resetColour() {
btnReset.setBackgroundColor(Color.parseColor("#3E3E3E"))
}
private fun replaceFragment(fragment: Fragment){
if (fragment !=null){
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment)
transaction.commit()
}
}
}
И вот мой код SettingsFragment (я ничего не менял)
package com.example.myassignment.Fragments
import android.graphics.Color
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.myassignment.R
import kotlinx.android.synthetic.main.fragment_settings.*
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [SettingsFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class SettingsFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_settings, container, false)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment SettingsFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
SettingsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
Вот XML для фрагмента, кнопка, которую я пытаюсь изменить, — btnReset
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".Fragments.SettingsFragment"
android:background="@color/black">
<TextView
android:id="@ id/txtSettings"
android:layout_width="323dp"
android:layout_height="102dp"
android:layout_marginTop="16dp"
android:background="@color/orange"
android:gravity="center"
android:text="Settings"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="60sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@ id/txtNotifications"
android:layout_width="223dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:background="@color/grey"
android:gravity="center"
android:text="Notifications"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@ id/btnNotifications"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/txtSettings" />
<TextView
android:id="@ id/txtNightMode"
android:layout_width="223dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:background="@color/grey"
android:gravity="center"
android:text="Night Mode"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@ id/btnNightMode"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/txtNotifications" />
<TextView
android:id="@ id/txtWIFI"
android:layout_width="223dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:background="@color/grey"
android:gravity="center"
android:text="WI-FI Only"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@ id/btnWIFI"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/txtNightMode" />
<ToggleButton
android:id="@ id/btnNotifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="44dp"
android:layout_marginRight="44dp"
android:text="ToggleButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@ id/txtSettings"
android:background="@color/cyan"
/>
<ToggleButton
android:id="@ id/btnNightMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="44dp"
android:layout_marginRight="44dp"
android:checked="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@ id/btnNotifications"
android:background="@color/cyan"
/>
<ToggleButton
android:id="@ id/btnWIFI"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="44dp"
android:layout_marginRight="44dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@ id/btnNightMode"
android:background="@color/cyan"/>
<Button
android:id="@ id/btnReset"
android:layout_width="337dp"
android:layout_height="154dp"
android:layout_marginTop="24dp"
android:text="Reset"
android:background="@color/cyan"
android:backgroundTint="@color/orange"
android:textColor="@color/black"
android:textSize="50sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/txtWIFI" />
</androidx.constraintlayout.widget.ConstraintLayout>
—— Редактировать ——
Новые настройки фрагментного кода:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
btnReset.setOnClickListener { resetColour() }
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_settings, container, false)
}
private fun resetColour() {
btnReset.setBackgroundColor(Color.parseColor("3E3E3E"))
}
Вот logcat
2021-02-17 08:20:32.594 11717-11717/com.example.myassignment E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myassignment, PID: 11717
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.example.myassignment.Fragments.SettingsFragment.onCreateView(SettingsFragment.kt:40)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Ответ №1:
Эта строка — ваша проблема.
btnReset.setOnClickListener { resetColour() }
btnReset
живет в вашем фрагменте, но вы пытаетесь ссылаться на него из своей деятельности. Попробуйте переместить этот код во фрагмент, который раздувает представление, btnReset
в котором он находится.
Видите строку import kotlinx.android.synthetic.main.fragment_settings.*
в вашем классе активности? Это то, из-за чего казалось btnReset
, что это допустимое свойство, на которое можно ссылаться в вашей деятельности. Вы должны удалить эту строку.
Наконец, очень маловероятно, что это «сбой без logcat». Вероятно, у вас есть какой-то фильтр в вашем logcat, который не позволяет вам увидеть сбой.
Комментарии:
1. Что вы подразумеваете под раздуванием представления? Извините, я действительно новичок в этом, вы имеете в виду файл .kt для фрагмента?
2. ДА.
SettingsFragment
Класс «раздувает» XML-файл настроек, в котором есть вашbtnReset
(он делает это здесь:return inflater.inflate(R.layout.fragment_settings, container, false)
поэтому вам нужно переместить свойOnClickListener
код вSettingsFragment
.3. Эй, приятель, я это сделал, но я все еще терплю крах. Я обновил вопрос с упомянутыми вами изменениями, а также добавил logcat. Не могли бы вы взглянуть, пожалуйста
4. Вы устанавливаете значение
OnClickListener
до того, как xml был увеличен. Вы не можете взаимодействовать со своими XML-представлениями доreturn inflater.inflate(R.layout.fragment_settings, container, false)
тех пор, пока не будет вызвано after . Я бы посоветовал вам переместитьOnClickListener
вonViewCreated()
вместоonCreateView()
5. боже, наконец-то это сработало! Большое спасибо, приятель!