I am creating tabs in my app using info from
epidemian answer
I created main class which handles tabs, this class extends TabActivity and creates tabs:
Resources res = getResources();
TabHost tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
intent = new Intent().setClass(this, stackA.class);
spec = tabHost.newTabSpec("tab1").setIndicator("Tab 1",
res.getDrawable(android.R.drawable.ic_menu_search))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, stackB.class);
spec = tabHost.newTabSpec("tab2").setIndicator("Tab 2",
res.getDrawable(android.R.drawable.ic_menu_search))
.setContent(intent);
tabHost.addTab(spec);
tabHost.setCurrentTab(0);
Then for every tab is created FragmentActivity and this gives possibility to create stack in every tab. My fragments is created:
protected void navigateTo(Fragment newFragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, newFragment);
ft.addToBackStack(null);
ft.commit();
}
public class fragmentA extends Fragment{
private LinearLayout ll;
private FragmentActivity fa;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fa = super.getActivity();
ll = (LinearLayout) inflater.inflate(R.layout.fragmenta, container, false);
Button next = (Button) ll.findViewById(R.id.button1);
next.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
((ActivityInTab) getActivity()).navigateTo(new fragmentB());
}
});
return ll;
}
}
This is working. What is wrong that when i am at tab 1 and fragment B (first fragment in stack is A), rotate my device and then it go back at fragment A.
epidemian said something about orientations and using setArguments/getArguments, but i am new to android programming so i don't really know how to do that:
Finally, if you need to survive orientation changes, it's important
that your fragments are created using setArguments/getArguments. If
you set instance variables in your fragments' constructors you'll be
screwed. But fortunately that's really easy to fix: just save
everything in setArguments in the constructor and then retrieve those
things with getArguments in onCreate to use them.
int x;
Bundle args = new Bundle();
args.putString("variable", x);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment = Fragment.instantiate(getActivity(), MyFragment.class.getName(), args);
ft.replace(R.id.layout1, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
than in the fragment:
getArguments().getInt("variable");
You can use Fragment.setRetainInstance(true) for this. See this related question.
You can prevent the Activity from beeing destroyed due to orientation change. Add the following line to your manifest of your TabActivity (orientation change + keyboard visibility changes)
android:configChanges="keyboardHidden|orientation"
See here for description.
setArguments/getArguments does not help you here. As he stated you may use it to save instance variables and retrieving them after orientation change. But with the given line above you do not need that because your Activity/Fragments won't get destroyed
Related
I'm trying to continue the flow of app within bottomsheet.
Case : When a user clicks any brand suppose "Levis" then it should display the brand products i.e. another fragment(containing Products data) within the same bottomsheet only.
Problem: the another fragment(containing Products data) is opening in a seperate frame not in the existing bottomsheet.
My code on adapter holder click event:
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String id = ld.getBrand_id();
Bundle bundle = new Bundle();
bundle.putString("somekeyvalue", String.valueOf(id));
Fragment fragment = new ProductFragment();
fragment.setArguments(bundle);
FragmentManager fragmentManager = ((FragmentActivity) ct).getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
I'm using Google material bottomsheet.
code to start bottomsheet:
BrandFragment bottomSheet = new BrandFragment();
bottomSheet.show(getChildFragmentManager(),
"ModalBottomSheet");
you are loading new ProductFragment() into R.id.frameLayout, which probably belongs to Activity. if you want to open new Fragment inside another one then define container, which belongs to this first Fragment. also use then getChildFragmentManager, not getSupportFragmentManager
btw. ensure that R.id.frameLayout is unique and declared ONLY inside "parent" Fragment, not in Activity
I tried to phrase the title as I can, but Basically inside the HomeActivity I have a custom menu with a bunch for fragments.! One of the them is HomeFragment which contains a Tablelayout of 2 tabs with a viewpager..!
Everything is working correctly.! but inside the menu fragment, when the user clicks the back button on the toolbar is to return to the HomeFragment.
A fragment replacement method will do the trick which I already used it to replace between the fragments when choosing from the menu !?
But in this case, the HomeFragment opens yet the Tablayout isn't responsive! it feels like the the fragment isn't created correctly!?
I tried using a new intent of the same activity which opens HomeFragment by default, and it opens it but with the same problem..!
The Problem
The Code
HomeFragment
// code..
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
InitViews(rootView);
TabLayoutAdapter adapter = new TabLayoutAdapter(getFragmentManager());
pager.setAdapter(adapter);
tabLayout.setupWithViewPager(pager);
return rootView;
}
// code..
Menu Fragment
// code..
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.to_home:
replaceFragment(new HomeFragment());
// tried this and it's the same problem
// startActivity(new Intent(getActivity(), HomeActivity.class).setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void replaceFragment(Fragment fragment) {
android.support.v4.app.FragmentTransaction t = getFragmentManager().beginTransaction();
t.replace(R.id.Container, fragment);
t.commit();
}
// code..
Looking at the code I think you have to use getChildFragmentManager() instead of getFragmentManager() and use it for fragment Transaction.
The definition of getChildFragmentManager() is:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
And the definition of getFragmentManager() is:
Return the FragmentManager for interacting with fragments associated with this fragment's activity.
Replace this line of code having getFragmentManager() by getChildFragmentManager()
TabLayoutAdapter adapter = new TabLayoutAdapter(getChildFragmentManager());
Also in the menu Fragment
android.support.v4.app.FragmentTransaction t = getChildFragmentManager().beginTransaction();
I am trying to call a function from my mainActivity to change a TextView in one of my fragments. I have read a couple posts on the best way of doing it but for some reason, none of them seem to work for me. I know the function is working because once a press the button the toast comes up but for some reason the text won't change. I was wondering what the issue could be, or if I am just missing an additional step.
here is the method being called in my mainActivity
public class MainActivity extends AppCompatActivity implements Tab1Fragment.OnCalcClickListener{
private static final String TAG = "MainActivity";
private SectionsPageAdapter mSectionsPageAdpater;
private ViewPager mViewPager;
Tab1Fragment tab1Fragment = new Tab1Fragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: Starting");
//initializing FragmentManager so the fragments can communicate
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, tab1Fragment);
fragmentTransaction.commit();
//declare sections page adapter
mSectionsPageAdpater = new SectionsPageAdapter(getSupportFragmentManager());
//Set up the view pager with the sections adapter
mViewPager = (ViewPager) findViewById(R.id.container);
setUpViewPager(mViewPager);
//create a tab layout object and set it's id to tabs (mainActivity.xml)
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
//
}
// create a sections page view adapter
private void setUpViewPager(ViewPager viewPager){
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), "Day");
adapter.addFragment(new Tab2Fragment(), "Info");
adapter.addFragment(new Tab3Fragment(), "Week");
viewPager.setAdapter(adapter);
}
//initialise calculator object
Calculator mainCalculator = new Calculator();
#Override
public void calculateClick(int to_calculate) {
switch (to_calculate){
case 1:
Toast.makeText(getBaseContext(),"working", Toast.LENGTH_SHORT).show();
mainCalculator.freqDay = mainCalculator.freqDay + 1;
mainCalculator.freqWeek = mainCalculator.freqWeek + 1;
mainCalculator.getTotalDay();
tab1Fragment.updateInfo();
break;
}
}
Here is the code for my fragment
public class Tab1Fragment extends Fragment implements
View.OnClickListener{
private static final String TAG = "Tab1Fragment";
//Establishing the buttons & Methods
Button btn1;
Button btn2;
TextView dayView;
OnCalcClickListener onCalcClickListener;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab1_fragment, container, false);
//Connecting the buttons to the xml
btn1 = (Button) view.findViewById(R.id.btn_1);
btn1.setOnClickListener(this);
btn2 = (Button) view.findViewById(R.id.btn_2);
btn2.setOnClickListener(this);
dayView = (TextView) view.findViewById(R.id.total_Sales_Day);
return view;
}
//Onclick listener for buttons
public void setOnClickListener(View.OnClickListener listener) {
btn1.setOnClickListener(listener);
btn2.setOnClickListener(listener);
}
//method that will bring data back from activity and set the text
public void updateInfo(){
Toast.makeText(getContext(),"65", Toast.LENGTH_SHORT).show();
dayView.setText("test");
}
To make calls to methods from your fragment in the activity class you need something like this:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Here the activity is calling the updateArticleView method from the fragment, instead of your updateInfo method, but you will get the idea.
Also pay attention to the one-pane scenario, where you need to swap the content and push the arguments using a Bundle object.
See Deliver a Message to a Fragment for more details.
When you add the fragment set a tag to it like this:
MyFragment frag = new MyFragment();
frag.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, frag, "TAG").commit();
While updating the textview get the instance of fragment using findFragmentByTag()
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("TAG");
fragment.updateInfo();
I want to remove a fragment and show a toast when I click a textView. My code shows the toast, but doesn't remove the fragment.
My method:
public void hide(View view) {
My_frag myFrag= new My_frag();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.remove(myFrag);
transaction.commit();
Toast.makeText(getApplicationContext(), "Hello", Toast.LENGTH_LONG)
.show();
}
My_frag class:
public class My_frag extends android.support.v4.app.Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.my_frag_layout, container, false);
}
}
At some point you must create and add the Fragment correct? You are re-creating the fragment in your hide(...) method so you are trying to remove something that has never been added. Sure you may have added an instance, but not the instance you are trying to remove.
Instead, create a global variable Fragment fragToRemove in your Activity. When you create the fragment (that is where ever you do transaction.add(fragToRemove = new My_Frag);) you will hold an instance. then change your transaction.remove(myFrag) to transaction.remove(fragToRemove) and it should work just fine.
Take the instance of Fragment Transaction other than that was taken while adding fragment to activity and call remove method on that and pass the same instance of Fragment which was used at the time.
Example:
public class MainActivity extends AppCompatActivity {
FragmentTransaction fragmentTransaction;
BlankFragment blankFragment;
Button b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.activity_button);
fragmentTransaction = getSupportFragmentManager().beginTransaction();
blankFragment=new BlankFragment(); //Fragment instance
fragmentTransaction.add(R.id.main_layout,blankFragment).commit();
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.remove(blankFragment).commit(); //created different
}
});
}
In the same way you can do in fragments also and can also remove fragment X on the click of component of fragment X.
I have a fragment inside a group activity and I want to replace it with another fragment:
FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
SectionDescriptionFragment bdf = new SectionDescriptionFragment();
ft.replace(R.id.book_description_fragment, bdf);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
It works fine when it is done as a seperate project without using activity group, every thing works fine in log cat as control goes inside getview(), but no view is visible, not even any exception arises, I want the book detail fragment to be replaced by section detail fragment.
Xml of book detail fragment has id book_description_fragment and xml for section description fragment has id section_description_fragment.
The above code is in onClick method of an item, I want that when user taps on an item in horizontal scroll view, then the fragment changes.
Fragments that are hard coded in XML, cannot be replaced. If you need to replace a fragment with another, you should have added them dynamically, first of all.
Note: R.id.fragment_container is a layout or container of your choice in the activity you are bringing the fragment to.
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Please see this Question
You can only replace a "dynamically added fragment".
So, if you want to add a dynamic fragment, see this example.
I've made a gist with THE perfect method to manage fragment replacement and lifecycle.
It only replace the current fragment by a new one, if it's not the same and if it's not in backstack (in this case it will pop it).
It contain several option as if you want the fragment to be saved in backstack.
=> See Gist here
Using this and a single Activity, you may want to add this to your activity:
#Override
public void onBackPressed() {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
return;
}
super.onBackPressed();
}
Use the below code in android.support.v4
FragmentTransaction ft1 = getFragmentManager().beginTransaction();
WebViewFragment w1 = new WebViewFragment();
w1.init(linkData.getLink());
ft1.addToBackStack(linkData.getName());
ft1.replace(R.id.listFragment, w1);
ft1.commit();
Use ViewPager. It's work for me.
final ViewPager viewPager = (ViewPager) getActivity().findViewById(R.id.vp_pager);
button = (Button)result.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewPager.setCurrentItem(1);
}
});
hope you are doing well.when I started work with Android Fragments then I was also having the same problem then I read about
1- How to switch fragment with other.
2- How to add fragment if Fragment container does not have any fragment.
then after some R&D, I created a function which helps me in many Projects till now and I am still using this simple function.
public void switchFragment(BaseFragment baseFragment) {
try {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
if (getSupportFragmentManager().findFragmentById(R.id.home_frame) == null) {
ft.add(R.id.home_frame, baseFragment);
} else {
ft.replace(R.id.home_frame, baseFragment);
}
ft.addToBackStack(null);
ft.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
enjoy your code time :)
you can use simple code its work for transaction
Fragment newFragment = new MainCategoryFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame_NavButtom, newFragment);
ft.commit();
You Can Use This code
((AppCompatActivity) getActivity()).getSupportFragmentManager().beginTransaction().replace(R.id.YourFrameLayout, new YourFragment()).commit();
or You Can This Use Code
YourFragment fragments=(YourFragment) getSupportFragmentManager().findFragmentById(R.id.FrameLayout);
if (fragments==null) {
getSupportFragmentManager().beginTransaction().replace(R.id.FrameLayout, new Fragment_News()).commit();
}
I change fragment dynamically in single line code
It is work in any SDK version and androidx
I use navigation as BottomNavigationView
BottomNavigationView btn_nav;
FragmentFirst fragmentFirst;
FragmentSecond fragmentSecond;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
fragmentFirst = new FragmentFirst();
fragmentSecond = new FragmentSecond ();
changeFragment(fragmentFirst); // at first time load the fragmentFirst
btn_nav = findViewById(R.id.bottomNav);
btn_nav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch(menuItem.getItemId()){
case R.id.menu_first_frag:
changeFragment(fragmentFirst); // change fragmentFirst
break;
case R.id.menu_second_frag:
changeFragment(fragmentSecond); // change fragmentSecond
break;
default:
Toast.makeText(SearchActivity.this, "Click on wrong bottom SORRY!", Toast.LENGTH_SHORT).show();
}
return true;
}
});
}
public void changeFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout_changer, fragment).commit();
}
In kotlin you can do:
// instantiate the new fragment
val fragment: Fragment = ExampleFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.book_description_fragment, fragment)
transaction.addToBackStack("transaction_name")
// Commit the transaction
transaction.commit()
This will work if you're trying to change the fragment from another fragment.
Objects.requireNonNull(getActivity()).getSupportFragmentManager()
.beginTransaction()
.replace(R.id.home_fragment_container,new NewFragment())
NOTE As stated in the above answers, You need to have dynamic fragments.
You can use fragment-ktx
// If you are in fragmet
childFragmentManager.beginTransaction()
// or if you are in activiry
supportFragmentManager.beginTransaction()
// Create and commit a new transaction
supportFragmentManager.commit {
setReorderingAllowed(true)
// Replace whatever is in the fragment_container view with this fragment
replace<ExampleFragment>(R.id.fragment_container)
}
To replace a fragment with another one do this, Note that R.id.fragment comes from the id that you give to the first tag of the fragment in the XML.
barAudioPlaying.setOnClickListener(view -> {
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment,new HomeFragment())
.commit();