How to use onClick method of fragment inside recycleView and another fragments? - android-fragments

I have the custom view (post_skeleton_manage) and imageView with onclick parameter in it.
The structure is: MainActivity > MainFragment > ManageFragment > RecycleView > ManageBlockFragment > ImageView
Adapter creates some of my custom views:
class ManageAdapter(private val names: List<String>) : RecyclerView
.Adapter<ManageAdapter.MyViewHolder>() {
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val label: TextView = itemView.findViewById(R.id.label)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.post_skeleton_manage, parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.label.text = names[position]
}
override fun getItemCount() = names.size
}
In post_skeleton_manage i have this one:
...
<ImageView
android:onClick="ActiveAdminPanel"
android:id="#+id/settings"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="6dp"
app:layout_constraintEnd_toEndOf="#+id/bottom"
app:layout_constraintTop_toTopOf="#+id/bottom"
app:srcCompat="#drawable/settings_svgrepo_com" />
...
When User clicks to the imageView I wanna navigate to another Fragment. Here is the code of the MainActivity:
public fun activeAdminPanel(view: View){
Navigation.findNavController(this, R.id.nav_graph_pages).navigate(R.id.action_Pages_Manage_to_Admin)
}
In ManageBlockFragment I also have these ones:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.settings.setOnClickListener {
println("admin panel")
findNavController().navigate(R.id.action_Pages_Manage_to_Admin)
}
}
public fun activeAdminPanel(view: View){
findNavController().navigate(R.id.action_Pages_Manage_to_Admin)
}
When i run app and ... and click to imageView, Android Studio shows this error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.sutk, PID: 14414
java.lang.IllegalStateException: Could not find method ActiveAdminPanel(View) in a parent or ancestor Context for android:onClick attribute defined on view class androidx.appcompat.widget.AppCompatImageView with id 'settings'
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:479)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:437)
at android.view.View.performClick(View.java:7506)
at android.view.View.performClickInternal(View.java:7483)
at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
at android.view.View$PerformClick.run(View.java:29341)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7872)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Please, help
I need to make my "button" works. Help me, please <3

Related

How can i populate all images of an arraylist into an imageview of a recyclerview?

Im populating an arraylist of images from firebase and their links from firestore into an imageview of a recyclerview. The arrayList logs all data but shows only the first index of an aray on an imageview.
class AgriBusinessAdapter(private val context : Context, private val agriArrayList: ArrayList<AgriBusinessModel>, private val onCallBack: AgriBusinessAdapter.OnCallBack) :
RecyclerView.Adapter<AgriBusinessAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// passing our layout file for displaying our card item
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_agri, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// setting data to our text views from our modal class.
val agriModel: AgriBusinessModel = agriArrayList[position]
holder.nameV.text = agriModel.name
agriModel.images?.forEachIndexed { index, uri ->
Picasso.get().load(uri).into(holder.images)
Log.d("index", index.toString())
Log.d("uri", uri)
}
}
override fun getItemCount(): Int {
// returning the size of our array list.
return agriArrayList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
// creating variables for our views.
val nameV: TextView = itemView.findViewById(R.id.name)
var images : ImageView = itemView.findViewById(R.id.imageFromDb)
}
interface OnCallBack {
fun onCallBack(view: View, category: AgriBusinessModel)
fun onSelect(category: AgriBusinessModel)
}
}

Unable To Load ImageView from External Storage RecyclerView

I am working on an Android app which has to load all QR created image from external storage to the fragment which contains a RecyclerView. All the work goes fine, but as I tried to load the image from the specific path from external storage directory, it fails to load and throws an exception..
I am stuck with this as I have given the path to it like
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
val charItemcreate: CharItemsCreate = arrayList.get(position)
val path: String = Environment.getExternalStorageDirectory().toString() + "Maximus/QRCreated/"
val bitmap = BitmapFactory.decodeFile(path)
//holder.images = charItemcreate.imageload.toIcon()
}
Here is the Layout I Created For RecyclerView..
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constmain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints">
<ImageView
android:layout_width="#dimen/_62sdp"
android:layout_height="#dimen/_62sdp"
android:id="#+id/imgrecyclerviewcreate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/txt_nametext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#id/imgrecyclerviewcreate"
android:text="#string/email"/>
<TextView
android:id="#+id/txt_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#id/imgrecyclerviewcreate"
app:layout_constraintTop_toBottomOf="#+id/txt_nametext"
android:text="#string/email"/>
</androidx.constraintlayout.widget.ConstraintLayout>
The Adapter Class I have Created where i have Given the Images Folder path
class AdapterCreateHistory(var context: Context, var arrayList: ArrayList<CharItemsCreate>) :
RecyclerView.Adapter<AdapterCreateHistory.ItemHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder {
val viewHolder = LayoutInflater.from(parent.context)
.inflate(R.layout.createhistoryitem, parent, false)
return ItemHolder(viewHolder)
}
override fun getItemCount(): Int {
return arrayList.size
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
val charItemcreate: CharItemsCreate = arrayList.get(position)
val path: String = Environment.getExternalStorageDirectory().toString() + "Maximus/QRCreated/"
val bitmap = BitmapFactory.decodeFile(path)
//holder.images = charItemcreate.imageload.toIcon()
}
class ItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var images = itemView.findViewById<ImageView>(R.id.imgrecyclerviewcreate)
}
Here is the Kotlin Model Class
class CharItemsCreate {
var imageload: Bitmap? = null
constructor(imageload: Bitmap) {
this.imageload = imageload
}
}
Here is the Main Fragment I am Working on. In Here I have Initialez the RecyclerView and the CharItemClass
class FragmentViewPagerScanHistory : Fragment() {
private var charItemcreate: ArrayList<CharItemsCreate>? = null
private var customAdaptercreate: AdapterCreateHistory? = null
private var gridLayoutManager: GridLayoutManager? = null
//val TYPE_SAVED = 15
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_view_pager_scan_history, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
gridLayoutManager = GridLayoutManager(context, 1, LinearLayoutManager.VERTICAL, false)
recyclerviewcreatehistory?.layoutManager = gridLayoutManager
recyclerviewcreatehistory?.setHasFixedSize(true)
charItemcreate = setImages()
customAdaptercreate = AdapterCreateHistory(this.context ?: return, charItemcreate!!)
recyclerViewfragment?.adapter = customAdaptercreate
}
private fun setImages(): ArrayList<CharItemsCreate>? {
return charItemcreate
}
I am Unable to Load Images into RecyclerView as I Am Getting Exception . I have Attached the Debugger With this It Also Give me the Null Values...
I have Also Given the Read Permission in the Manifest
Here is the Logcat After It Crashed
Hello you can use Glide or picasso library, that will handle exception in very appropriate way,
here is the implementation of Glide :-
implementation 'com.github.bumptech.glide:glide:4.11.0'
This is is the code block :-
Glide.with(context).load(yourpath).centerCrop().error(image that place while error occure).into(imageview);

lateinit value is always null or not initialized with MapBox

Hello i have an issue with MapBox SDK for android , i use kotlin language in my project and the Viewmap value always came with problem. I'm new in kotlin so maybe i skip something.
i make bottom_navigation_bar so i use fragment to navigate in my application.
my fragment class were i use my variable
package com.example.parky.parky_android
import android.app.Application
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import com.mapbox.mapboxsdk.constants.Style
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
class ItemFourFragment : Fragment() {
private lateinit var mapView: MapView
fun onCreate(savedInstanceState: Bundle?, context: Context, inflater: LayoutInflater, container: ViewGroup?) {
super.onCreate(savedInstanceState)
// Mapbox Access token
Mapbox.getInstance(context, getString(R.string.token_mapbox))
val view = inflater.inflate(R.layout.activity_main, container ,false)
mapView = view.findViewById(R.id.mapview)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync({
it.setStyle(Style.SATELLITE)
// Customize map with markers, polylines, etc.
})
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_item_four, container, false)
}
companion object {
fun newInstance(): ItemFourFragment {
val fragment = ItemFourFragment()
return fragment
}
}
}
And my xml files where i display it :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemFiveFragment">
<com.mapbox.mapboxsdk.maps.MapView
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="41.885"
mapbox:mapbox_cameraTargetLng="-87.679"
mapbox:mapbox_styleUrl="#string/mapbox_style_satellite"
mapbox:mapbox_cameraTilt="20"
mapbox:mapbox_cameraZoom="12"/>
</RelativeLayout>
and finally the log
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.parky.parky_android, PID: 30820
kotlin.UninitializedPropertyAccessException: lateinit property mapView has not been initialized
at com.example.parky.parky_android.ItemFourFragment.onStart(ItemFourFragment.kt:42)
at android.support.v4.app.Fragment.performStart(Fragment.java:2372)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1467)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:797)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Do you have any idea what the problem is ?
Thanks for your time.
So here:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_item_four, container, false)
}
You're returning a view that will be attached to the Fragment and actually displayed.
Here:
fun onCreate(savedInstanceState: Bundle?, context: Context, inflater: LayoutInflater, container: ViewGroup?) {
super.onCreate(savedInstanceState)
// Mapbox Access token
Mapbox.getInstance(context, getString(R.string.token_mapbox))
val view = inflater.inflate(R.layout.activity_main, container ,false)
mapView = view.findViewById(R.id.mapview)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync({
it.setStyle(Style.SATELLITE)
// Customize map with markers, polylines, etc.
})
}
You're inflating a new view that is never being attached to anything. It's also inflating a separate layout, activity_main.xml, which I assume does not include a MapView.
Instead, you should resolve your MapView within onViewCreated(), after you've returned your inflated view in onCreateView():
override fun onViewCreated(View view, Bundle savedState) {
mapView = view.findViewById(R.id.mapview).apply {
onCreate(savedState)
getMapAsync { map ->
map.setStyle(Style.SATELLITE)
}
}
}
You also should not use lateinit var for this property, as you're not guaranteed to have a view created (e.g. onCreateView() may never be invoked). One instance of this is if your Fragment is on the backstack and not user visible. On a configuration change or recreation of the Activity, the Fragment on the backstack will go through onCreate(), but will not create a view. In this case, you would run into a crash in onStart() attempting to reference mapView that has not been initialized.
Instead, leave it nullable, and perform the operations with mapView?.doThing().

Kotlin RecyclerView in Fragment - Navigation architecture component - null error

I am trying to create a RecyclerView in a fragment but I am getting a null error on the RecyclerView. I was able to create the fragment successfully using the new Navigation architecture component with a bottom navigation bar. I am running Android Studio canary 3.2 Beta 1.
Note sure where I have gone wrong as I am not getting any red lines in Android Studio.
Debug Error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.projects.arise.mytestapp, PID: 28285
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.projects.arise.mytestapp/com.projects.arise.mytestapp.MainActivity}:
java.lang.IllegalStateException: rview_keys must not be null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.IllegalStateException: rview_keys must not be null
at com.projects.arise.mytestapp.MainActivity.onCreate(MainActivity.kt:55)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
at android.app.ActivityThread.-wrap11(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
at android.os.Handler.dispatchMessage(Handler.java:105) 
at android.os.Looper.loop(Looper.java:164) 
at android.app.ActivityThread.main(ActivityThread.java:6541) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val host: NavHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: return
val navController = host.navController
setupBottomNavMenu(navController)
}
override fun onSupportNavigateUp(): Boolean {
return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp()
}
private fun setupBottomNavMenu(navController: NavController) {
findViewById<BottomNavigationView>(R.id.navigation)?.let { bottomNavView ->
NavigationUI.setupWithNavController(bottomNavView, navController)
}
}
}
FragmentKeys.kt
class FragmentKeys : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true)
return inflater.inflate(R.layout.fragment_keys_layout, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
//val rview_keys: RecyclerView = findViewById(R.id.rview_keys)
rview_keys.layoutManager = LinearLayoutManager(context)
rview_keys.adapter = AdapterKeys(KeysListObjects.keys)
}
}
I commented out the one line above because I was getting an "unresolved reference" error on "findViewById". This line didn't seem to be necessary as it was not in other people's code. For example: Kotlin Android Fragment recyclerView and context issue
AdapterKeys.kt
class AdapterKeys(val keys: List<KeysList>) : RecyclerView.Adapter<AdapterKeys.KeysViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KeysViewHolder {
val view = LayoutInflater.from(parent?.context).inflate(R.layout.list_item_keys, parent, false)
return KeysViewHolder(view)
}
override fun getItemCount() : Int {
return keys.size
} //override fun getItemCount() = keys.size
override fun onBindViewHolder(holder: KeysViewHolder, position: Int) {
val keysList = keys[position]
holder.setData(keysList, position)
}
inner class KeysViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setData(keysList: KeysList?, position: Int) {
itemView.tview_Keys.text = keysList!!.keysText
}
}
}
ModelKeys.kt
object KeysListObjects {
val keys = listOf<KeysList>(
KeysList("Testing1"),
KeysList("Testing2"),
KeysList("Testing3")
)
}
you are getting the error because you commented this
//val rview_keys: RecyclerView = findViewById(R.id.rview_keys)
there is no declaration of rview_keys as a variable. So it is considering rview_keys as a view because in your activity you have a view with id rview_keys.
Following lines from error just confirm it.
java.lang.IllegalStateException: rview_keys must not be null at com.projects.arise.mytestapp.MainActivity.onCreate(MainActivity.kt:55) at
Check code at line number 55 of MainActivity.
The reason these people don't have that line is that they are using it as a view.
And you can't use it as a view in onActivityCreated().
I had to do two things to get this to work:
Move the two rview_keys lines of code from onActivityCreated to onViewCreated (which I believe is earlier in the fragment lifecycle). Thanks to above posters for their feedback here! So now my fragment class looks like this:
FragmentKeys.kt
class FragmentKeys : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true)
return inflater.inflate(R.layout.fragment_keys_layout, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rview_keys.layoutManager = LinearLayoutManager(context)
rview_keys.adapter = AdapterKeys(KeysListObjects.keys)
}
}
I was still getting build errors so I tried changing one of the Kotlin dependencies in my build.gradle file (jdk7) back to what it was before even (jre7) though I was getting a deprecation warning.
The new dependency I was being asked to use - which wasn't working:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
The old dependency I switched back to - which is working (for now):
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

Error calling setSupportActionBar in a Fragment in Kotlin

I am trying to set up a toolbar in a fragment.
Whilst the Google Developer docs have been updated to include Kotlin code (see this page):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my)
// Note that the Toolbar defined in the layout has the id "my_toolbar"
setSupportActionBar(findViewById(R.id.my_toolbar))
it relates to the setup of a toolbar in an activity as opposed to a fragment.
I found this SO post which suggests that you can't just call setSupportActionBar in a fragment. To quote:
Fragments don't have such method setSupportActionBar(). ActionBar is a
property of Activity, so to set your toolbar as the actionBar, your
activity should extend from ActionBarActivity and then you can call in
your Fragment:
...
If you're using AppCompatActivity:
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);
However the code given above is in java.
How do I call this in Kotlin?
To access the ActionBar from a Fragment in Kotlin:
if(activity is AppCompatActivity){
(activity as AppCompatActivity).setSupportActionBar(mToolbar)
}
To set an ActionBar title from a Fragment you can do
(activity as AppCompatActivity).supportActionBar?.title = "Title"
or
(activity as AppCompatActivity).supportActionBar?.setTitle(R.string.my_title_string)
There is an implementation in the Navigation codelab from Google that I think will do what I need: enable customisation of the title, menu items and hook into the up navigation for different fragment contexts. Specifically:
The toolbar is included in the main layout xml file (navigation_activity.xml in that codelab) outside of the fragment:
navigation_activity.xml
<LinearLayout>
<android.support.v7.widget.Toolbar/>
<fragment/>
<android.support.design.widget.BottomNavigationView/>
</LinearLayout>
Then setup the toolbar in the main activity file as follows:
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var drawerLayout: DrawerLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.navigation_activity)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
//...
// Set up Action Bar
val navController = host.navController
setupActionBar(navController)
//...
}
private fun setupActionBar(navController: NavController) {
drawerLayout = findViewById(R.id.drawer_layout)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val retValue = super.onCreateOptionsMenu(menu)
val navigationView = findViewById<NavigationView>(R.id.nav_view)
// The NavigationView already has these same navigation items, so we only add
// navigation items to the menu here if there isn't a NavigationView
if (navigationView == null) {
menuInflater.inflate(R.menu.menu_overflow, menu)
return true
}
return retValue
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Have the NavHelper look for an action or destination matching the menu
// item id and navigate there if found.
// Otherwise, bubble up to the parent.
return NavigationUI.onNavDestinationSelected(item,
Navigation.findNavController(this, R.id.my_nav_host_fragment))
|| super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(drawerLayout,
Navigation.findNavController(this, R.id.my_nav_host_fragment))
}
}
Then in the fragment file you can inflate further menu items. In the codelab, main_menu.xml contains a shopping cart item which is added to the overflow setup in the main activity above.
MainFragment.kt
class MainFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true)
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.main_menu, menu)
}
}

Resources