I have 4+ Fragments (android.support.v4.app.Fragment).
Fragment f1, f2, f3, f4;
int F1 = 1; int F2 = 2; int F3 = 3; int F4 = 4;
protected void onCreate(Bundle savedInstanceState)
{
//...
f1 = new Fragment();
f2 = new Fragment();
f3 = new Fragment();
f4 = new Fragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fl_root, f1)
.add(R.id.fl_root, f2)
.add(R.id.fl_root, f3)
.add(R.id.fl_root, f4)
.commit();
setFragment(F1);
}
public void setFragment(int fragment)
{
switch (fragment)
{
case F1:
if (!f1.isVisible()) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.rtol, R.anim.ltor, 0, 0)
.show(f1)
.hide(f2)
.hide(f3)
.hide(f4)
.commit();
}
break;
case F2:
if (!f2.isVisible()) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.rtol, R.anim.ltor, 0, 0)
.show(f2)
.hide(f1)
.hide(f3)
.hide(f4)
.commit();
}
break;
case F3:
if (!f3.isVisible()) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.rtol, R.anim.ltor, 0, 0)
.show(f3)
.hide(f1)
.hide(f2)
.hide(f4)
.commit();
}
break;
case F4:
if (!f1.isVisible()) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.rtol, R.anim.ltor, 0, 0)
.show(f4)
.hide(f1)
.hide(f2)
.hide(f3)
.commit();
}
break;
}
After setFragment to first, second and so on (1->2->3->4) rtol (translate from right to left) animation works, and it's fine.
But after going back, using setFragment (4->3->2->1), there are still rtol animation, instead of correct ltor(translate from left to right).
What I'm doing wrong, and what is the solution?
Actually there are 20+ Fragments in Single Activity in my Project.
I solved this animation problem + OutOfMemory (because of 20+ fragments added and hided).
A little bit code:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (!back)
ft.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left);
else
ft.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right);
switch (fragment)
{
case F1:
ft.replace(R.id.fl_root, new F1(), String.valueOf(F1));
break;
//...
}
Slide Animation here
The setCustomAnimations method takes one anim for entering and one for exiting a fragment so even if you go back, you are entering one of these fragments.
So you have to take a look at the fragment you are coming from and switch the animations.
Edit:
Maybe like this untested
int lastFragment;
public void setFragment(int fragment)
{
FragmentTransaction ft = getSupportFragmentManager.beginTransaction();
if(fragment > lastFragment) {
ft.setCustomAnimations(R.anim.rtol, R.anim.ltor, 0, 0);
} else {
ft.setCustomAnimations(R.anim.ltor, R.anim.rtol, 0, 0);
}
switch (fragment)
{
case F1:
if (!f1.isVisible()) {
ft
.show(f1)
.hide(f2)
.hide(f3)
.hide(f4)
.commit();
}
break;
case F2:
if (!f2.isVisible()) {
ft
.show(f2)
.hide(f1)
.hide(f3)
.hide(f4)
.commit();
}
break;
case F3:
if (!f3.isVisible()) {
ft
.show(f3)
.hide(f1)
.hide(f2)
.hide(f4)
.commit();
}
break;
case F4:
if (!f1.isVisible()) {
ft
.show(f4)
.hide(f1)
.hide(f2)
.hide(f3)
.commit();
}
break;
lastFragment = fragment;
}
Related
I tried many methods to save instances but I am confused how to save instances in backstack because no one described how to use it if there multiple fragments.my code in mainactivity below:
bottomNavigationView.setOnItemSelectedListener(item -> {
switch (item.getItemId()){
case R.id.home:
loadFragment(new HomeFragment(),0);
break;
case R.id.create:
loadFragment(new CreateFragment(),1);
break;
case R.id.profile:
loadFragment(new ProfileFragment(),1);
break;
}
return true;
});
public void loadFragment(Fragment fragment,int flag){
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
if(flag==0){
fragmentTransaction.add(R.id.frame_layout,fragment);
fragmentManager.popBackStack(ROOT_FRAGMENT_TAG,FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentTransaction.addToBackStack(ROOT_FRAGMENT_TAG);
}
else {
fragmentTransaction.replace(R.id.frame_layout,fragment);
fragmentTransaction.addToBackStack(null);
}
fragmentTransaction.commit();
}
I suggest you to make your Fragment Classes Singleton.
private static MyFragment fragment;
public static MyFragment getInstance() {
if (fragment == null) {
fragment = new MyFragment();
}
return fragment;
}
then use getInstance() method to instantiate your fragment
i used this GitHub library in my code for bottom navigation.chip navigation bar
i tried to make it floating up after starting the program.but when run the program it is disappeared but when clicking in the buttons place . on click listener works but i couldn't see the navigation bar
this is the click listener ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btmNav = findViewById(R.id.btmNav);
layout = findViewById(R.id.cntBTM);
animMove = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_up);
btmNav.startAnimation(animMove);
//////////////*
if (savedInstanceState == null) {
NewsFragment newsFragment = new NewsFragment();
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, newsFragment)
.commit();
}
btmNav.setOnItemSelectedListener(new ChipNavigationBar.OnItemSelectedListener() {
#Override
public void onItemSelected(int id) {
Fragment fragment = null;
switch (id) {
case R.id.home:
fragment = new WebFragment();
break;
case R.id.activity:
fragment = new ActivityFragment();
break;
case R.id.settings:
fragment = new SettingFragment();
break;
}
if (fragment != null) {
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, fragment)
.commit();
} else {
Log.e(TAG, "Error in creating fragment");
}
}
});
and this in main activity
<com.ismaeldivita.chipnavigation.ChipNavigationBar
android:id="#+id/btmNav"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_margin="12dp"
android:background="#drawable/rounded"
android:elevation="5dp"
android:outlineAmbientShadowColor="#color/colorAccent"
app:cnb_menuResource="#menu/bottom_menu"
app:cnb_unselectedColor="#fff"
Use this library https://github.com/ismaeldivita/chip-navigation-bar
Dont forget to add maven in settings.graddle
maven { url 'https://jitpack.io' }
And dont forget to add this dependency to your build.graddle file
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0'
add your build.gradle implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.3.72'
I have an issue with onBackPressed() implementation in my app. I have a single fragment with differents tags. The user could navigate between fragments with a Navigation View and the back button. Everything works as expected except when FragmentTransaction goes like this:
Initial Fragment->A->B->C->A
When I use back button to return, the behavior I want to achieve is A->C->B->Initial.
Instead, I get A->B->C->A->Initial
How can I acomplish my desired behavior?
This is what I have so far:
private int backStackEntries = 0;
public void onBackPressed() {
Log.d(TAG,"Number of fragments in back: "+backStackEntries);
NewsListFragment fragment = (NewsListFragment) getSupportFragmentManager().findFragmentByTag(currentFrag);
backStackEntries-=1;
if(backStackEntries<0)
backStackEntries = 0;
if(fragment.getTag().equals(News_TAG[0])){
if(fragment.getParserMaker().isRunning()){
moveTaskToBack(true);
}
else{
finish();
}
}
else{
currentFrag = getSupportFragmentManager().getBackStackEntryAt(backStackEntries).getName();
getSupportFragmentManager().beginTransaction()
.hide(fragment)
.show(getSupportFragmentManager().findFragmentByTag(currentFrag))
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
}
}
private void makeFragmentTransaction(String[] urls, int item,String _TAG) {
Bundle bundle = new Bundle();
bundle.putStringArray("urls", urls);
NewsListFragment newsFragment = (NewsListFragment) getSupportFragmentManager().findFragmentByTag(_TAG);
if(newsFragment == null){
newsFragment = new NewsListFragment();
}
newsFragment.setArguments(bundle);
if(currentFrag == null){
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, newsFragment, _TAG)
.addToBackStack(_TAG)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
currentFrag = _TAG;
}
else if(!newsFragment.isAdded()){
getSupportFragmentManager().beginTransaction()
.hide(getSupportFragmentManager().findFragmentByTag(currentFrag))
.add(R.id.container,newsFragment,_TAG)
.addToBackStack(_TAG)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
currentFrag = _TAG;
backStackEntries+=1;
}
else if(!currentFrag.equals(_TAG)){
getSupportFragmentManager().beginTransaction()
.hide(getSupportFragmentManager().findFragmentByTag(currentFrag))
.show(newsFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
backStackEntries+=1;
currentFrag = _TAG;
}
navigationView.setCheckedItem(item);
drawerLayout.closeDrawers();
}
Adding the last backStackEntries+=1; makes the weird behavior and erasing that line makes the deal BUT it creates another Transaction issue:
Initial(going back)->B->C
Pressing back button: C->Initial
I have also tried making transactions like this:
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, newsFragment, _TAG)
.addToBackStack(_TAG)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
currentFrag = _TAG;
And onBackPressed like this:
NewsListFragment fragment = (NewsListFragment) getSupportFragmentManager().findFragmentByTag(currentFrag);
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
getSupportFragmentManager().popBackStack();
} else {
if (fragment.getParserMaker().isRunning()) {
moveTaskToBack(true);
} else {
finish();
}
}
This also cause the undesired behavior and popBackStack() removes fragment, which I don't want to do.
I also had the same problem, I solved it by implementing my own history stack for the fragments. everytime that I wanted to add a fragment to the stack, I would look through the stack and removed the fragment with the same class as the one I was gonna add (if there was one)
I have use .replace() for replace a old Fragment with a new, but in this moment i do no how use the same of .replace() by a Fragment to a mapsFragment.
Ideas?!
I can use replace? if i can' t use it, what I can use?
This is my code in this moment. (the .replace() don' t work)
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
mapsFragment fragM = null;
Fragment frag = null;
switch (position) {
case 0: //Home
mTitle = "Maps";
fragM = new mapsFragment();
break;
case 1: //Query utente
mTitle = "Section 2";
break;
case 2: //Query Amministratore
mTitle = "Section 3";
break;
}
if (position != 3) {
if(position==0){
fragmentManager.beginTransaction()
.replace(R.id.container, fragM)
.commit();
}else {
fragmentManager.beginTransaction()
.replace(R.id.container, frag)
.commit();
}
I have find the solution:link where i have found it
This is the code in particular:
if(position==0){
FragmentTransaction mTransaction = getSupportFragmentManager()
.beginTransaction();
SupportMapFragment mFRaFragment = new mapsFragment();
mTransaction.replace(R.id.container, mFRaFragment);
mTransaction.commit();
}else {
I currently have a MainActivity.java which should be the only activity class. Though in that activity class I have a nav-drawer which links to other fragment views.
Currently the main issue Im facing is implementing tabs under a fragment and making them just be available for only that fragment and subfragments. I ran my application and the tabs appeared, but they also appear on other fragments after I visit the TeamsAndDriversFragment.
In my MainActivity.java I have the following function which helps point to the fragments it will generate once someone clicks on them in the nav-drawer:
/**
* Diplaying fragment view for selected nav drawer list item
* */
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new TimeAndScoringFragment();
break;
case 1:
fragment = new ScheduleFragment();
break;
case 2:
fragment = new StandingsFragment();
break;
case 3:
fragment = new TeamsAndDriversFragment();
break;
case 4:
fragment = new NewsFragment();
break;
default:
break;
}
if (fragment != null) {
// Create a fragment transaction object to be able to switch fragments
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Here is my current TeamsAndDriversFragment class where I have an actionbar navigation with tabs:
public class TeamsAndDriversFragment extends Fragment implements TabListener {
private List<Fragment> fragList = new ArrayList<Fragment>();
#Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
ActionBar bar = getActivity().getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
Tab mTeamsTab = bar.newTab();
mTeamsTab.setText("Teams");
mTeamsTab.setTabListener(this);
bar.addTab(mTeamsTab);
Tab mDriversTab = bar.newTab();
mDriversTab.setText("Drivers");
mDriversTab.setTabListener(this);
bar.addTab(mDriversTab);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Fragment f = null;
TabFragment tf = null;
if(fragList.size() > tab.getPosition()) {
fragList.get(tab.getPosition());
}
if(f == null) {
tf = new TabFragment();
Bundle data = new Bundle();
data.putInt("idx", tab.getPosition());
tf.setArguments(data);
fragList.add(tf);
} else {
tf = (TabFragment) f;
}
ft.replace(android.R.id.content, tf);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if(fragList.size() > tab.getPosition()) {
ft.remove(fragList.get(tab.getPosition()));
}
}
}
In the displayView() method simply remove all tabs from the ActionBar, this way you'll always have a clean ActionBar with the exception of the TeamsAndDriversFragment fragment:
private void displayView(int position) {
getSupportActionBar().removeAllTabs();
// ...
}