Showing DialogFragment from RecyclerView in Kotlin [duplicate] - java

This question already has answers here:
Starting DialogFragment from a class extending RecyclerView.ViewHolder
(2 answers)
DialogFragment From RecyclerView
(1 answer)
Closed 7 months ago.
I have a DialogFragment that I want to show when clicking on an item inside a Recycler View. Here are my files:
DialogFragment.kt:
class TaskDialogFragment:DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var rootView: View = inflater.inflate(R.layout.task_dialog, container, false)
return rootView
}
}
RecyclerViewAdapter.kt:
class RecycleViewAdapter(): RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>() {
private lateinit var dao: TaskDao
private lateinit var dialogFragment: TaskDialogFragment
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
init {
itemView.setOnClickListener { v: View ->
// this is where I want my dialogFragment to be opened from
dialogFragment = TaskDialogFragment()
dialogFragment.show(supportFragmentManager, "taskDialog")
}
}
}
I have tried following the steps shown here https://developer.android.com/guide/fragments/dialogs but I get an error saying Unresolved Reference: supportFragmentManager.
How would I open this dialog from the recycler view? Any tips would be appreciated.

Related

How to navigate from ViewModel to a Fragment in Android Kotlin

I have a view model I have added a click event listener. How do I navigate from that ViewModel into a Fragment
The ViewModel Code
class PromoAdapter(var promo: ArrayList<PromoModal>) :
RecyclerView.Adapter<PromoAdapter.UserViewHolder>() {
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(promo[position])
holder.promoRow.setOnClickListener() {
// Navigate to Fragment with name UserFragment
};
}
}
User Fragment Code
class UserFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
val view: View = LayoutInflater.from(container!!.context)
.inflate(R.layout.user_page_fragment, container, false)
}
}
I have tried writing the following code still not working
Inside the ViewModel Click Event
val intent = Intent(itemView.context, UserFragment::class.java)
itemView.context?.startActivity(intent)
I cant find something working any help will be appreciated
It's better to move the click listener to a fragment
In Adapter:
class PromoAdapter(
var promo: ArrayList<PromoModal>,
val openFragment: (promoModal: PromoModal) -> Unit
) :
RecyclerView.Adapter<PromoAdapter.UserViewHolder>() {
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(promo[position])
val currentItem = promo.getOrNull(position) ?: return
holder.promoRow.setOnClickListener {
openFragment(currentItem)
};
}
}
In Fragment:
val mAdapter = PromoAdapter(
promo = promoList,
openFragment = { promoModal ->
// Navigate to Fragment with name UserFragment
}
)

How to send data from Activity to Fragment using Interface and without the transaction?

I want to send the data from MainActivity to Fragment but i don't want to pass the data in the arguments when i am making the transaction to the fragment like below:
val bundle = Bundle()
bundle.putString("name", name)
val fragment = BlankFragment(this)
fragment.arguments = bundle
supportFragmentManager.beginTransaction().replace(R.id.fragmentView, fragment).commit()
I want to pass the data from the activity to the fragment using the interface. I am able to send the data from the fragment to the activity using the interface but not vice versa.
You have an instance of a fragment in fragment, so provided it has a property name you can just say fragment.name = "name".
Note that when the app is restarted by the system after it is killed, the system will try to restore the fragment by calling it with empty constructor. So you can't have a constructor that have arguments, and also you won't get a name if you set it using fragment.name = "name". Using a bundle ensures that that the fragment gets its arguments after restart.
I hope this can resolve your issue
Adding fragment to Activity
val interfaceCall:FetchDataInterface = DataFragment.newInstance("data")
interfaceCall.getData("data from interface")
supportFragmentManager.beginTransaction()
.replace(R.id.frame, DataFragment.newInstance("data"))
.commit()
Fragment Class
class DataFragment : Fragment(),MainActivity.FetchDataInterface {
// TODO: Rename and change types of parameters
private var param1: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(DATA)
Log.e("checkParam", " : $param1")
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_data, container, false)
}
companion object {
// TODO: Rename and change types and number of parameters
#JvmStatic
fun newInstance(value: String) =
DataFragment().apply {
arguments = Bundle().apply {
putString(DATA, value)
}
}
}
override fun getData(value: String) {
Log.e("checkParam", " interface: $value")
}
}
Interface
interface FetchDataInterface{
fun getData(value:String)
}
Tryout this onces
In activity.....
TextEditorDialogFragment textEditorDialogFragment =
TextEditorDialogFragment.show(this, text, colorCode);
In Fragment....
public class TextEditorDialogFragment extends DialogFragment {
public static final String TAG = TextEditorDialogFragment.class.getSimpleName();
String inputText;
int colorCode;
public static TextEditorDialogFragment show(#NonNull AppCompatActivity appCompatActivity, #NonNull String inputText_, #ColorInt int colorCode_) {
inputText =inputText_;
colorCode=colorCode_;
TextEditorDialogFragment fragment = new TextEditorDialogFragment();
fragment.show(appCompatActivity.getSupportFragmentManager(), TAG);
return fragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.add_text_dialog, container, false);
}
}

Kotlin: Fragment not attached, Unable to instantiate fragment calling fragment const caused exception

I am trying to pass a childFragmentManager from a fragment to an adapter. The current fragment is called from a different fragment and not activity.
the fragment class has a val
class DisplaySchoolFrag : BaseFragment<binding, DisplaySchoolViewModel>{
...
private val adapter = DisplaySchoolAdapter(childFragmentManager)
In the adapter I just have the const declaration for childFrag no other usage for now.
class DisplaySchoolAdapter(childFrag: FragmentManager) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
I need the childFragmentManager inside the adapter, because inside the adapter class theres a button which leads to bottomsheet fragment.
FragmentHostCallback<?> mhost
getChildFrar(){
if (this.mHost == null) {
throw new IllegalStateException("Fragment " + this + " has not been attached yet.");
and this line is causing the Fragment not attached, Unable to instantiate fragment calling fragment const caused exception
i tried this
lateinit var childFrag : FragmentManager
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
childFrag = childFragmentManager
return super.onCreateView(inflater, container, savedInstanceState)
}
and passing the childFrag into the DisplaySchoolAdapter(childFrag) declaration still getting the error.
You should pass in a callback in to DisplaySchoolAdapter and override the individual item's setOnClickListener listener and invoke the callback.
class DisplaySchoolAdapter(lambdaToBeInvoked: () -> Unit): RecyclerView.Adapter<SomeViewHolder>() {
... set up your adapter
override fun onBindViewHolder(holder: SomeViewHolder, position: Int) {
val item = items[position]
holder.bind(item)
holder.itemView.setOnClickListener { lambdaToBeInvoked() }
}
}
You can fill in the implementation details in the rest of your adapter, but the onBindViewHolder is where you would invoke the callback. If you need to pass any parameters into there, then feel free to add those in your implementation.
Then in your fragment when you instantiate your adapter you would pass in what you want your childFragment to do.
class YourFragment: FragmentActivity() {
override onCreate() {
val adapter = DisplaySchoolAdapter {
// have your childFragment navigate to somewhere
}
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager()
}
}

How to open a Kotlin Class uisng Java Class in Android?

I am calling one button click listener in my java class that will open the Kotlin class fragment. I have written the code but facing a small issue related to a new instance in java class. Please guied on this.
Java Class Code:
notifications.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fp = getSupportFragmentManager();
FragmentTransaction ok = fp.beginTransaction();
ok.add(R.id.fragment_container_dashboard, Weather.newInstance());
ok.addToBackStack(null);
ok.commit();
}
});
*Can not resolve the method 'newInstance' in 'Weather.'
Kotlin Class:
class Weather : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Get the custom view for this fragment layout
return inflater!!.inflate(R.layout.weather, container, false)
}
}
How to resolve this?
Assuming that newInstance() is placed in the companion object of Weather fragment class, from within Java code you can call it like this:
Weather.Companion.newInstance()

Creating a backstack like Instagram's bottom navigation bar

I was wondering how can i create something that is like instagram's backstack.
I have a an app, that has a bottom navigation bar which opens 3 different fragments (MapFragment, HostFragment, ProfileFragment), inside HostFragment, i create a new one called Host2Fragment, when the user clicks a button:
Tab1 Tab2 Tab3
[MapFragment][HostFragment][ProfileFragment]
.
.
.
[Host2Fragment]
Some examples:
NOTE: Tab1/MapFragment is the home fragment
User is on Host2Fragment, pressing back goes back to HostFragment
pressing back again goes to Tab1
User is on Host2Fragment, clicking on Tab2 goes back to HostFragment
Essentially, pressing back, should just peel off all the layers back to the home fragment (Tab1), and update the bottom navigation bar while doing so. I also want to keep the state of the fragments, so that when i click back to it, it should still be in the same state
What i have so far:
MainActivity
class MainActivity : AppCompatActivity(){
private val mapFragment: Fragment = MapFragment()
private val hostFragment: Fragment = HostFragment()
private val profileFragment: Fragment = ProfileFragment()
private val fm = supportFragmentManager
private var activeFragment = mapFragment
lateinit var toolbar: ActionBar
private val mOnNavigationItemSelectedListener =
BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_map -> {
fm.beginTransaction().hide(activeFragment).show(mapFragment).commit()
activeFragment = mapFragment
return#OnNavigationItemSelectedListener true
}
R.id.navigation_host -> {
fm.beginTransaction().hide(activeFragment).show(hostFragment).commit()
activeFragment = hostFragment
return#OnNavigationItemSelectedListener true
}
R.id.navigation_profile -> {
fm.beginTransaction().hide(activeFragment).show(profileFragment).commit()
activeFragment = profileFragment
return#OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fm.beginTransaction().add(R.id.container, profileFragment, "profileFragment").hide(profileFragment).commit()
fm.beginTransaction().add(R.id.container, hostFragment, "hostFragment").hide(hostFragment).commit()
fm.beginTransaction().add(R.id.container, mapFragment, "mapFragment").commit()
toolbar = supportActionBar!!
val bottomNavigation: BottomNavigationView = findViewById(R.id.navigationView)
bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
//the home Fragment
bottomNavigation.selectedItemId = R.id.navigation_map
}
}
HostFragment
class HostFragment : Fragment(){
companion object {
private const val TAG = "HostFragment"
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_host, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val button = view.findViewById(R.id.button) as Button
button.setOnClickListener{
Log.d(HostFragment.TAG, "Clicked Host button")
fragmentManager?.beginTransaction()?.add(R.id.container, Host2Fragment(), "host2Fragment")?.commit()
}
}
}

Categories