Related
I want to create a profile in my app, where I can edit or add some information when logged in. It already works with the checkbox but not with the other editText items. Also I want to show the saved information after I closed the app in the profile. Any idea how I could do this? Like changing an editText to a textView or is there any other way?
Here is my code of the fragment Profile:
(I tried several options to save data in the firebase database)
package com.example.discoverme
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.ContentValues.TAG
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.*
import android.widget.*
import androidx.fragment.app.Fragment
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.UserProfileChangeRequest
import com.google.firebase.database.*
import java.util.*
import java.util.Calendar.*
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
Toast.makeText(this.requireContext(), "Profil", Toast.LENGTH_LONG)
Log.e("Halllo", "Hat toll geklapptttt")
val telefon = rootView.findViewById<View>(R.id.telnummer) as EditText
val geburtstag = rootView.findViewById<View>(R.id.geburtsdatum) as EditText
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val stundenlohn = rootView.findViewById<View>(R.id.stundenlohn) as EditText
var tele = telefon.text.toString()
var gebi = geburtstag.text.toString()
var loc = location.text.toString()
var stundenl = stundenlohn.text.toString()
val nameTxt: TextView = rootView.findViewById(R.id.textName1)
val emailTxt: TextView = rootView.findViewById(R.id.emailemail)
val spezi = rootView.findViewById<TextView>(R.id.spezialisierungen)
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
Log.e("Speichern", "speichert")
Log.e("Telefon", tele)
//userHashMap["Telefon"] = tele
//mDatabase.child("Telefon").setValue(tele)
mDatabase.child("Telefon").setValue(tele)
.addOnSuccessListener {
Log.e("Telefon", tele)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
if (!gebi.isEmpty()) {
Log.e("Geburtstag", gebi)
userHashMap["Geburtsdatum"] = gebi
// mDatabase.updateChildren(userHashMap)
}
if (!loc.isEmpty()) {
userHashMap["Adresse"] = loc
// mDatabase.updateChildren(userHashMap)
}
if (!stundenl.isEmpty()) {
userHashMap["Stundenlohn"] = stundenl
// mDatabase.updateChildren(userHashMap)
}
mDatabase.updateChildren(userHashMap)
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(snapshot: DataSnapshot) {
nameTxt.text = snapshot.child("Name").value.toString()
emailTxt.text = snapshot.child("Email").value.toString()
if (snapshot.child("Spezialisierung").exists()) {
Log.e("Spez", "Ist anscheinend da")
spezi.text = snapshot.child("Spezialisierung").value.toString()
}
/* if (snapshot.child("Telefon").exists()) {
telefon.text = snapshot.child("Telefon").value.toString()
}
*/
}
})
val buttonSignOut : ImageButton? = rootView.findViewById(R.id.signOut_button1)
if (buttonSignOut != null) {
buttonSignOut.setOnClickListener{
mAuth.signOut()
Toast.makeText(this.context, "Signed Out", Toast.LENGTH_LONG).show()
startActivity(Intent(this.context, Start::class.java))
}
}
val buttonspezi = rootView.findViewById<Button>(R.id.buttonspez)
buttonspezi.setOnClickListener { view ->
var dialog: AlertDialog
// Initialize an array of colors
val arrayColors = arrayOf("Hochzeit", "Portrait", "Familien", "Architektur", "Passfotos", "Lebensmittel", "Film", "Interior", " Kinder/Babies", "Landschaft", "Mode", "People und Lifestyle", "Werbung", "Sport", "Produkte", "Akt")
// Initialize a boolean array of checked items
val arrayChecked = booleanArrayOf(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)
var stringArray = arrayOf<String>()
// Initialize a new instance of alert dialog builder object
val builder = AlertDialog.Builder(this.context)
// Set a title for alert dialog
builder.setTitle("Gib seine Spezialisierung an.")
// Define multiple choice items for alert dialog
builder.setMultiChoiceItems(arrayColors, arrayChecked) { dialog, which, isChecked ->
// Update the clicked item checked status
arrayChecked[which] = isChecked
// Get the clicked item
val color = arrayColors[which]
}
// Set the positive/yes button click listener
builder.setPositiveButton("OK") { _, _ ->
// Do something when click positive button
spezi.text = "Deine Spezialisierungen sind.. \n"
for (i in 0 until arrayColors.size) {
val checked = arrayChecked[i]
if (checked) {
stringArray += arrayOf(arrayColors[i])
spezi.text = "${spezi.text}" + stringArray.toString()
}
}
userHashMap["Spezialisierung"] = stringArray.asList()
Log.e("Liste", stringArray.asList().toString())
mDatabase.updateChildren(userHashMap)
}
// Initialize the AlertDialog using builder object
dialog = builder.create()
// Finally, display the alert dialog
dialog.show()
}
return rootView
}
// Method to show an alert dialog with multiple choice list items
// Extension function to show toast message
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
and here is the xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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="wrap_content">
<LinearLayout
android:id="#+id/profil_foto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff"
android:orientation="vertical"
tools:context=".ProfilFoto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="259dp"
android:background="#9C27B0"
android:orientation="vertical"
android:visibility="visible">
<ImageButton
android:id="#+id/signOut_button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="320dp"
android:layout_marginLeft="350dp"
android:background="#9C27B0"
android:contentDescription="TODO"
android:paddingTop="20dp"
android:paddingEnd="20dp"
android:paddingRight="20dp"
android:src="#drawable/ic_baseline_logout_24"
android:title="#string/sign_out"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:showAsAction="ifRoom"
app:tint="#FFFFFF"
tools:ignore="RtlSymmetry"
tools:visibility="visible" />
<ImageView
android:id="#+id/logo4"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_gravity="center"
android:layout_margin="10dp"
android:contentDescription="#string/todo"
android:src="#drawable/ic_profil_wei_" />
<TextView
android:id="#+id/textName1"
android:layout_width="wrap_content"
android:layout_height="39dp"
android:layout_gravity="center_horizontal"
android:textColor="#fff"
android:textSize="21sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>
<LinearLayout
android:layout_width="360dp"
android:layout_height="700dp"
android:layout_gravity="center"
android:layout_marginTop="45dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="25dp">
<EditText
android:id="#+id/infotext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:hint="Erzähle etwas über dich..."
android:paddingLeft="20dp">
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_baseline_location_on_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/locationPerson"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Adresse"
android:paddingLeft="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="#00FFFFFF"
android:src="#drawable/ic_baseline_cake_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/geburtsdatum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Geburtsdatum"
android:paddingLeft="20dp" />
</LinearLayout>
<EditText
android:id="#+id/telnummer"
android:layout_width="300dp"
android:layout_height="35dp"
android:background="#drawable/button_register_background"
android:drawableLeft="#drawable/ic_baseline_call_24"
android:drawablePadding="10dp"
android:ems="10"
android:hint="Telefonnummer"
android:paddingLeft="20dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_mail_full"
app:tint="#9C27B0" />
<TextView
android:id="#+id/emailemail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<Button
android:id="#+id/buttonspez"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Spezialisierungen"
android:textAllCaps="false"
android:background="#drawable/buttom_rounded_corner_lila"
android:textColor="#FFFFFF"
android:layout_gravity="center_vertical|center_horizontal"
android:gravity="center"
/>
<TextView
android:id="#+id/spezialisierungen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/Base.TextAppearance.AppCompat.Large"
android:layout_margin="25dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_baseline_attach_money_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/stundenlohn"
android:hint="Stundenlohn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="20dp" />
</LinearLayout>
<Button
android:id="#+id/speichern"
android:layout_width="160dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="25dp"
android:background="#drawable/buttom_rounded_corner_lila"
android:text="Änderungen speichern"
android:textColor="#FFFFFF"
app:cornerRadius="20dp">
</Button>
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="17dp" />
</LinearLayout>
</ScrollView>
I solved it. I just had to move the findViewById declaration inside the setOnClickListener and not only in the onCreate. Now I'm getting the ediText information and can save it in my firebase database.
Like so:
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
Toast.makeText(this.requireContext(), "Profil", Toast.LENGTH_LONG)
Log.e("Halllo", "Hat toll geklapptttt")
val nameTxt: TextView = rootView.findViewById(R.id.textName1)
val emailTxt: TextView = rootView.findViewById(R.id.emailemail)
val spezi = rootView.findViewById<TextView>(R.id.spezialisierungen)
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
val telefon = rootView.findViewById<View>(R.id.telnummer) as EditText
val geburtstag = rootView.findViewById<View>(R.id.geburtsdatum) as EditText
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val stundenlohn = rootView.findViewById<View>(R.id.stundenlohn) as EditText
val tele = telefon.text.toString()
val gebi = geburtstag.text.toString()
val loc = location.text.toString()
val stundenl = stundenlohn.text.toString()
Log.e("Speichern", "speichert")
if (!gebi.isEmpty()) {
Log.e("Telefon", tele)
//userHashMap["Telefon"] = tele
//mDatabase.child("Telefon").setValue(tele)
mDatabase.child("Telefon").setValue(tele)
.addOnSuccessListener {
Log.e("Telefon", tele)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
}
if (!gebi.isEmpty()) {
Log.e("Geburtstag", gebi)
//userHashMap["Geburtsdatum"] = gebi
mDatabase.child("Geburtstag").setValue(gebi)
.addOnSuccessListener {
Log.e("Telefon", gebi)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
if (!loc.isEmpty()) {
Log.e("Location", loc)
//userHashMap["Adresse"] = loc
mDatabase.child("Adresse").setValue(loc)
.addOnSuccessListener {
Log.e("Telefon", loc)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
if (!stundenl.isEmpty()) {
// userHashMap["Stundenlohn"] = stundenl
mDatabase.child("Stundenlohn").setValue(stundenl)
.addOnSuccessListener {
Log.e("Telefon", stundenl)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(snapshot: DataSnapshot) {
nameTxt.text = snapshot.child("Name").value.toString()
emailTxt.text = snapshot.child("Email").value.toString()
if (snapshot.child("Spezialisierung").exists()) {
Log.e("Spez", "Ist anscheinend da")
spezi.text = snapshot.child("Spezialisierung").value.toString()
}
/* if (snapshot.child("Telefon").exists()) {
telefon.text = snapshot.child("Telefon").value.toString()
}
*/
}
})
val buttonSignOut : ImageButton? = rootView.findViewById(R.id.signOut_button1)
if (buttonSignOut != null) {
buttonSignOut.setOnClickListener{
mAuth.signOut()
Toast.makeText(this.context, "Signed Out", Toast.LENGTH_LONG).show()
startActivity(Intent(this.context, Start::class.java))
}
}
I just need to figure out how to show the saved information, in the profile after saving it once.
I'll get right to the question: Is there a known issue or code that leads to the drawable of checkboxes (or other views) to not be refreshed/updated properly according to their state? If so, is there a solution?
Setup: I have an activity which adds a fragment containing checkboxes. The checkboxes behave peachy, responding on click events and I can handle them inside an onCheckedChangeListener. When the user has ticked three checkboxes the fragment is saved in the backstack and replaced by the subsequent fragment.
Expected Behaviour: If the user were to return to the previous "checkbox"-fragment, correct boxes should be ticked. CheckState of those said boxes should therefore be true so checkbox.isChecked = true is called in onViewCreated.
Behaviour: The boxes are not shown as ticked but behave in that manner when moving back to the previous fragment. The drawable shown is representing checked = false + pressed false
When I press one of the said boxes it shows the drawable representing checked = true + pressed = true and then returns to drawable representing checked = false + pressed = false on the first press, leading me to suspect that they in fact are checked as expected but shown as checked = false.
If I click on the same box again it gets checked, which supports the suspicion.
The "isChecked" inside the onCheckedChangeListener supports this suspicion as well being false # #1 and true # #2
What I've done: I've tried to isolate the setup in another application and everything works as expected there. I can call ".isChecked = true" in onViewCreated and those checkboxes will appear with drawable representing checked = true. One would think that the root of the problem would be easy to find when I've stripped the fragment down to the bare minimum but still, no luck.
Feel free to ask clarifying questions. I've been stuck on this for hours so any help is appreciated!
Fragment:
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.support.v7.widget.AppCompatCheckBox
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import co.joyship.android.R
import co.joyship.android.base.BaseFragment
import co.joyship.android.co.joyship.android.constants.Screen
import co.joyship.android.data.enums.Interest
import co.joyship.android.data.enums.Interest.*
import kotlinx.android.synthetic.main.fragment_top_interests.*
import java.util.*
class InterestFragment : BaseFragment(), View.OnClickListener {
private var listOfInterests = ArrayList<String>()
private var mListener: PreferencesRegistrationInterface? = null
private var checkAccumulator: Int = 0
private var interestViewMap = mapOf<Interest, AppCompatCheckBox>()
private var viewInterestMap = mapOf<Int, Interest>()
private lateinit var mOnCheckedListener: CompoundButton.OnCheckedChangeListener
override fun onResume() {
super.onResume()
checkBoxesInitially()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_top_interests, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mOnCheckedListener = instantiateOnCheckedListener()
generateViewMap()
generateInterestMap()
btnTopInterestsBack?.setOnClickListener(this)
btnTopInterestsForward?.setOnClickListener(this)
btnTopInterestsForward?.isEnabled = false
}
private fun generateViewMap() {
interestViewMap = mapOf<Interest, AppCompatCheckBox>(
Pair(MUSIC, cbMusic),
Pair(TV_SERIES, cbTv),
Pair(MOVIES, cbMovies),
Pair(GAMES, cbGames),
Pair(READING, cbReading),
Pair(TRAVEL, cbTravel),
Pair(SPORTS, cbSports),
Pair(EXERCISE, cbExercise),
Pair(PARTY, cbParty),
Pair(FOOD_BEVERAGE, cbFood),
Pair(FASHION, cbFashion),
Pair(POLITICS, cbPolitics),
Pair(BUSINESS, cbBusiness),
Pair(TECHNOLOGY, cbTechnology),
Pair(SCIENCE, cbScience))
}
private fun generateInterestMap() {
viewInterestMap = mapOf(
Pair(cbMusic.id, MUSIC),
Pair(cbTv.id, TV_SERIES),
Pair(cbMovies.id, MOVIES),
Pair(cbGames.id, GAMES),
Pair(cbReading.id, READING),
Pair(cbTravel.id, TRAVEL),
Pair(cbSports.id, SPORTS),
Pair(cbExercise.id, EXERCISE),
Pair(cbParty.id, PARTY),
Pair(cbFood.id, FOOD_BEVERAGE),
Pair(cbFashion.id, FASHION),
Pair(cbPolitics.id, POLITICS),
Pair(cbBusiness.id, BUSINESS),
Pair(cbTechnology.id, TECHNOLOGY),
Pair(cbScience.id, SCIENCE))
}
override fun onClick(view: View) {
if (!clickThrottled())
when (view.id) {
R.id.btnTopInterestsForward -> saveInterestsAndMoveForward()
R.id.btnTopInterestsBack ->
mListener?.onInterestsSelectionFragmentInteraction(
null,
null,
null,
view)
}
}
override fun onAttach(activityContext: Context?) {
super.onAttach(activityContext)
if (activityContext is PreferencesRegistrationInterface) {
mListener = activityContext
} else {
throw RuntimeException(activityContext!!.toString() + " must implement PreferencesRegistrationInterface")
}
}
override fun onDetach() {
mListener = null
super.onDetach()
}
private fun countCheck(isChecked: Boolean) {
checkAccumulator += if (isChecked) 1 else -1
}
private fun checkBoxesInitially() {
for (i in listOfInterests.indices) {
interestViewMap
.filterKeys { it.toString() == listOfInterests[i] }
.values
.first().isChecked = true
}
checkAccumulator = listOfInterests.size
interestViewMap.values.forEach { it.setOnCheckedChangeListener(mOnCheckedListener) }
}
private fun instantiateOnCheckedListener() =
CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
val boxId = buttonView.id
if (!clickThrottled()) {
countCheck(isChecked)
if (checkAccumulator <= 3) {
btnTopInterestsForward?.isEnabled = false
if (isChecked)
listOfInterests.add(viewInterestMap[boxId].toString())
else listOfInterests.remove(viewInterestMap[boxId].toString())
}
if (checkAccumulator == 3 && isChecked) {
saveInterestsAndMoveForward()
} else if (checkAccumulator > 3) {
btnTopInterestsForward!!.isEnabled = true
buttonView.isChecked = !isChecked
checkAccumulator--
}
btnTopInterestsForward!!.isEnabled = checkAccumulator == 3
} else {
(buttonView as AppCompatCheckBox).apply {
setOnCheckedChangeListener(null)
setChecked(!isChecked)
setOnCheckedChangeListener(mOnCheckedListener)
}
}
}
private fun saveInterestsAndMoveForward() {
val interest1 = listOfInterests[0]
val interest2 = listOfInterests[1]
val interest3 = listOfInterests[2]
mListener?.onInterestsSelectionFragmentInteraction(interest1, interest2, interest3, null)
}
companion object {
fun newInstance(): InterestFragment {
return InterestFragment().apply { type = "Interest fragment" }
}
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:id="#+id/svInterests"
style="#style/joyship_page.scroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/joyship_background"
android:fadeScrollbars="true"
android:orientation="vertical"
android:paddingBottom="#dimen/marginMainMinusShadow"
android:scrollbarThumbVertical="#color/colorBrand">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.AppCompatImageButton
android:id="#+id/btnTopInterestsBack"
style="#style/joyship_clickableIconPadded"
android:layout_width="#dimen/iconArrowNarrowEnlarged"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ib_arrow_backward" />
<android.support.v7.widget.AppCompatImageButton
android:id="#+id/btnTopInterestsForward"
style="#style/joyship_clickableIconPadded"
android:layout_width="#dimen/iconArrowNarrowEnlarged"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ib_arrow_forward" />
<TextView
android:id="#+id/tvHeaderTopActivities"
style="#style/joyship_text.header"
android:layout_marginTop="#dimen/halfMainMargin"
android:fontFamily="#font/josefin_sans_regular"
android:text="#string/headerInterestSelection"
android:textSize="#dimen/fontSizeXl"
app:layout_constraintTop_toBottomOf="#id/btnTopInterestsBack"
tools:ignore="SpUsage" />
<android.support.v7.widget.LinearLayoutCompat
style="#style/joyship_viewgroup.card"
android:layout_marginTop="#dimen/marginBeneathOnboardingHeaderShadow"
app:layout_constraintBottom_toBottomOf="parent"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="#id/tvHeaderTopActivities">
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbMusic"
style="#style/joyship_control.checkbox"
android:layout_marginTop="#dimen/halfMainMargin"
android:text="#string/interest_music" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbTv"
style="#style/joyship_control.checkbox"
android:text="#string/interest_tv" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbMovies"
style="#style/joyship_control.checkbox"
android:text="#string/interest_movies" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbGames"
style="#style/joyship_control.checkbox"
android:text="#string/interest_games" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbReading"
style="#style/joyship_control.checkbox"
android:text="#string/interest_reading" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbTravel"
style="#style/joyship_control.checkbox"
android:text="#string/interest_travel" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbSports"
style="#style/joyship_control.checkbox"
android:text="#string/interest_sports" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbExercise"
style="#style/joyship_control.checkbox"
android:text="#string/interest_exercise" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbParty"
style="#style/joyship_control.checkbox"
android:text="#string/interest_party" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbFood"
style="#style/joyship_control.checkbox"
android:text="#string/interest_foodAndBeverage" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbFashion"
style="#style/joyship_control.checkbox"
android:text="#string/interest_fashion" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbPolitics"
style="#style/joyship_control.checkbox"
android:text="#string/interest_politics" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbBusiness"
style="#style/joyship_control.checkbox"
android:text="#string/interest_business" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbTechnology"
style="#style/joyship_control.checkbox"
android:text="#string/interest_technology" />
<android.support.v7.widget.AppCompatCheckBox
android:id="#+id/cbScience"
style="#style/joyship_control.checkbox"
android:layout_marginBottom="#dimen/halfMainMargin"
android:text="#string/interest_science" />
</android.support.v7.widget.LinearLayoutCompat>
</android.support.constraint.ConstraintLayout>
<style name="joyship_control">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_marginStart">#dimen/marginMainPlusShadow</item>
<item name="android:layout_marginEnd">#dimen/marginMainPlusShadow</item>
<item name="android:fontFamily">#font/josefin_sans_regular</item>
<item name="android:gravity">center_vertical</item>
<item name="android:textColor">#color/colorText</item>
<item name="android:textSize">#dimen/fontSizeM</item>
</style>
<style name="joyship_control.checkbox" parent="joyship_control">
<item name="android:layout_height">#dimen/controllerHeight</item>
<item name="android:background">#null</item>
<item name="android:button">#null</item>
<item name="android:drawableEnd">#drawable/cb_joyship</item>
</style>
I want to create a custom dialog in Kotlin. I looked through questions on this theme on Stack Overflow, but I could not find any useful information. How can I do it?
You can use below code for a custom Dialog. It's my working code.
private fun showDialog(title: String) {
val dialog = Dialog(activity)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(false)
dialog.setContentView(R.layout.custom_layout)
val body = dialog.findViewById(R.id.body) as TextView
body.text = title
val yesBtn = dialog.findViewById(R.id.yesBtn) as Button
val noBtn = dialog.findViewById(R.id.noBtn) as Button
yesBtn.setOnClickListener {
dialog.dismiss()
}
noBtn.setOnClickListener {
dialog.dismiss()
}
dialog.show()
}
custom_dialog.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/fitsdk_white_rectangle"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="30dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="30dp"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/error_timeout_title"
android:textColor="#color/black" />
<TextView
android:id="#+id/tvBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="#string/error_timeout_body"
android:textColor="#color/black" />
<Button
android:id="#+id/btn_yes"
android:layout_width="100dp"
android:layout_height="30dp"
android:background="#android:color/white"
android:clickable="true"
android:text="Yes"
android:textColor="#5DBCD2"
android:textStyle="bold" />
</LinearLayout>
</FrameLayout>
CustomDialogClass.kt
class CustomDialogClass(context: Context) : Dialog(context) {
init {
setCancelable(false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.custom_dialog)
}
}
Below my solution as a kind of "message box".
I have not implemented an "OK" button. The message box should close after clicking on it.
Here the layout element (*/layout/message_box.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical">
<TextView
android:id="#+id/message_box_header"
android:layout_width="match_parent"
android:layout_height="30dp"
android:textAlignment="center"
android:textSize="20sp" />
<TextView
android:id="#+id/message_box_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
This function I've implement in a Fragment class. It is written in Kotlin.
fun showMessageBox(text: String){
//Inflate the dialog as custom view
val messageBoxView = LayoutInflater.from(activity).inflate(R.layout.message_box, null)
//AlertDialogBuilder
val messageBoxBuilder = AlertDialog.Builder(activity).setView(messageBoxView)
//setting text values
messageBoxView.message_box_header.text = "This is message header"
messageBoxView.message_box_content.text = "This is message content"
//show dialog
val messageBoxInstance = messageBoxBuilder.show()
//set Listener
messageBoxView.setOnClickListener(){
//close dialog
messageBoxInstance.dismiss()
}
}
you have a clean codes on an extension function of context in kotlin and use it on
all of your codes
fun Context.showDialog(
title: String,
description: String,
titleOfPositiveButton: String? = null,
titleOfNegativeButton: String? = null,
positiveButtonFunction: (() -> Unit)? = null,
negativeButtonFunction: (() -> Unit)? = null
) {
val dialog = Dialog(this, R.style.Theme_Dialog)
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) // if you have blue line on top of your dialog, you need use this code
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setCancelable(false)
dialog.setContentView(R.layout.dialog_custom_layout)
val dialogTitle = dialog.findViewById(R.id.title) as TextView
val dialogDescription = dialog.findViewById(R.id.description) as TextView
val dialogPositiveButton = dialog.findViewById(R.id.positiveButton) as TextView
val dialogNegativeButton = dialog.findViewById(R.id.negativeButton) as TextView
dialogTitle.text = title
dialogDescription.text = description
titleOfPositiveButton?.let { dialogPositiveButton.text = it } ?: dialogPositiveButton.makeGone()
titleOfNegativeButton?.let { dialogNegativeButton.text = it } ?: dialogNegativeButton.makeGone()
dialogPositiveButton.setOnClickListener {
positiveButtonFunction?.invoke()
dialog.dismiss()
}
dialogNegativeButton.setOnClickListener {
negativeButtonFunction?.invoke()
dialog.dismiss()
}
dialog.show()
}
and this is a sample of use this function
requireContext().showDialog(
title = "Your Title",
description = "Your Description",
titleOfPositiveButton = "yes",
titleOfNegativeButton = "No",
positiveButtonFunction = { // Run codes after click on positive button },
negativeButtonFunction = { // Run codes after click on negative button }
)
and you need to have style for constant with on design of your dialog
<style name="Theme_Dialog" parent="android:Theme.Holo.Dialog">
<item name="android:windowMinWidthMajor">90%</item>
<item name="android:windowMinWidthMinor">90%</item>
</style>
This is the way by which you can create your own dialog with custom layout.
val dialogBuilder = AlertDialog.Builder(context, R.style.AlertDialogTheme)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.layout_chat_type_selection, null)
dialogBuilder.setView(dialogView)
val radioGroupChat = dialogView.radio_group_chat
dialogView.radioButton_user_chat.isChecked = true
dialogBuilder.setPositiveButton(getString(R.string.ok_text), object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, id: Int) {
when (radioGroupChat.checkedRadioButtonId) {
R.id.radioButton_user_chat -> {
(activity as HomeActivity).replaceFragment(MySkippersFragment.getInstance(isFromChat = true))
}
R.id.radioButton_circle_chat -> {
(activity as HomeActivity).replaceFragment(PickCircleFragment.getInstance(
PickCircleFragment.NEW_CIRCLE_CHAT), true)
}
}
}
})
dialogBuilder.setNegativeButton(getString(R.string.cancel_text), object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface?, which: Int) {
}
})
val alertDialog = dialogBuilder.create()
alertDialog.show()
Works fine. You can also customize it the way you want.
Main class:
class CustomAlertDialogOneButton( activity: Activity?,
private val alertOneButtonClickListener: OnAlertOneButtonClickListener):Dialog(activity!!) {
private var title = ""
private var text = ""
private var dialogId = -1
private var buttonName = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.custom_alert_one_button_dialog)
setCancelable(false)
this.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
viewsClickListenerInit()
}
override fun onStart() {
initDialog()
super.onStart()
}
private fun fillFields(title: String, text: String?, dialogId: Int, buttonName: String) {
clearDialog()
this.title = title
this.text = text ?: ""
this.dialogId = dialogId
this.buttonName = buttonName
}
private fun clearDialog() {
title = ""
text = ""
}
private fun initDialog() {
if (title.isNotBlank()) {
tvAlertTitle.text = title
}
if (text.isNotBlank()) {
tvAlertText.text = text
}
tvAlertButtonOk.text = buttonName
}
fun show(title: String, text: String?, dialogId: Int = -1, buttonName: String = ResourcesRepository.resources.getString(R.string.ok)) {
fillFields(title, text, dialogId, buttonName)
super.show()
}
private fun viewsClickListenerInit() {
tvAlertButtonOk.setOnClickListener {
alertOneButtonClickListener.okClickListener(dialogId)
dismiss()
}
}}
XML for it: name it likes - custom_alert_one_button_dialog.xml
<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="280dp"
android:layout_height="145dp"
android:background="#color/colorWhite"
android:orientation="vertical">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="#+id/tvAlertTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="22dp"
android:textAlignment="center"
android:textColor="#color/colorDarkGrey"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvAlertText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="13dp"
android:paddingEnd="24dp"
android:paddingBottom="10dp"
android:textColor="#color/colorGrey"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvAlertTitle" />
<TextView
android:id="#+id/tvAlertButtonOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="34dp"
android:paddingBottom="18dp"
android:text="#string/ok"
android:textColor="#color/colorDarkGrey"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
Interface for button click listener:
interface OnAlertOneButtonClickListener {
fun okClickListener(dialogId: Int = -1)}
Implementation:
class SomeActivity : AppCompatActivity(), OnAlertOneButtonClickListener {
****
private var customDialogOneButton by lazy {
CustomAlertDialogOneButton(this, this)
}
****
customDialogOneButton.show(
title = "some title",
text = "some text",
dialogId = some int constant,
buttonName = "some button name"
)
****
override fun okClickListener(dialogId: Int) {
when (dialogId) {
some int constant -> {
// call method
}
}
}
My custom dialog xml file:
<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"
android:background="#color/dialogWindowBackground">
<TextView
android:id="#+id/popup_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16sp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16sp"
android:layout_marginBottom="10dp"
android:text="#string/body"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<LinearLayout
android:id="#+id/linearLayoutOpt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16sp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16sp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/popup_dialog">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:orientation="horizontal">
<TextView
android:id="#+id/no_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="8dp"
android:paddingRight="8dp"
android:paddingBottom="18dp"
android:text="No"
android:textAllCaps="false"
android:textColor="#color/colorAccent" />
<Space
android:layout_width="32sp"
android:layout_height="12sp" />
<TextView
android:id="#+id/yes_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="8dp"
android:paddingRight="8dp"
android:paddingBottom="18dp"
android:text="Yes"
android:textAllCaps="false"
android:textColor="#color/colorAccent" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
My Kotlin code:
private fun showDialog() {
val customDialog = Dialog(requireActivity())
customDialog.setContentView(R.layout.custom_dialog)
customDialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val yesBtn = customDialog.findViewById(R.id.yes_opt) as TextView
val noBtn = customDialog.findViewById(R.id.no_opt) as TextView
yesBtn.setOnClickListener {
//Do something here
customDialog.dismiss()
}
noBtn.setOnClickListener {
customDialog.dismiss()
}
customDialog.show()
}
If someone wants to show 2 buttons on dialog ( GENERIC SOLUTION ) KOTLIN
fun createCustomTwoButtonDialog(
msg: String, context: Context?
, positiveButtonText: String, negativeButtonText: String,
isCancellable: Boolean,
dialogListener: DialogListener
) {
context?.let { context ->
val builder =
AlertDialog.Builder(context)
builder.setTitle("Your desired title")
builder.setMessage(msg)
builder.setCancelable(isCancellable)
builder.setPositiveButton(positiveButtonText) { dialogInterface: DialogInterface?, i: Int ->
dialogListener.onPositiveClick()
dialogInterface?.dismiss()
}
builder.setNegativeButton(negativeButtonText)
{ dialogInterface: DialogInterface?, i: Int ->
dialogListener.onNegativeClick()
dialogInterface?.dismiss()
}
val alertDialog = builder.create()
alertDialog.show()
}
}
DialogListener is interface with 2 methods onNegativeClick() and onPositiveClick()
I created this Kotlin Class :
class AnimDialog(private val context: Context) {
private val dialog = Dialog(context)
fun test(s: String) {
Log.i("TAG", "test: $s")
}
init{
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
fun one(headerImage :Int?=null,
description: String,
titleOfPositiveButton: String? = null,
titleOfNegativeButton: String? = null,
positiveButtonFunction: (() -> Unit)? = null,
negativeButtonFunction: (() -> Unit)? = null
) :Dialog{
dialog.setCancelable(false)
dialog.setContentView(R.layout.dialog_one)
val dialogHeaderImage=dialog.findViewById(R.id.imageHead_dia) as ImageView
val dialogDescription = dialog.findViewById(R.id.description) as TextView
val dialogPositiveButton = dialog.findViewById(R.id.positiveButton) as Button
val dialogNegativeButton = dialog.findViewById(R.id.negativeButton) as Button
headerImage?.let { dialogHeaderImage.setImageResource(it) }
dialogHeaderImage.
startAnimation(
AnimationUtils.loadAnimation(
context,
R.anim.bounce
)
)
dialogDescription.text = description
titleOfPositiveButton?.let { dialogPositiveButton.text = it } ?: dialogPositiveButton.text
titleOfNegativeButton?.let { dialogNegativeButton.text = it } ?: dialogNegativeButton.text
dialogPositiveButton.setOnClickListener {
positiveButtonFunction?.invoke()
dialog.dismiss()
}
dialogNegativeButton.setOnClickListener {
negativeButtonFunction?.invoke()
dialog.dismiss()
}
return dialog
}
Where you must define :
1- Layout <dialog_one> include positive btn, negative btn, image view, text view
2- Animation <bounce> if you would like add anim to the header image
Now in Activity:
val animDialog = AnimDialog(this)
animDialog.one(
headerImage = android.R.drawable.ic_delete,
description = "Sometimes we looking for new dialog to fill better \n ",
titleOfPositiveButton = "Accept it",
titleOfNegativeButton = "Not now",
positiveButtonFunction = {
animDialog.test("OK")
},
negativeButtonFunction = {
animDialog.test("NO")
}).show()
I use Android Studio with Kotlin and I have a problem with my Toolbar, when I create it, it hides my others elements on my activity =>
Without Toolbar
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main))
val user = User("Bob", 20)
findViewById<Button>(R.id.go_to_second).setOnClickListener {
println("Lancement de la seconde activité")
val intent = Intent(this, Second::class.java)
intent.putExtra("user", user)
startActivity(intent)
}
findViewById<Button>(R.id.bouton_dialogue).setOnClickListener {
val confdial = ConfirmDialog()
confdial.listener = object: ConfirmDialog.ConfDeleteListener {
override fun onPositiveClick() {
Log.i("MainActivity", "Recuperation du postive suppression dialog")
val dd = FileListDialog()
dd.show(supportFragmentManager, "onPositiveClick")
}
override fun onNegativeClick() {
Log.i("MainActivity", "Confirmation du negative suppression dialog")
}
}
confdial.show(supportFragmentManager, "confirmDelete")
}
}
}
activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="visible"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/go_to_second"
android:visibility="visible"
android:layout_gravity="center"
android:text="go pr l'aventure" />
<Button
android:id="#+id/bouton_dialogue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
android:text="lancement dialogue" />
Result =>
result without toolbar
With Toolbar
MainActivity.kt
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.Toolbar
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
val user = User("Bob", 20)
findViewById<Button>(R.id.go_to_second).setOnClickListener {
println("Lancement de la seconde activité")
val intent = Intent(this, Second::class.java)
intent.putExtra("user", user)
startActivity(intent)
}
findViewById<Button>(R.id.bouton_dialogue).setOnClickListener {
val confdial = ConfirmDialog()
confdial.listener = object: ConfirmDialog.ConfDeleteListener {
override fun onPositiveClick() {
Log.i("MainActivity", "Recuperation du postive suppression dialog")
val dd = FileListDialog()
dd.show(supportFragmentManager, "onPositiveClick")
}
override fun onNegativeClick() {
Log.i("MainActivity", "Confirmation du negative suppression dialog")
}
}
confdial.show(supportFragmentManager, "confirmDelete")
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item?.itemId){
R.id.action_second -> {
val intent = Intent(this, Menu_activiy::class.java)
startActivity(intent)
return true
}
R.id.action_delete -> {
Toast.makeText(this, "supprimer", Toast.LENGTH_LONG).show()
return true
}
else -> return super.onOptionsItemSelected(item)
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:background="#color/colorPrimary"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="visible"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/go_to_second"
android:visibility="visible"
android:layout_gravity="center"
android:text="go pr l'aventure" />
<Button
android:id="#+id/bouton_dialogue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
android:text="lancement dialogue" />
</LinearLayout>
main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_second"
android:icon="#mipmap/ic_launcher_round"
android:title="Seconde"
app:showAsAction="always"/>
<item android:id="#+id/action_save"
android:icon="#drawable/epee"
android:title="Enregistrer"
app:showAsAction="always"/>
<item android:id="#+id/action_delete"
android:icon="#drawable/pioche"
android:title="Supprimer"
app:showAsAction="ifRoom"/>
<item android:id="#+id/action_help"
android:icon="#drawable/pomme"
android:title="Aide"
app:showAsAction="never"/>
</menu>
Result with ToolBar =>
Result with ToolBar
So we can see ToolBar but others elements like "Hello World" TextView has disappeared
Set the orientation of the LinearLayout:
android:orientation="horizontal" or android:orientation="vertical" also delete all the attributes that refer to ConstraintLayout.
Your toolbar's width is match_parent. This mean toolbar width is same your parent view. Your other views are still there but they are not visible, because LinearLayout's orientation is horizontal. They are out of parent view (LinearLayout).
You must change your parent layouts orientation to vertical or change your parent views type.
I guess the problem is the same which is stated in the above answer.
When the orientation of a LinearLayout is unspecified, it is using the default, which is horizontal. Should the layout be a column or a row? Use "horizontal" for a row, "vertical" for a column. The default is horizontal.
Since you are not giving any orientation it's horizontal and pushing other views out of scope so you better give a orientation in your linear layout.
android:orientation="vertical"
you can margin your hello world textView with
android:layout_marginTop="?attr/actionBarSize"
There are more fields below the keyboard. This happened when i updated the support library. I know it's Kotlin but it looks almost the same as java. How do I fix this issue?
This is what it looks like:
My code:
class ProjectsEditBottomSheetFragment(val privateID: String,
val publicID: String) : BottomSheetDialogFragment() {
private val mBottomSheetBehaviorCallback = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
dismiss()
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
if (slideOffset < -0.15f) {
dismiss()
}
}
}
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val view = View.inflate(context, R.layout.projects_edit_sheet, null)
dialog.setContentView(view)
dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
val params = (view.parent as View).layoutParams as CoordinatorLayout.LayoutParams
val behavior = params.behavior
if (behavior != null && behavior is BottomSheetBehavior<*>) {
behavior.setBottomSheetCallback(mBottomSheetBehaviorCallback)
}
// Get and set values
val realm = Realm.getDefaultInstance()
val realmObject = realm.where(ProjectsRealmObject::class.java)
.equalTo("privateID", privateID)
.findFirst()
realm.beginTransaction()
view.title_input.text = SpannableStringBuilder(realmObject.title)
view.description_input.text = SpannableStringBuilder(realmObject.description)
view.public_checkbox.isChecked = realmObject.isPublic
realm.commitTransaction()
// Keyboard
view.title_input.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(view.title_input, InputMethodManager.SHOW_FORCED)
} else {
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(view.title_input.windowToken, 0)
}
}
view.description_input.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(view.description_input, InputMethodManager.SHOW_FORCED)
} else {
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(view.description_input.windowToken, 0)
}
}
// Click listners
view.public_layout.setOnClickListener { view.public_checkbox.toggle() }
view.cancel.setOnClickListener {
view?.hideKeyboard()
dismiss()
}
view.save.setOnClickListener {
view?.hideKeyboard()
// Save to realm
realm.beginTransaction()
realmObject.title = if (view.title_input.text.toString() == "") getString(R.string.unnamed) else view.title_input.text.toString()
realmObject.description = view.description_input.text.toString()
realmObject.isPublic = view.public_checkbox.isChecked
realmObject.synced = false
realmObject.updatedRealm = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString() + ""
realm.commitTransaction()
ProjectsSync(context)
toast("Sparat")
dismiss()
}
}
}
xml:
<ScrollView
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"
android:background="#color/white"
app:layout_collapseMode="none"
app:behavior_hideable="false"
app:behavior_peekHeight="100dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
style="#style/Widget.Design.BottomSheet.Modal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/content">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="16dp"
android:paddingLeft="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/edit_info_placeholder_title"
android:id="#+id/title_input"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="16dp"
android:paddingLeft="16dp">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/edit_info_placeholder_description"
android:id="#+id/description_input"/>
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:clickable="true"
android:background="#drawable/click"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:id="#+id/public_layout">
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:id="#+id/public_checkbox"
android:layout_marginRight="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/edit_info_placeholder_is_public"
android:layout_gravity="center_vertical"
style="#style/textMedium"/>
</LinearLayout>
<!-- Buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right"
android:paddingBottom="8dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/edit_info_button_cancel"
android:id="#+id/cancel"
style="#style/Widget.AppCompat.Button.Borderless.Colored"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/edit_info_button_save"
android:id="#+id/save"
style="#style/Widget.AppCompat.Button.Borderless.Colored"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
I found the solution for 27 api. So the reason why keyboard hides view even with SOFT_INPUT_ADJUST_RESIZE is that the windowIsFloating is set for Dialogs.
The most convenient way that I found to change this is by creating style:
<style name="DialogStyle" parent="Theme.Design.Light.BottomSheetDialog">
<item name="android:windowIsFloating">false</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowSoftInputMode">adjustResize</item>
</style>
And set this in onCreate method of your BottomSheetDialogFragment:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogStyle)
}
This is how it looks on my device:
I tried all of answers in this topic but nothing helped. I looked through many sites and found only one solution that working for me.
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
dialog.setOnShowListener {
Handler().post {
val bottomSheet = (dialog as? BottomSheetDialog)?.findViewById<View>(R.id.design_bottom_sheet) as? FrameLayout
bottomSheet?.let {
BottomSheetBehavior.from(it).state = BottomSheetBehavior.STATE_EXPANDED
}
}
}
return dialog
}
Original solution
You can use the next class:
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.BottomSheetDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
public class TestBottomSheetDialog extends BottomSheetDialogFragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = LayoutInflater.from(getContext()).inflate(R.layout.fragment_bottom_sheet, container, false);
if (getDialog().getWindow() != null) {
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
if (getActivity() != null) {
View decorView = getActivity().getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
Rect displayFrame = new Rect();
decorView.getWindowVisibleDisplayFrame(displayFrame);
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int heightDifference = height - displayFrame.bottom;
if (heightDifference != 0) {
if (fragmentView.getPaddingBottom() != heightDifference) {
fragmentView.setPadding(0, 0, 0, heightDifference);
}
} else {
if (fragmentView.getPaddingBottom() != 0) {
fragmentView.setPadding(0, 0, 0, 0);
}
}
});
}
getDialog().setOnShowListener(dialog -> {
BottomSheetDialog d = (BottomSheetDialog) dialog;
View bottomSheetInternal = d.findViewById(android.support.design.R.id.design_bottom_sheet);
if (bottomSheetInternal == null) return;
BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED);
});
return fragmentView;
}
}
This is working for me
public class CustomBottomSheetDialogFragment extends BottomSheetDialogFragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View v = inflater.inflate(R.layout.content_dialog_bottom_sheet, container, false);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
return v;
}
This solution worked for me after spending 5 hours without luck:
Step #1:
Add this code to your styles.xml (located in res\values folder)
<style name="CustomizedBottomDialogStyle">
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.7</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowAnimationStyle">#android:style/Animation.Dialog</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="android:background">#android:color/transparent</item>
</style>
The key here is to set android:windowIsFloating -> false, if it is true your code will not work! Therefor i used rather android:backgroundDimEnabled and android:backgroundDimAmount to make background looks transparent with beautiful overlay.
Step #2:
Write this function to adjust it programmatically (note it is not optional, you need to perform both steps #1 and #2):
private fun showDialog() {
BottomSheetDialog(requireActivity(), R.style.CustomizedBottomDialogStyle).apply {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
setOnShowListener {
Handler().post {
val bottomSheet = findViewById<View>(R.id.design_bottom_sheet) as? FrameLayout
bottomSheet?.let {
BottomSheetBehavior.from(it).state = STATE_EXPANDED
}
}
}
setContentView(R.layout.dialog_layout)
// Your code goes here....
show()
}
}
The answer to the highest score is partly right. In my case, 90% of the view is visible after the same style is set. Finally, I made it completely visible through the following solution:
editText.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
(this#****BottomSheetDialogFragment.dialog as BottomSheetDialog).behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
add this to your styles
<style name="DialogStyle">
<item name="android:windowBackground">#android:color/transparent</item>
<item name="colorPrimaryDark">#android:color/transparent</item>
</style>
then in your's bottom sheet dialog's onCreate() add
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.DialogStyle);
also don't forget to add to dialog's setupDialog() method
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);