I want to switch Fragments by button click inside the fragment itself. I have have created viewpager + tablayout, everything worked until i made an interface to communicate with my activity where i can set different Page for Viewpager. I am pretty new to Kotlin and I do not understand why I am catching NullPointer :(
I probably initialized my button poorly too, but I am not sure
Here is my MainActivity code
class MainActivity : AppCompatActivity()
, MyFragment1.buttonClick {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tablayout.addTab(tablayout.newTab().setIcon(R.drawable.ic_fragment1))
tablayout.addTab(tablayout.newTab().setIcon(R.drawable.ic_fragment_2))
tablayout.addTab(tablayout.newTab().setIcon(R.drawable.ic_fragment3))
tablayout.tabGravity = TabLayout.GRAVITY_FILL
val adapter = MyAdapter(this, supportFragmentManager, tablayout.tabCount)
viewpager!!.adapter = adapter
viewpager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tablayout))
val tabStrip = tablayout.getChildAt(0) as LinearLayout
for (i in 0 until tabStrip.childCount) {
tabStrip.getChildAt(i).setOnTouchListener { v, event -> true }
}
}
override fun buttonClicked(view: View) {
viewpager.currentItem = 2
}
fun selectIndex(index: Int) {
viewpager.currentItem = index
}
override fun onBackPressed() {
val currentPos = viewpager.currentItem
if (currentPos != 0) {
viewpager.currentItem = 0
} else {
super.onBackPressed()
}
}
}
**And a code for my Fragment**
class MyFragment1 : Fragment() {
private var click: buttonClick? = null
interface buttonClick {
fun buttonClicked(view: View)
}
var currentPage: Int = 0
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_my_fragment1, container, false)
val btn: Button = view?.findViewById(R.id.btn_next)
btn.setOnClickListener {
Toast.makeText(context, "test", Toast.LENGTH_LONG).show()
click?.buttonClicked(it)
}
return view
}
}
Have you initialized your click variable?
private var click: buttonClick? = null
override fun onAttach(context: Context?) {
super.onAttach(context)
click = context as? buttonClick
}
override fun onDetach() {
super.onDetach()
click = null
}
Related
This is my Activity function that the startActivity(i) unable go to the Fragment page after scanning a barcode, I have try that it can go to activity page and show the code successful but I need it go to Fragment page.
barcodeDetector.setProcessor(object : Detector.Processor<Barcode> {
override fun release() {
Toast.makeText(applicationContext, "Scanner has been closed", Toast.LENGTH_SHORT)
.show()
}
override fun receiveDetections(detections: Detector.Detections<Barcode>) {
val barcodes = detections.detectedItems
if (barcodes.size() == 1) {
scannedValue = barcodes.valueAt(0).rawValue
runOnUiThread {
cameraSource.stop()
Toast.makeText(this#InsertStockInActivity, scannedValue, Toast.LENGTH_SHORT).show()
val i = Intent(this#InsertStockInActivity, comFragment::class.java)
.putExtra("cameraSource", scannedValue)
startActivity(i)
finish()
}
}else
{
Toast.makeText(this#InsertStockInActivity, "value- else", Toast.LENGTH_SHORT).show()
}
}
})
This is my Fragment page. do I write anything wrong?
class comFragment : Fragment() {
private lateinit var binding: FragmentComBinding
private val nav by lazy { findNavController() }
private val vm: StockInViewModel by activityViewModels()
private val formatter = SimpleDateFormat("dd MMMM yyyy '-' hh:mm:ss a", Locale.getDefault())
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentComBinding.inflate(inflater, container, false)
//binding.btnScanBarcode.setOnClickListener{ nav.navigate(R.id.insertStockInActivity) }
val value = requireActivity().intent.getStringExtra("cameraSource")
binding.edtId.findViewById<EditText>(R.id.value)
return binding.root
}
}
You use intent to navigate to Activity not to Fragment.
You can:
Use fragment transactions to navigate to new Fragment in your current Activity
Use intent to navigate to new Activity and in your new Activity use fragment transactions to your Fragment
You need to create a class that extends FragmentActivity and start your fragment there:
public class MyFragmentActivity extends YourActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null){
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, new MyFragment ()).commit();}
}
}
then fragment constructor:
public MyFragment() {
}
then from your calling activity, start your fragment activity in the normal way
Intent i = new Intent(YourActivity.this, MyFragment.class);
startActivity(i);
This this code :
in which i open bottomSheetDialogFragment in that i want to add fragment.
I want to add multiple fragments in bottomsheetDialogFragment but it throws
java.lang.IllegalArgumentException: No view found for id 0x7f0a01cb
class AddNotesBottomSheetDialog : BottomSheetDialogFragment() {
private lateinit var bottomSheetDialog: BottomSheetDialog
private lateinit var bottomSheetBehavior: BottomSheetBehavior<View>
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
Log.v(LOG_TAG, "-> onCreateDialog")
bottomSheetDialog = BottomSheetDialog(context!!)
var view = View.inflate(context, R.layout.bottom_sheet_notes, null)
bindViews(view)
bottomSheetDialog.setContentView(view)
bottomSheetBehavior = BottomSheetBehavior.from(view.parent as View)
bottomSheetBehavior.isHideable = false
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
return bottomSheetDialog
}
private fun bindViews(view: View) {
loadAddNotesFragments()
}
override fun onStart() {
super.onStart()
Log.v(LOG_TAG, "-> onStart")
bottomSheetBehavior.isHideable = false
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
if (!visible)
dialog.hide()
}
fun show(fragmentManager: FragmentManager) {
Log.v(LOG_TAG, "-> show")
visible = true
if (isAdded) {
Log.v(LOG_TAG, "-> Is already added")
dialog.show()
} else {
Log.v(LOG_TAG, "-> Not added")
show(fragmentManager, AddNotesBottomSheetDialog.LOG_TAG)
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.v(LOG_TAG, "-> onDestroyView")
}
private fun loadAddNotesFragments() {
val createNoteFragment = CreateNoteFragment()
val ft = fragmentManager?.beginTransaction()
ft?.replace(R.id.placeHolderBottomSheet, createNoteFragment)
ft?.commit()
}
}
Solved: I tried to add multiple fragments transaction in bottomSheetDialogFragment but it's not possible to do transaction in BottomSheetDialogFragment thats why its through this exception. so i used viewPager inside the BottomsheetDialog and its work perfect.
try calling loadAddNotesFragments() in
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
loadAddNotesFragments()
}
And try using childFragmentManager to begin transaction's: reference
private fun loadAddNotesFragments() {
val createNoteFragment = CreateNoteFragment()
val ft = childFragmentManager()?.beginTransaction()
ft?.replace(R.id.placeHolderBottomSheet, createNoteFragment)
ft?.commit()
}
I believe this will solve your problem.
UPDATE:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.bottom_sheet_notes, container, false)
}
use this to inflate the content of bottomSheet, and
REMOVE:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
Log.v(LOG_TAG, "-> onCreateDialog")
bottomSheetDialog = BottomSheetDialog(context!!)
var view = View.inflate(context, R.layout.bottom_sheet_notes, null)
bindViews(view)
bottomSheetDialog.setContentView(view)
bottomSheetBehavior = BottomSheetBehavior.from(view.parent as View)
bottomSheetBehavior.isHideable = false
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
return bottomSheetDialog
}
ADD:
override fun onStart() {
super.onStart()
val bottomSheet = dialog.findViewById(android.support.design.R.id.design_bottom_sheet) as ViewGroup //FrameLayout as my
val mBehavior = BottomSheetBehavior.from(bottomSheet)
//Add Behavior logic here
}
NOTE:
No need of overriding onCreateDialog() unless you want your own Dialog to be initiated, i.e some other type of dialog.
I have tried to add an setOnClickListener in my Fragment. But both methods i tried didnt work. There is no readction to my button press in the App.
class LoginFragment: Fragment(), View.OnClickListener {
//AuthVariable for global use
private lateinit var myAuth: FirebaseAuth
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
var view = inflater.inflate(R.layout.content_login, container, false)
view?.login_button?.setOnClickListener(this)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onClick(p0: View?) {
Log.i("BUTTON123","TEST")
loginUser()
}
}
Activity:
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
//AuthVariable for global use
private lateinit var myAuth : FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
nav_view.setNavigationItemSelectedListener(this)
//Initializing FirebaseAuth Instance
myAuth = FirebaseAuth.getInstance()
var user = myAuth.currentUser
if(user != null){
updateUI(user)
}else{
val test = supportFragmentManager
val frag = LoginFragment()
test.beginTransaction().replace(R.id.placeholder,frag).addToBackStack(null).commit()
}
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
R.id.action_settings -> return true
else -> return super.onOptionsItemSelected(item)
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.nav_addShop -> {
//Activity to Add your Shop
val addshopIntent = Intent(this,AddShopActivity::class.java)
startActivity(addshopIntent)
}
R.id.nav_searchShop -> {
//SearchFragment
val test = supportFragmentManager
val frag = test()
test.beginTransaction().replace(R.id.placeholder,frag).addToBackStack(null).commit()
}
R.id.nav_shopMap -> {
//MapActivity
val mapintent = Intent(this, ShopMap::class.java)
startActivity(mapintent)
}
R.id.nav_manage -> {
}
R.id.nav_share -> {
}
R.id.nav_logout -> {
myAuth.signOut()
updateUI(myAuth.currentUser)
}
}
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
}
Did you forget the onClick() method in LoginFragment?
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.content_login, container, false)
view.login_button.setOnClickListener {
Log.i("BUTTON123","TEST")
loginUser()
}
return view
}
I have created RecyclerView in fragment inside activity, all are working good but when i do notifyDataSetChanged() to adapter from activity through interface,I got an error "lateinit property adapter has not been initialized" but I have already initialized adapter
class BuildingListFragment : Fragment(), MainActivity.EditInterface {
lateinit var adapter: BuildingListAdapter
private var mListener: OnFragmentInteractionListener? = null
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_building_list, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val buildingList = ArrayList<BuildingDetailModel>()
val alphaList = arrayOf("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K",
"L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "z")
for (i in alphaList.indices) {
val building = BuildingDetailModel()
building.buildingName = alphaList[i] + " Building"
buildingList.add(building)
}
//initialize adapter
adapter = BuildingListAdapter(buildingList)
// RV_Building_List.layoutManager = LinearLayoutManager(context, LinearLayout.VERTICAL, false)
RV_Building_List.adapter = adapter
RV_Building_List.layoutManager = object : LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false) {
override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State) {
super.onLayoutChildren(recycler, state)
//TODO if the items are filtered, considered hiding the fast scroller here
val firstVisibleItemPosition = findFirstVisibleItemPosition()
if (firstVisibleItemPosition != 0) {
// this avoids trying to handle un-needed calls
if (firstVisibleItemPosition == -1)
//not initialized, or no items shown, so hide fast-scroller
{
fastscroller.visibility = View.GONE
}
return
}
val lastVisibleItemPosition = findLastVisibleItemPosition()
val itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1
//if all items are shown, hide the fast-scroller
fastscroller.visibility = if (adapter.itemCount > itemsShown) View.VISIBLE else View.GONE
}
}
fastscroller.setRecyclerView(RV_Building_List)
fastscroller.setViewsToUse(R.layout.recycler_view_fast_scroller__fast_scroller, R.id.fastscroller_bubble, R.id.fastscroller_handle)
}
override fun editClickFromMainActivity() {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
//at this line error is lateinit property adapter has not been initialized
if (adapter.getIsSelected()) adapter.setIsSelected(false) else adapter.setIsSelected(true)
}
override fun onDetach() {
super.onDetach()
mListener = null
}
override fun onResume() {
super.onResume()
}
interface OnFragmentInteractionListener {
// TODO: Update argument type and name
fun onFragmentInteraction(uri: Uri)
}
companion object {
// TODO: Rename and change types and number of parameters
fun newInstance(): BuildingListFragment {
val fragment = BuildingListFragment()
return fragment
}
}
}
My mainActivity
class MainActivity : AppCompatActivity() {
private val mOnNavigationItemSelectedListener =
BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_list -> {
val fragment = BuildingListFragment.Companion.newInstance();
addFragment(fragment, R.anim.slide_re_in, R.anim.slide_re_out)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_map -> {
val fragment = BuildingMapFragment.Companion.newInstance();
addFragment(fragment, R.anim.slide_in, R.anim.slide_out)
return#OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
val fragment = BuildingListFragment.Companion.newInstance()
addFragment(fragment, R.anim.slide_re_in, R.anim.slide_re_out)
iv_Add.setOnClickListener {
var intent = Intent(this, AddBuildingMapsActivity::class.java)
startActivity(intent)
}
iv_edit.setOnClickListener {
(BuildingListFragment.newInstance() as EditInterface).editClickFromMainActivity()
}
}
/**
* add/replace fragment in container [framelayout]
*/
private fun addFragment(fragment: Fragment, slide_re_in: Int, slide_re_out: Int) {
supportFragmentManager
.beginTransaction()
.setCustomAnimations(slide_re_in, slide_re_out)
.replace(R.id.fragmentContainer, fragment, null)//fragment.javaClass.getSimpleName()
.addToBackStack(null)//fragment.javaClass.getSimpleName()
.commit()
}
override fun onBackPressed() {
super.onBackPressed()
Log.e("TAG", "TAG")
}
interface EditInterface {
fun editClickFromMainActivity()
}
}
please help me to solve this issue
thanks..
Your problem is that you're creating a new instance of the fragment when the click handler is being called in the main activity line
(BuildingListFragment.newInstance() as EditInterface).editClickFromMainActivity()
You will need to call the method on the actual fragment instance that's currently on screen. There's various ways of getting around this but I think the safest path for now is doing something like
iv_edit.setOnClickListener {
val fragment = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? BuildingListFragment
fragment?.editClickFromMainActivity()
}
though this will mean that you must also use the same FRAGMENT_TAG in addFragment on the .replace(R.id.fragmentContainer, fragment, null) line (FRAGMENT_TAG instead of null)
I need to open a context menu on MenuItem click. How can i do this? I've tried to do this on BottomNavigationView.OnNavigationItemSelectedListener:
registerForContextMenu(menuItem.actionView)
openContextMenu(menuItem.actionView)
but the actionView in null.
Thanks a lot.
Main Activity:
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
navigation.selectedItemId = R.id.navigation_dashboard
}
}
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
...
R.id.navigation_add -> {
registerForContextMenu(menuItem.actionView)
openContextMenu(item.actionView)
return#OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
navigation.selectedItemId = R.id.navigation_dashboard
}
override fun onCreateContextMenu(menu: ContextMenu, v: View,
menuInfo: ContextMenuInfo) {
...
}
override fun onContextItemSelected(item: MenuItem): Boolean {
...
}