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);
Related
I have an old project written in Java made to slide horizontally between three different fragments, and they were stated on the main activity. It worked perfect.
public class MainActivity extends AppCompatActivity {
ViewPager pager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = findViewById(R.id.theViewPagerInTheMainActivity);
pager.setOffscreenPageLimit(3);
PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager());
Frag_A aFrag = new Frag_A();
adapter.addItem(aFrag);
Frag_B bFrag = new Frag_B();
adapter.addItem(bFrag);
Frag_C cFrag = new Frag_C();
adapter.addItem(cFrag);
pager.setAdapter(adapter);
pager.setCurrentItem(1);
}
class PagerAdapter extends FragmentStatePagerAdapter {
ArrayList<Fragment> items = new ArrayList<Fragment>();
public PagerAdapter(FragmentManager fragManager) {
super(fragManager);
}
public void addItem(Fragment item) {
items.add(item);
}
#Override
public Fragment getItem(int position) {
return items.get(position);
}
#Override
public int getCount() {
return items.size();
}
}
}
Each three different fragments, followed by different codes that works fine, starts with:
public class Frag_A extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag_a, container, false);
}
}
Same goes like Frag_B and frag_b layout, Frag_C and frag_c layout.
I'm doing it all again now, but in Kotlin and using ViewPager2. I'm not making any fragments programmatically, I want all three of their ID written on the main activity. Converting the code directly in Android Studio didn't work, of course, and hours of searching failed to cover my needs. From my humble understanding, creating different-coloured fragments from one pre-made fragment doesn't really seem to be adaptable for my project and all ended up in red underlines. Can it be made without importing .v4 supporting library?
Solved by myself!
class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val adapter = DatPagerAdapter(this)
val fragsList = listOf(Frag_A(), Frag_B(), Frag_C())
adapter.fragsListHere.addAll(fragsList)
theVP2InTheMainActivity.adapter = adapter
theVP2InTheMainActivity.setCurrentItem(1)
}
class DatPagerAdapter(fragactivity: FragmentActivity) : FragmentStateAdapter(fragactivity) {
val fragsListHere = mutableListOf<Fragment>()
override fun getItemCount():Int = fragListHere.size
override fun createFragment(position: Int): Fragment = fragListHere[position]
}
}
Since FragmentPagerAdapter is depecrated. I switch it to FragmentStateAdapter(FragmentActivity fragmentActivity) that work fine with ViewPager2
My ViewPagerAdapter :
```
class ViewPagerAdapter(fragmentActivity: FragmentActivity):
FragmentStateAdapter(fragmentActivity){
override fun getItemCount(): Int {
return 3
}
override fun createFragment(position: Int): Fragment {
return when(position){
0 -> {
HomeFragment()
}
1 -> {
HomeFragment2()
}
2 -> {
HomeFragment3()
}
else -> {
throw Resources.NotFoundException("Position Not Found")
}
}
}
}
```
My Activity :
class MainActivity5 : AppCompatActivity() {
private lateinit var binding: ActivityMain5Binding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMain5Binding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.viewpager.adapter = ViewPagerAdapter(this)
}
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
override fun onBackPressed() {
if (binding.viewpager.currentItem == 0) {
super.onBackPressed()
} else {
// Otherwise, select the previous step.
binding.viewpager.currentItem = binding.viewpager.currentItem - 1
}
}
}
Thanks For asking!!
Note: I used binding to replace findViewById
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
}
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 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 know this question asked many times. But I didn't get the asnswer. I have a layout which contains two Tabs. When I switch the tabs they are reloading every time. Many people suggest to use viewpager. But I know nothing about viewPager. My project is almost completed.
My layout code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_devices);
mPreferences = getSharedPreferences(PreferencesManager.SCOPE,
MODE_PRIVATE);
mBundle = getIntent().getExtras();
try {
rl = (RelativeLayout) findViewById(R.id.mainLayout);
//((Object) rl).setOffscreenPageLimit(2);
fragMentTra = getFragmentManager().beginTransaction();
ActionBar bar = getActionBar();
bar.addTab(bar.newTab().setText(TAB_NAME1).setTabListener(this));
bar.addTab(bar.newTab().setText(TAB_NAME2).setTabListener(this));
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.show();
} catch (Exception e) {
e.getMessage();
}
}
FragmentMine fram1;
FragmentTransaction fragMentTra = null;
FragmentAll fram2;
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (tab.getText().equals(TAB_NAME1)) {
try {
rl.removeAllViews();
} catch (Exception e) {
}
fram1 = new FragmentMine();
fragMentTra.addToBackStack(null);
fragMentTra = getFragmentManager().beginTransaction();
fragMentTra.add(rl.getId(), fram1);
fragMentTra.commit();
} else if (tab.getText().equals(TAB_NAME2)) {
try {
rl.removeAllViews();
} catch (Exception e) {
}
fram2 = new FragmentAll();
fragMentTra.addToBackStack(null);
fragMentTra = getFragmentManager().beginTransaction();
fragMentTra.add(rl.getId(), fram2);
fragMentTra.commit();
}
}
How to stop reloading tabs when switched?
Every time onTabSelected() is called you are instantiating a new Fragment.
You should make use of a FragmentPagerAdapter.
Check: http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html
As pointed out by Rik, you are instantiating a new Fragment by:
fram1 = new FragmentMine();
You need to save the state of your fragment by overriding onSaveInstanceState():
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Whatever is there to save
}
Using this class helps you for work onViewCreated only one time
abstract class BaseFragment<B : ViewDataBinding>(
private val viewID: Int,
) : Fragment() {
var dataBinding: B? = null
private var isPageLoaded = false
abstract fun onViewCreated()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (!isPageLoaded) {
onViewCreated()
isPageLoaded = true
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
if (dataBinding == null) {
performDataBinding(inflater, container)
}
return dataBinding?.root
}
private fun performDataBinding(
inflater: LayoutInflater,
container: ViewGroup?,
) {
dataBinding = DataBindingUtil.inflate(
inflater, viewID, container, false
)
dataBinding?.let {
it.lifecycleOwner = this
}
}
}
and use this class in your fragment like this :
class HomeFragment : BaseFragment<FragmentHomeBinding>(R.layout.fragment_home) {
...
}