I am trying to implement a settings screen within my app which contains 2 nested preference screens namely "Backup" and "About". I tried to follow the guides from this link: Organize your Settings
Please see my code below:
activity_settings.xml
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.settings.SettingsActivity">
<ImageButton
android:id="#+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="#string/ContentDescription_Icon_Back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_back_dark" android:layout_marginStart="16dp"
android:layout_marginTop="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Settings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/back_button"
style="#style/Screen_Title_Default" android:id="#+id/textView"
app:layout_constraintBottom_toBottomOf="#+id/back_button"/>
<fragment
android:id="#+id/fragment_cont"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:name="com.th3pl4gu3.lifestyle.ui.settings.SettingsMainFragment"
app:layout_constraintTop_toBottomOf="#+id/textView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
SettingsActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.th3pl4gu3.lifestyle.R
import com.th3pl4gu3.lifestyle.databinding.ActivitySettingsBinding
class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat?, pref: Preference): Boolean {
// Instantiate the new Fragment
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment
)
fragment.arguments = args
fragment.setTargetFragment(caller, 0)
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_cont, fragment)
.addToBackStack(null)
.commit()
return true
}
private lateinit var _binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = DataBindingUtil.setContentView(this, R.layout.activity_settings)
}
override fun onStart() {
super.onStart()
_binding.backButton.setOnClickListener {
onBackPressed()
}
}
}
preferences_settings_main.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:key="backup_local"
app:title="Backup"
app:summary="Create and restore backups"
app:fragment="com.th3pl4gu3.lifestyle.ui.settings.SettingsBackupFragment"
android:icon="#drawable/ic_backup_dark"/>
<Preference
app:key="about"
app:title="About"
app:summary="About this application"
android:icon="#drawable/ic_info_dark"/>
</PreferenceScreen>
SettingsMainFragment.kt
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import com.th3pl4gu3.lifestyle.R
class SettingsMainFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences_settings_main, rootKey)
}
}
preferences_settings_backup.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Backup">
<EditTextPreference
android:defaultValue="internal/Android"
android:key="path"
android:summary="The path to create local backup"
android:title="Backup Path"/>
<Preference
app:title="Create Backup Locally"
app:summary="Creates a backup locally and saves to specified path."/>
<Preference
app:title="Create Backup in Cloud"
app:summary="Creates a backup and saves to Google Drive"/>
</PreferenceCategory>
<PreferenceCategory app:title="Restore">
<Preference
app:title="Restore Locally"
app:summary="Restore a Backup Locally"/>
<Preference
app:title="Restore from Cloud"
app:summary="Restore a Backup from Google Drive"/>
</PreferenceCategory>
What i wanted was when i click on "Backup" on the main preference screen, it would replace the whole fragment and show only the backup preference fragment. Instead, i am having this output:
It is showing the fragment on the same screen which i do not want. Can someone help me please?
Related
I am using a checkbox to toggle password visibility in edit text. Basically, when I check/uncheck the checkbox, the cursor of the edit text shifts to the initial position of the character in the password text. It should not change the cursor position in edit text when the checkbox is checked or unchecked.
Please anyone can suggest why the cursor position changes? and how I can fix that?
login_layout
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="#+id/etUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:autofillHints="name"
android:hint="Username"
android:imeOptions="actionNext"
android:inputType="text"
android:maxLines="1"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:autofillHints="password"
android:hint="Password"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:maxLines="1"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/etUsername" />
<CheckBox
android:id="#+id/imgTogglePassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-5dp"
android:layout_marginEnd="-5dp"
android:button="#drawable/btn_toggle_password"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="#id/etPassword"
app:layout_constraintEnd_toEndOf="#id/etPassword"
app:layout_constraintTop_toTopOf="#id/etPassword" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
LoginActivity
import android.os.Bundle
import android.text.method.HideReturnsTransformationMethod
import android.text.method.PasswordTransformationMethod
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.testapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
initUI()
}
private fun initUI() {
binding.imgTogglePassword.setOnCheckedChangeListener { _, isChecked ->
// checkbox status is changed from uncheck to checked.
if (!isChecked) {
// hide password
binding.etPassword.transformationMethod = PasswordTransformationMethod.getInstance()
} else {
// show password
binding.etPassword.transformationMethod = HideReturnsTransformationMethod.getInstance()
}
}
}
}
Login Page
Issue
You just need to use this line :
binding.etPassword.setSelection(binding.etPassword.text.length) as the below code.
import android.os.Bundle
import android.text.method.HideReturnsTransformationMethod
import android.text.method.PasswordTransformationMethod
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.testapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
initUI()
}
private fun initUI() {
binding.imgTogglePassword.setOnCheckedChangeListener { _, isChecked ->
// checkbox status is changed from uncheck to checked.
if (!isChecked) {
// hide password
binding.etPassword.transformationMethod = PasswordTransformationMethod.getInstance()
} else {
// show password
binding.etPassword.transformationMethod = HideReturnsTransformationMethod.getInstance()
}
binding.etPassword.setSelection(binding.etPassword.text.length)
}
}
}
CheckBox is not the common way to show/hide password.
Try endIconDrawable:
<com.google.android.material.textfield.TextInputLayout
...
app:endIconDrawable="#drawable/selector_button_eye"
app:endIconCheckable="true"
app:endIconTint="#color/colorEyeButtonTint">
<com.google.android.material.textfield.TextInputEditText
...
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
I' m not sure about the "endIconXXX" attributes because I only used the deprecated passwordToggleDrawable before. But they are similar.
I have three activities A, B and C, and use shared element transitions between A and B and between B and C.
A -> B works fine, and then using back button or finishAfterTransition smoothly reverses the transition from B back to A.
B -> C works fine too, going back from C to B is also smooth.
However A -> B -> C -> B -> A is the problem. The C -> B transition is smooth, but then the B back to A transition is 'forgotten' and is just an instant jump without a smooth transition.
Why is B -> A different after having gone B -> C -> B ? Update - this is only happening under API30 (using a Nexus 9 emulation). When I use a Nexus 9 with API28, everything works as expected!
When starting the activities I am using:
val options = ActivityOptions.makeSceneTransitionAnimation(this, transition_name)
startActivity(intent, options.toBundle())
I had a theory that the problem was occurring in B, when calling C it was changing the enterTransition, sharedElementEnterTranstion, exitTransition, sharedElementExitTranstion, returnTransition, sharedElementReturnTranstion, reenterTransition, sharedElementReenterTranstion attributes of B, and hence not transitioning back to A. However I've saved and logged all these and the object details don't seem to be different in either scenario.
Any help gratefully received, thanks.
I've mocked this up in a very simple three activity project to demonstrate the problem:
First screen XML:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/testtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:onClick="secondActivity"
android:text="Go to second screen"
android:transitionName="transition_name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Second screen XML:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="#+id/testtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Welcome to the second activity"
android:transitionName="transition_name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.147" />
<TextView
android:id="#+id/testtext2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:onClick="thirdActivity"
android:text="Go to third screen"
android:transitionName="transition_name2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.996"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.466" />
</androidx.constraintlayout.widget.ConstraintLayout>
Third screen XML:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ThirdActivity">
<TextView
android:id="#+id/testtext2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:transitionName="transition_name2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.845" />
</androidx.constraintlayout.widget.ConstraintLayout>
Main activity:
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Pair
import android.view.View
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun secondActivity(view: View) {
val intent = Intent(this, SecondActivity::class.java)
val view: View = findViewById(R.id.testtext)
val pair = Pair.create(view, "transition_name")
val options = ActivityOptions.makeSceneTransitionAnimation(this, pair)
startActivity(intent, options.toBundle())
}
}
Second activity:
import android.app.ActivityOptions
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.transition.Fade
import android.transition.Transition
import android.util.Log
import android.util.Pair
import android.view.View
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
}
fun thirdActivity(view: View) {
val intent = Intent(this, ThirdActivity::class.java)
val view: View = findViewById(R.id.testtext2)
val pair = Pair.create(view, "transition_name2")
val options = ActivityOptions.makeSceneTransitionAnimation(this, pair)
startActivity(intent, options.toBundle())
}
override fun onBackPressed() {
super.onBackPressed()
supportFinishAfterTransition()
}
}
Third activity:
import android.os.Bundle
class ThirdActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_third)
}
}
The navigation bottom view is not showing I do not see anything wrong with the code, although it shows in the preview.
Once the main activity has been launched it does not show.
Note that I am starting the main activity with the bottom navigation view within a launching activity that checks whether the user logged in.
This is the launching activity layout file
package io.keepcoding.androidfinalproject.ui
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.keepcoding.androidfinalproject.R
import io.keepcoding.androidfinalproject.ui.auth.AuthActivity
import io.keepcoding.androidfinalproject.ui.main.MainActivity
class LaunchingActivity : AppCompatActivity() {
private var userLoggedIn: Boolean = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_launch)
if(userLoggedIn){
startAppActivity()
} else {
startAuthActivity()
}
}
private fun startAuthActivity() {
val intent = Intent(this, AuthActivity::class.java)
startActivity(intent)
finish()
}
private fun startAppActivity() {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
}
This is the launching activity layout file that is not shown, because as soon as the app starts if the user is logged in, main activity is started.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.LaunchingActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is my main activity layout file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainActivity"
>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigationView"
app:labelVisibilityMode="labeled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="#color/app_bar"
app:itemIconTint="#color/white"
app:itemTextColor="#color/bottom_nav_bar_unselected"
app:menu="#menu/bottom_nav_menu"/>
</RelativeLayout>
This is my main activity code
package io.keepcoding.androidfinalproject.ui.main
import android.os.Bundle
import android.os.PersistableBundle
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.replace
import com.google.android.material.bottomnavigation.BottomNavigationView
import io.keepcoding.androidfinalproject.R
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var toolbar: ActionBar
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_main)
toolbar = supportActionBar!!
val bottomNavigation: BottomNavigationView = navigationView
bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener {
when(it.itemId) {
R.id.navigation_products -> {
toolbar.title = "Products"
val productFragment = ProductsFragment.newInstance()
openFragment(productFragment)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_map -> {
toolbar.title = "Map"
val mapFragment = ProductsFragment.newInstance()
openFragment(mapFragment)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_profile -> {
toolbar.title = "Profile"
val profileFragment = ProductsFragment.newInstance()
openFragment(profileFragment)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_notifications -> {
toolbar.title = "Notifications"
val notificationsFragment = ProductsFragment.newInstance()
openFragment(notificationsFragment)
return#OnNavigationItemSelectedListener true
}
}
false
}
private fun openFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.container, fragment)
transaction.addToBackStack(null)
transaction.commit()
}
}
Here is the menu layout file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/navigation_products"
android:icon="#drawable/ic_products"
android:enabled="true"
android:title="#string/title_products" />
<item
android:id="#+id/navigation_map"
android:icon="#drawable/ic_map"
android:enabled="true"
android:title="#string/title_map" />
<item
android:id="#+id/navigation_sell"
android:icon="#drawable/ic_add"
android:enabled="true"
android:title="#string/title_sell"
/>
<item
android:id="#+id/navigation_profile"
android:icon="#drawable/ic_profile"
android:enabled="true"
android:title="#string/title_profile"
/>
<item
android:id="#+id/navigation_notifications"
android:icon="#drawable/ic_notifications"
android:enabled="true"
android:title="#string/title_notifications" />
</menu>
You can find a link to the project here
https://github.com/kcFinalProject/AndroidFinalProject/tree/master
Your activity_main.xml is the one that has the nav bar right?
If that's the case, maybe your issue is that the Frame Layour height is match_parent
To see if this is the problem, set the frame layout visibility to invisible
Add to the FrameLayout the property android:visibility="invisible" and then see if the nav bar is visible.
If the nav bar is visible now, then you have to set the bottom constraints of the FrameLayout at the top of the nav bar. Add another property to the FrameLayout android:layout_above="#id/navigationView"
It is solved, I was overriding the wrong onCreate method, so the main activity being started from within Launching activity never actually run.
onCreate not called
I faced an error that actually mustn't occur, because I do exactly the same thing in my project in another screen, and it works there, but doesn't want to work in another screen.
The problem is the following: from an Activity in a result of some action I open up a DialogFragment which contains an image and other views in its layout file. Now I can't understand why, but it works in the first case (you'll see below) but doesn't work in the second...
First case:
Layout XML file (dialog_character_selector.xml):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="dialogViewModel"
type="neptun.jxy1vz.cluedo.ui.menu.character_selector.CharacterSelectorViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Spinner
android:id="#+id/spinnerCharacter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/ivCharacterCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="20dp"
android:src="#drawable/szereplo_hatlap"
app:layout_constraintBottom_toTopOf="#+id/btnStart"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.7"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/spinnerCharacter" />
<Button
android:id="#+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/start"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:onClick="#{()->dialogViewModel.startGame()}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The DialogFragment's Kotlin source code (CharacterSelectorDialog.kt):
package neptun.jxy1vz.cluedo.ui.menu.character_selector
import android.animation.AnimatorInflater
import android.animation.AnimatorSet
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.appcompat.app.AlertDialog
import androidx.core.animation.doOnEnd
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import neptun.jxy1vz.cluedo.R
import neptun.jxy1vz.cluedo.databinding.DialogCharacterSelectorBinding
class CharacterSelectorDialog : DialogFragment(), AdapterView.OnItemSelectedListener {
private lateinit var dialogCharacterSelectorBinding: DialogCharacterSelectorBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
dialogCharacterSelectorBinding = DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.dialog_character_selector,
null,
false
)
dialogCharacterSelectorBinding.spinnerCharacter.adapter = ArrayAdapter<String>(
context!!,
android.R.layout.simple_spinner_dropdown_item,
resources.getStringArray(R.array.characters)
)
dialogCharacterSelectorBinding.spinnerCharacter.onItemSelectedListener = this
//I do this due to a card flipping animation, it's not important, not part of my problem
val scale = resources.displayMetrics.density
dialogCharacterSelectorBinding.ivCharacterCard.cameraDistance = 8000 * scale
dialogCharacterSelectorBinding.dialogViewModel = CharacterSelectorViewModel(context!!)
return AlertDialog.Builder(context!!, R.style.Theme_AppCompat_Light_Dialog).setView(dialogCharacterSelectorBinding.root).setTitle(resources.getString(R.string.dialog_character_title)).create()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
dialogCharacterSelectorBinding.ivCharacterCard.setImageResource(R.drawable.szereplo_hatlap)
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
dialogCharacterSelectorBinding.ivCharacterCard.setImageResource(R.drawable.szereplo_hatlap)
(AnimatorInflater.loadAnimator(context, R.animator.card_flip) as AnimatorSet).apply {
setTarget(dialogCharacterSelectorBinding.ivCharacterCard)
start()
doOnEnd {
dialogCharacterSelectorBinding.dialogViewModel!!.setPlayer(position)
val img = when (position) {
0 -> R.drawable.szereplo_ginny
1 -> R.drawable.szereplo_harry
2 -> R.drawable.szereplo_hermione
3 -> R.drawable.szereplo_ron
4 -> R.drawable.szereplo_luna
else -> R.drawable.szereplo_neville
}
dialogCharacterSelectorBinding.ivCharacterCard.setImageResource(img)
}
}
}
}
Second case:
Layout XML file (dialog_helper_card.xml):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="helperCardDialogViewModel"
type="neptun.jxy1vz.cluedo.ui.dice.card_dialog.helper.HelperCardViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/ivHelperCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="20dp"
android:src="#drawable/mento_hatlap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
I think in the main parts it's just the same as the previous one.
Kotlin source file (HelperCardDialog.kt):
package neptun.jxy1vz.cluedo.ui.dice.card_dialog.helper
import android.animation.AnimatorInflater
import android.animation.AnimatorSet
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.core.animation.doOnEnd
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import neptun.jxy1vz.cluedo.R
import neptun.jxy1vz.cluedo.databinding.DialogHelperCardBinding
class HelperCardDialog(private val cardResource: Int) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog {
val dialogHelperCardBinding = DataBindingUtil.inflate<DialogHelperCardBinding>(LayoutInflater.from(context), R.layout.dialog_helper_card, null, false)
dialogHelperCardBinding.helperCardDialogViewModel = HelperCardViewModel()
(AnimatorInflater.loadAnimator(context, R.animator.card_flip) as AnimatorSet).apply {
setTarget(dialogHelperCardBinding.ivHelperCard)
start()
doOnEnd {
dialogHelperCardBinding.ivHelperCard.setImageResource(cardResource)
}
}
return AlertDialog.Builder(context!!, R.style.Theme_AppCompat_Dialog).setTitle(resources.getString(R.string.got_helper_card)).setNeutralButton(resources.getString(R.string.ok)
) { dialog, _ ->
dialog.dismiss()
}.create()
}
}
That's it. These are my most important files in my problem. Sorry for the lot of code...
I hope you will see where the problem is and tell me what's the solution for it.
Finally I found the error in my code. I left the setView() function call from the second AlertDialog.Builder().
The correct code snippet is:
return AlertDialog.Builder(context!!, R.style.Theme_AppCompat_Dialog)
.setView(dialogHelperCardBinding.root)
.setTitle(resources.getString(R.string.got_helper_card)).setNeutralButton(
resources.getString(R.string.ok)
) { dialog, _ ->
dialog.dismiss()
}.create()
I am trying to use TextInputLayout in a preference screen so as have a nice neat password box that has a show password option. I know there are ways and means of doing it with checkboxes and scripting but I would really love to be to just use the TextInputLayout, maybe wrapped or in a custom widget. Gradle dependencies are correct as it works fine in other activity screens.
The following preferences.xml crashes with an "Error inflating class com.google.android.material.textfield.TextInputLayout"
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>
</androidx.preference.PreferenceScreen>
Ok I worked out the answer (and learned a lot in the process). Took a lot of research and trial and error but I hope the following might prove helpful to someone similarly frustrated.
The custom preference layout:
password.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textLay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="66dp"
android:hint="#string/Set_Password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="#android:id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
The preference screen layout:
preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.toggen.myapplication.PasswordPreference
android:key="pref_password"
android:layout="#layout/password" />
</PreferenceScreen>
SettingsActivity.kt
package com.toggen.myapplication
import kotlinx.android.synthetic.main.password0.view.*
import androidx.appcompat.app.AppCompatActivity
import android.util.AttributeSet
import android.widget.EditText
import android.content.Context
import androidx.preference.*
import android.os.Bundle
class PasswordPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs){
private var passW: EditText? = null
override fun onBindViewHolder(holder: PreferenceViewHolder?) {
super.onBindViewHolder(holder)
passW = holder?.itemView?.textLay?.editText?.apply{ setText(getPersistedString("admin")) }
}
override fun onDetached() {
super.onDetached()
passW?.apply{ persistString("$text") }
}
}
class SettingsActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null) {
supportActionBar?.title = "Settings"
supportFragmentManager.beginTransaction()
.replace(android.R.id.content, SettingsFragment()).commit()
}
}
override fun onSupportNavigateUp() = onBackPressed().run { true }
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) = setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
Finally the answer that I've been looking for!! THANK YOU!!
Only modification that I would make is to use:
android:dialogLayout="#layout/password"
instead of:
android:layout="#layout/password"