**The flow: ** There are two xml files:
activity_main.xml
bottomsheet_fragment.xml
I want to click on "click here" button (xml id: btn_show) and show the bottom sheet fragment [This is happening correctly) .. corresponding files: activity_main.xml, MainActivity.kt
Now I want to click on the button in the bottom sheet(xml id: btn_button1), and show the text you pressed button 1 via toast(or anything else is fine too, I just want to show something when I click the button) [This part is not happenning correctly) .. corresponding files: bottomsheet_fragment.xml, BottomSheetFragment.kt
I am attaching codes for the files below:
bottomsheet_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btn_button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="Sample button 1"
/>
</LinearLayout>
BottomSheetFragment.kt
package android.example.naruto
import android.example.naruto.databinding.ActivityMainBinding
import android.example.naruto.databinding.BottomsheetFragmentBinding
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
class BottomSheetFragment: BottomSheetDialogFragment() {
private lateinit var binding2: BottomsheetFragmentBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding2 = BottomsheetFragmentBinding.inflate(layoutInflater)
binding2.btnButton1.setOnClickListener{
Toast.makeText(context, "You pressed on button 1!", Toast.LENGTH_SHORT).show()
}
}
}
activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="#+id/btn_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click here"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
main_activity.kt
package android.example.naruto
import android.example.naruto.databinding.ActivityMainBinding
import android.example.naruto.databinding.BottomsheetFragmentBinding
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
private lateinit var binding1: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding1 = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding1.root)
val bottomSheetFragment= BottomSheetFragment()
binding1.btnShow.setOnClickListener {
bottomSheetFragment.show(supportFragmentManager, "BottomSheetDialog")
}
}
}
Thanks in advance for the help! Please let me know if you need any more details or clarifications.
I referred to these tutorials: https://www.youtube.com/watch?v=yqnVPiWAw0o&t=21s, https://www.youtube.com/watch?v=4GXflIdrlus
I am not able to see onCreateView method in BottomSheetFragment and probably that's why it is not working
You can change your code like this
From
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding2 = BottomsheetFragmentBinding.inflate(layoutInflater)
binding2.btnButton1.setOnClickListener{
Toast.makeText(context, "You pressed on button 1!", Toast.LENGTH_SHORT).show()
}
}
To
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding2 = BottomSheetFamilyTreeBinding.inflate(inflater, container, false)
return binding2.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding2.btnButton1.setOnClickListener{
Toast.makeText(context, "You pressed on button 1!", Toast.LENGTH_SHORT).show()
}
}
Related
I've worked on the FragmentContainerView activity with some fragments, in that fragment, I want to use Compose alongside XML using ComposeViewin the first fragment, but when I try to navigate from the second fragment and back to the first fragment, the component from ComposeView was disappeared.
I've set up a fragment with FragmentContainerView using the replace strategy and I put the fragment inside the list like usual, and I have no idea what happens with this situation.
You can watch in this video
also this is my code
NavigationActivity.kt
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import androidx.navigation.NavDeepLinkRequest
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import id.derysudrajat.inlinebinding.viewBinding
import id.derysudrajat.library.R
import id.derysudrajat.library.databinding.ActivityNavigationBinding
class NavigationActivity : AppCompatActivity() {
private val binding by viewBinding(ActivityNavigationBinding::inflate)
private val listOfFragment = listOf(FragmentMainNav(), FragmentDetailNav())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.btnHome.setOnClickListener{
replace(HOME_NAV)
}
binding.btnDetail.setOnClickListener{
replace(DETAIL_NAV)
}
Navigation.createNavigateOnClickListener(R.id.fragmentDetailNav, null)
}
private fun replace(nav: String) {
supportFragmentManager
.beginTransaction()
.replace(
binding.fragmentContainerView.id,
if (nav == HOME_NAV) listOfFragment[0] else listOfFragment[1]
)
.commit()
}
companion object {
const val HOME_NAV = "home_nav"
const val DETAIL_NAV = "detail_nav"
}
}
FragmentMainNav.kt
import android.os.Bundle
import android.view.View
import androidx.compose.material3.Text
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.lifecycle.Lifecycle
import androidx.navigation.findNavController
import id.derysudrajat.inlinebinding.BindingFragment
import id.derysudrajat.inlinebinding.viewBinding
import id.derysudrajat.library.R
import id.derysudrajat.library.databinding.FragmentNavMainBinding
class FragmentMainNav : BindingFragment<FragmentNavMainBinding>() {
override val binding by viewBinding(FragmentNavMainBinding::inflate)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textMain.text = "Fragment Main"
binding.composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
Text(text = "This is Compose")
}
}
}
}
fragment_nav_main.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="match_parent">
<TextView
android:id="#+id/text_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment Main"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.compose.ui.platform.ComposeView
android:id="#+id/compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/text_main" />
</androidx.constraintlayout.widget.ConstraintLayout>
FragmentDetailNav.kt
import android.os.Bundle
import android.view.View
import id.derysudrajat.inlinebinding.BindingFragment
import id.derysudrajat.inlinebinding.viewBinding
import id.derysudrajat.library.databinding.FragmentNavDetailBinding
import id.derysudrajat.library.databinding.FragmentNavMainBinding
class FragmentDetailNav : BindingFragment<FragmentNavDetailBinding>() {
override val binding by viewBinding(FragmentNavDetailBinding::inflate)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textDetail.text = "Detail Navigation"
}
}
fragment_nav_detail.kt
<?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">
<TextView
android:id="#+id/text_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Detail Navigation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I've tried using different ways like changing ViewCompositionStrategy and it still not working, I expected to show ComposeView still show when the fragment was replaced and back, btw the compose that I was tried is from compose BOM 2022.10.00 - 2023.01.00 but still disappeared when the fragment was replaced.
I think you could move the binding.composeView.apply {} block from onViewCreated to onCreateView as shown by provided sample in official documentation here. I've tested it using compose bom 2023.01.00 and plain ViewBinding and it works fine. So the HomeFragment would be like this:
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val view = binding.root
binding.composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
Text(text = "This is Compose")
}
}
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
As additional note, i don't think the Navigation.createNavigateOnClickListener() is necessary and could just be removed.
I am trying to develope an app which lets the user choose and read a csv file from his phone, so the app can set a variable with the chosen file content (string). This variable can then be used to set the text of a TextView.
I already was able to let the user of my app choose the desired file. I couldn't get the file content though. And I've already seen that onActivityResult and startActivityForResult are depreacated which means that a lot of tutorials are outdated. Plus I was not able to get a solution to my problem by the documentation here.
This picture shows you, that after the user chooses his csv file, the textView is not changing.
This is what I have come up with so far for my ContentFragment.kt file. As you can see I already have a line for setting the TextView text to the content of a csv file which is located in the asset folder. That works great (here it is commented out - only there fyi), but I would like to do the same for the user's csv file:
package com.example.myapplication
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.myapplication.databinding.FragmentContentBinding
import kotlinx.android.synthetic.main.fragment_content.*
import java.io.BufferedReader
import java.io.InputStreamReader
class ContentFragment : Fragment() {
var _binding: FragmentContentBinding? = null
val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentContentBinding.inflate(inflater, container, false)
val file = BufferedReader(InputStreamReader(resources.assets.open("Testfile.csv"))).use {
it.readText()
} // The variable is unused. This line of code only exists to demonstrate that the file_content.settext(file) in the TestButton click event is working.
binding.TestButton.setOnClickListener {
// file_content.setText(file) // <-- This line works
val intent = Intent()
.setType("*/*")
.setAction(Intent.ACTION_GET_CONTENT)
startActivity(Intent.createChooser(intent, "Select a file"))
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onActivityResult(
requestCode: Int, resultCode: Int, resultData: Intent?) {
resultData?.data?.also { uri ->
val file = BufferedReader(InputStreamReader(resources.assets.open(resultData.toString()))).use {
it.readText()
}
file_content.setText(file)
}
}
}
This is the xml of the fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ContentFragment"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/TestButton"
android:text="Import File"
tools:ignore="MissingConstraints"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="In here the content of the file will appear."
android:id="#+id/file_content"
tools:ignore="MissingConstraints" />
</LinearLayout>
And here are more files, which are not so necessary:
MainActivity.kt:
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.myapplication.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="56dp"
app:layout_constraintBottom_toBottomOf="parent">
<fragment
android:id="#+id/fragment"
class="com.example.myapplication.ContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Replace:
val file = BufferedReader(InputStreamReader(resources.assets.open(resultData.toString()))).use {
it.readText()
}
with:
val file = BufferedReader(InputStreamReader(requireContext().contentResolver.openInputStream(uri))).use {
it.readText()
}
Note that your use of */* for the MIME type means that the user can choose non-text content. Consider using text/*.
I was able to solve my problem by editing ContentFragment.kt. Now it works to let the user choose a csv-file and show its content in a textView.
package com.example.myapplication
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import com.example.myapplication.databinding.FragmentContentBinding
import kotlinx.android.synthetic.main.fragment_content.*
import java.io.BufferedReader
import java.io.InputStreamReader
class ContentFragment : Fragment() {
var _binding: FragmentContentBinding? = null
val binding get() = _binding!!
private val request = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null) {
val inputStream = requireContext().contentResolver.openInputStream(uri)
val file = BufferedReader(InputStreamReader(inputStream)).use {
it.readText()
}
file_content.setText(file)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentContentBinding.inflate(inflater, container, false)
binding.TestButton.setOnClickListener {
val intent = Intent()
.setType("*/*")
.setAction(Intent.ACTION_GET_CONTENT)
request.launch("*/*")
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
I'm creating an application that displays a webview and has a button that opens the Android settings. My problem is that when I add this button, the webview stops working and only show a white screen that doesn't charge. What am I doing wrong? I leave the code below:
PD: If I delete the code starting from "//init code" it works....
MainActivity.kt
package com.becas.apn_mexico
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import android.view.View
import com.becas.apn_mexico.base.BaseActivity
import com.becas.apn_mexico.databinding.ActivityMainBinding
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : BaseActivity<ActivityMainBinding>() {
companion object {
private const val URL_LINK_WEBSITE = "https://apn.tutorialez.net/index.php/landing-page/"
}
override fun setupViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
}
override fun setupViewModel() {
}
override fun setupUI(savedInstanceState: Bundle?) {
binding.mainWebview.loadUrlExt(URL_LINK_WEBSITE)
showAdBanner(binding.adsView.adsPhoneTabSpecialSmartBanner)
showAdInterstitial(getString(R.string.admob_interstitial))
}
// Init Code
private lateinit var fab: FloatingActionButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab = findViewById(R.id.abrir_configuracion)
// Configurando el setonclicklistener
fab.setOnClickListener(View.OnClickListener{
val i = Intent(Settings.ACTION_APN_SETTINGS)
startActivity(i) })
}
}
ActivityMain.xml
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.becas.apn_mexico.MainActivity">
<WebView
android:id="#+id/main_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/ads_view" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/abrir_configuracion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_above="#id/ads_view"
android:clickable="true"
android:backgroundTint="#color/colorPrimary"
android:contentDescription="#string/open_config_apn"
app:srcCompat="#drawable/ic_baseline_settings_24" />
<include
android:id="#+id/ads_view"
layout="#layout/ads_phone_tab_special_smart_banner" />
</RelativeLayout>
I think your problem is that you are not using the viewbinding to inflate your view:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// You need to get here the binding and put it into the ContentView method
val view = binding.root
setContentView(view)
fab = findViewById(R.id.abrir_configuracion)
// Configurando el setonclicklistener
fab.setOnClickListener(View.OnClickListener{
val i = Intent(Settings.ACTION_APN_SETTINGS)
startActivity(i) })
}
Alternatively, the problem is in your layout. Can you remove the
<include
android:id="#+id/ads_view"
layout="#layout/ads_phone_tab_special_smart_banner" />
From your layout and let me know if you get the expected result?
I want to learn it by myself but can't find it on the internet because I do not know what its name is .. screen? dialogue? menu? I just do not know and therefore do not find in an Internet search
In my understanding, you are talking about the bottom sheet
Here are the five simple steps to create a bottom sheet in android
Step 1
Add the material support design dependency in the app-level build.gradle file
implementation "com.android.support:design:27.0.2"
Step 2
Design the layout file that was to be shown as the bottom sheet.
<?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"
android:paddingBottom="8dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/txt_download"
style="#style/BottomSheetItem"
android:drawableStart="#drawable/ic_baseline_save_alt_24"
android:drawableLeft="#drawable/ic_baseline_save_alt_24"
android:text="Download"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/txt_copy"
style="#style/BottomSheetItem"
android:drawableStart="#drawable/copy_iocn"
android:drawableLeft="#drawable/copy_iocn"
android:text="Copy"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txt_download" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/txt_share"
style="#style/BottomSheetItem"
android:layout_marginTop="8dp"
android:drawableStart="#drawable/share_iocn"
android:drawableLeft="#drawable/share_iocn"
android:text="Share"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txt_copy" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/txt_whats_app"
style="#style/BottomSheetItem"
android:drawableStart="#drawable/ic_whatsapp_new"
android:drawableLeft="#drawable/ic_whatsapp_new"
android:text="Whats App"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txt_share" />
</androidx.constraintlayout.widget.ConstraintLayout>
You can add the item style in styles.xml
<style name="BottomSheetItem">
<item name="android:textSize">20sp</item>
<item name="android:drawablePadding">20dp</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">15dp</item>
<item name="fontFamily">#font/mono_bold</item>
</style>
Step 3
Now extend the class with BottomSheetDialogFragment and override the onCreateView method to provide the layout.
package com.sample
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.sample.R
import kotlinx.android.synthetic.main.bottom_sheet_options.*
import java.lang.ref.WeakReference
class OptionsBottomSheetFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.bottom_sheet_options, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpViews()
}
private fun setUpViews() {
// We can have cross button on the top right corner for providing elemnet to dismiss the bottom sheet
//iv_close.setOnClickListener { dismissAllowingStateLoss() }
txt_download.setOnClickListener {
dismissAllowingStateLoss()
Toast.makeText(application, "Download option clicked", Toast.LENGTH_LONG)
.show()
}
txt_share.setOnClickListener {
dismissAllowingStateLoss()
Toast.makeText(application, "Share option clicked", Toast.LENGTH_LONG)
.show()
}
}
companion object {
#JvmStatic
fun newInstance(bundle: Bundle): OptionsBottomSheetFragment {
val fragment = OptionsBottomSheetFragment()
fragment.arguments = bundle
return fragment
}
}
}
Note: We can set an interface and send the callback to parent activity to handle the actions accordingly.
With interface callback, it will be modified as follows
package com.sample
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.sample.R
import kotlinx.android.synthetic.main.bottom_sheet_layiut.*
class OptionsBottomSheetFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.bottom_sheet_options, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpViews()
}
private fun setUpViews() {
// We can have cross button on the top right corner for providing elemnet to dismiss the bottom sheet
//iv_close.setOnClickListener { dismissAllowingStateLoss() }
txt_download.setOnClickListener {
dismissAllowingStateLoss()
mListener?.onItemClick("Download")
}
txt_share.setOnClickListener {
dismissAllowingStateLoss()
mListener?.onItemClick("Share")
}
}
private var mListener: ItemClickListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is ItemClickListener) {
mListener = context as ItemClickListener
} else {
throw RuntimeException(
context.toString()
.toString() + " must implement ItemClickListener"
)
}
}
override fun onDetach() {
super.onDetach()
mListener = null
}
interface ItemClickListener {
fun onItemClick(item: String)
}
companion object {
#JvmStatic
fun newInstance(bundle: Bundle): OptionsBottomSheetFragment {
val fragment = OptionsBottomSheetFragment()
fragment.arguments = bundle
return fragment
}
}
}
Step 4
Design a layout with a button to show the dialog on its click.
<?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">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_click_me"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:padding="#dimen/spacing_20"
android:background="#color/grey3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Click Me"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Step 5
The final step is to show the dialog in the activity
package com.sample
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.main.*
class SampleActivity :AppCompatActivity(),OptionsBottomSheetFragment.ItemClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.amin)
tv_click_me?.setOnClickListener {
supportFragmentManager.let {
OptionsBottomSheetFragment.newInstance(Bundle()).apply {
show(it, tag)
}
}
}
}
override fun onItemClick(param:String) {
when(param){
"share"->{
//Handle data
}
"Download"->{
//Handle data
}
else->{
//Handle data
}
}
}
}
Beginner Android developer here. I'm currently using Navigation Component in my project, and I have a DialogFragment which has a Toolbar and menu as a destination. However, the menu title is cut off even though the dialog could be expanded a bit more.
Here's what it looks like right now:
However, as you can see there's still room for it to expand. I want it to look like this:
But I'm not sure how to achieve it without setting the layout to MATCH_PARENT programatically.
Here's the code for my DialogFragment:
package tang.song.edu.yugiohcollectiontracker.ui_inventory
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.DialogFragment
import androidx.navigation.fragment.findNavController
import tang.song.edu.yugiohcollectiontracker.R
import tang.song.edu.yugiohcollectiontracker.databinding.FragmentTransactionDialogBinding
import tang.song.edu.yugiohcollectiontracker.viewBinding
import javax.inject.Inject
class TransactionDialogFragment : DialogFragment(), Toolbar.OnMenuItemClickListener {
#Inject
lateinit var mViewModelFactory: TransactionDialogViewModelFactory
private lateinit var viewModel: TransactionDialogViewModel
private val binding by viewBinding(FragmentTransactionDialogBinding::inflate)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initToolbar()
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
TODO("Not yet implemented")
}
private fun initToolbar() {
binding.newTransactionToolbar.apply {
inflateMenu(R.menu.transaction_dialog_toolbar_menu)
setOnMenuItemClickListener(this#TransactionDialogFragment)
setNavigationOnClickListener {
findNavController().navigateUp()
}
}
}
}
and my layout, which is just a Constraint Layout
<?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="match_parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/new_transaction_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:navigationIcon="#drawable/ic_close_black_24dp"
app:title="#string/lbl_new_transaction" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
The default parameters of setLayout(int, int) are MATCH_PARENT
You may try to use FILL_PARENT instead to see if it is able to change the width
Ref: https://developer.android.com/reference/android/view/Window#setLayout(int,%20int)