How can I add back to previous page on webview fragments? - java

I have an android app created with android studio that has a main activity and fragments with webview. Each fragment contains webview code with a link to a website. The problem that I have is that when I press back it closes the app. I want to use back to go to the previous page and the previous activity.
Main Activity code:
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.nav_facebook:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new FacebookFragment()).commit();
break;
case R.id.nav_twitter:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new TwitterFragment()).commit();
break;
case R.id.nav_instagram:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new InstagramFragment()).commit();
break;
case R.id.nav_linkedin:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new LinkedinFragment()).commit();
break;
case R.id.nav_snapchat:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new SnapchatFragment()).commit();
break;
case R.id.nav_pinterest:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new PinterestFragment()).commit();
break;
case R.id.nav_youtube:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new YoutubeFragment()).commit();
break;
case R.id.nav_about:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new AboutFragment()).commit();
break;
case R.id.nav_privacy:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new PrivacyFragment()).commit();
break;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
Here is the code of one of the fragment's code (the rest of the fragments has similar code):
public class FacebookFragment extends Fragment {
public FacebookFragment() {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_facebook, container, false);
WebView webView = (WebView)v.findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("https://www.facebook.com/");
return v;
}
}

After replacing the fragment just make sure to add it to back stack using:
replace(R.id.fragment_container,
new YoutubeFragment()).addToBackStack("tag").commit()
and override the onBackPressed function to pop up stack while it's not empty.

All these fragments have same function is go back fragment. Why don't add the base fragment for them and the code will be easier.

Related

Swipe between fragments with help of BottomNavigationBar

I have trouble finding a good example on how to swipe between fragments with help of bottom navigatiom bar. Since FragmentStatePagerAdapter is deprecated and a new ViewPager2 is now recommended instead of the old ViewPager I want to use ViewPager2 and FragmentStateAdapter in my code instead. I have found an example of how to combine BottomNavigationBar and ViewPager here and I want to do something similar. My code have many similarities to the one in the example with the only difference that I have my code in a fragment instead of an activity. Here is a picture of how my FrontendFragment display look like. I can switch between the views using the bottomnavigationbar but I also want to be able to swipe between the views. Can someone help me or at least direct me on the right way? Here is my code:
FragmentPagerAdapter Class:
public class FragmentPagerAdapter extends FragmentStateAdapter {
private static final int mFragmentCount = 5;
public FragmentPagerAdapter(#NonNull Fragment fragment) {
super(fragment);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position){
case 0:
return new HomeFragment();
case 1:
return new SearchFragment();
case 2:
return new AddFragment();
case 3:
return new MessageFragment();
case 4:
return new ProfileFragment();
}
return null;
}
#Override
public int getItemCount() {
return mFragmentCount;
}
}
FrontendFragment Class:
public class FrontendFragment extends Fragment implements BottomNavigationView.OnNavigationItemSelectedListener{
private BottomNavigationView mBottomNavigationView;
private ViewPager2 mViewPager2;
private FragmentPagerAdapter mFragmentPagerAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_frontend, container, false);
loadFragment(new HomeFragment());
mBottomNavigationView = v.findViewById(R.id.bottomNavigationBar);
mBottomNavigationView.setOnNavigationItemSelectedListener(this);
return v;
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.home_icon:
selectedFragment = new HomeFragment();
break;
case R.id.search_icon:
selectedFragment = new SearchFragment();
break;
case R.id.add_icon:
selectedFragment = new AddFragment();
break;
case R.id.message_icon:
selectedFragment = new MessageFragment();
break;
case R.id.profile_icon:
selectedFragment = new ProfileFragment();
break;
}
return loadFragment(selectedFragment);
}
private boolean loadFragment(Fragment selectedFragment) {
if(selectedFragment != null){
MainActivity.sFm.beginTransaction().replace(R.id.relLayoutMiddle, selectedFragment).commit();
return true;
}
return false;
}
}
Thanks in advance!
As I'm already using BottomNav with ViewPager2 in one of my app, I can help.
Your code is partially correct which means your FragmentPagerAdapter is fine, but not your FrontEndFragment.
See, the FragmentPagerAdapter has to be set to a ViewPager2 as
//this here is the FrontEndFragment
mViewPager2.setAdapter(new FragmentPagerAdapter(this));
Then, You don't have to do the FragmentTransaction at all, you just have to change the ViewPager2's current item position through the BottomNavigationBar as
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.home_icon:
mViewPager2.setCurrentItem(0);
break;
case R.id.search_icon:
mViewPager2.setCurrentItem(1);
break;
case R.id.add_icon:
mViewPager2.setCurrentItem(2);
break;
case R.id.message_icon:
mViewPager2.setCurrentItem(3);
break;
case R.id.profile_icon:
mViewPager2.setCurrentItem(4);
break;
}
return false;
}
This is all, you don't have to deal with Fragments at all apart from the FragmentPagerAdapter. Also, don't forget to remove the loadFragment(new HomeFragment()); which is not required, nor the function loadFragment() is required.
(Optional), Furthermore, if you want to disable the Swipe Action of the ViewPager2 and want the Fragments to be selected based on the Selected BottomNav item only, then you can set setUserInputEnabled() property of ViewPager2 as false.
Next, to set the BottomNavigationBar's item as selected based on the swipe of the ViewPager2, what you've to do is,
Create a global var
MenuItem previousMenuItem;
Then, set a default item (first) to be selected of BottomNav on activity start as
mBottomNavigationView.getMenu().getItem(0).setChecked(true);
Finally, set an OnPageSelected() callback on ViewPager2 to update the selected Menu Item as:
mViewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
if (previousMenuItem != null) {
previousMenuItem.setChecked(false);
}
else {
mBottomNavigationView.getMenu().getItem(0).setChecked(false);
}
mBottomNavigationView.getMenu().getItem(position).setChecked(true);
previousMenuItem = mBottomNavigationView.getMenu().getItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
What you're doing here is that you're setting default item to previousMenuItem and then on swiping to a different page, deselecting the previousMenuItem and selecting the new one, which means updating the BottomNav based on ViewPager's current item. This is the complete code you require to acheive your objective.
If you want to swipe between views, a simple solution would be to store all views in your parent view, but set all layouts for views except the initial view to android:visibility="gone". Make sure to set the initial view layout to android:visibility="visible" though. Now on you button clicks, you will have to implement onClick such that they turn on/ off view visibilities accordingly. For example, store views in order and control them via array index. But the whole thing you're trying to do is generally not a good design pattern in my opinion.
Why don't you load another Activity onClick instead of crowding your single activity? This will cause load time issues. Even if the views are non-visible, it's just an overall hassle to maintain all that in one place.

How to get last Fragment used when pressing back button

I have a simple fragment with this code:
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment selectedFragment= null;
switch (menuItem.getItemId()){
case R.id.nav_home:
selectedFragment= new HomeFragment();
setTitle("Beranda");
break;
case R.id.nav_message:
selectedFragment= new MessageFragment();
setTitle("Pesan");
break;
case R.id.nav_transaction:
selectedFragment= new TransactionFragment();
setTitle("Transaksi");
break;
case R.id.nav_profile:
selectedFragment= new ProfileFragment();
setTitle("Profil");
if(sessionLevel.equals("admin")){
setTitle("Admin");
}
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
Most of the fragment are just some kind of holder for Intent Activity. And the Activity itself doesnt have some fancy code.
The problem is that when i do Intent on Profile menu and then press back, the fragment shown is HomeActivity but the selected button is Profile.
I dont know about the other 2 fragment since im not there yet, but probably they do the same thing.
You can do this like the following:
#Override
public void onBackPressed() {
super.onBackPressed();
Fragment frag = YourActivity.this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if(frag!=null && frag instanceof yourFragment)
{}
}
The following will give you count
int count = getSupportFragmentManager().getBackStackEntryCount();
You can make condition, If count is great than 1 then have more than 1 fragments else you have atleast 1 fragment and that will be last fragment. If count 0 then no more fragment available on stack as all have been poped out of stack.
Create an interface:
public interface IOnBackPressed {
boolean onBackPressed();
}
In Fragment implement IOnBackPressed like:
public class FAQFragment extends Fragment implements IOnBackPressed {
public boolean onBackPressed() {
return false
}
}
On Main Activity Backpress use
#Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}
}

nullPointerException between fragment and main activity, android/android-studio [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I want to make a communication between my fragment and main activity so I need to get switch.isCheked but get:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.app.Activity.findViewById(int)' on a null object reference
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new NotesFragment()).commit();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
final NotesFragment notesFragment = new NotesFragment();
final RemindersFragment remindersFragment = new RemindersFragment();
final SettingsFragment settingsFragment = new SettingsFragment();
final Switch aSwitch = settingsFragment.getView().findViewById(R.id.switch_pop_up);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment selectedFragment = null;
switch (menuItem.getItemId()) {
case R.id.action_notes:
if(aSwitch.isChecked())
Toast.makeText(MainActivity.this, "Your Notes", Toast.LENGTH_SHORT).show();
selectedFragment = notesFragment;
break;
case R.id.action_reminders:
if(aSwitch.isChecked())
Toast.makeText(MainActivity.this, "Your Reminders", Toast.LENGTH_SHORT).show();
selectedFragment = remindersFragment;
break;
case R.id.action_settings:
if(aSwitch.isChecked())
Toast.makeText(MainActivity.this, "Settings", Toast.LENGTH_SHORT).show();
selectedFragment = settingsFragment;
break;
}
assert selectedFragment != null;
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit();
return true;
}
});
}
}
SettingsFragment.java
public class SettingsFragment extends Fragment {
Switch switch_pop_up;
boolean stateSwitchPopUp;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_settings, null);
switch_pop_up = v.findViewById(R.id.switch_pop_up);
return inflater.inflate(R.layout.fragment_settings,container,false);
}
}
I think it is because of :
final Switch aSwitch = settingsFragment.getView().findViewById(R.id.switch_pop_up);
How can I fix this?
The problems are:
you are not attaching your SettingsFragment to activity to make it visible on screen (like you do with your NotesFragment)
you're trying to access it's child views from your MainActivity's onCreate method.
Fragments get initialized after activity is being created and ready to host them. Therefore, settingsFragment.getView() is returning null. It's onCreateView lifecycle method has not being called yet.
You need to reconsider your approach and try to find other solution. I suggest you to read this threads in SO to get more ideas on how to solve your problem.
How to access Fragment's child views inside fragment's parent Activity?
Access Fragment View from Activity's onCreate
Android: how to notify Activity when Fragments views are ready?
On your fragment, in the onCreateView method, change this line:
View v = inflater.inflate(R.layout.fragment_settings, null);
into:
View v = inflater.inflate(R.layout.fragment_settings, container, false);
Edit 1:
This happens because you're doing v.findViewById(), but you're not returning v on onCreateView().
Change your return line in the fragment to return v;
Edit 2:
Add a getter on the fragment to the switch_pop_up:
public Switch getSwitchPopUp() {
return switch_pop_up;
}
On your activity, replace this line:
final Switch aSwitch = settingsFragment.getView().findViewById(R.id.switch_pop_up);
with:
final Switch aSwitch = settingsFragment.getSwitchPopUp();
And you'll have to inflate your SettingsFragment before this line.
Note: Whichever result you need, this is not a good aproach anyway, so you might want to look into other ways to do it.

Fragment Transaction shows Tabs Fragment below

I'm making an app that has launches with a Swiping Tabs Fragment, but I also want to have a Preferences menu using Fragment Transaction. When I press the Settings button in my app, the preferences menu does appear and is interactive, but the layout seems to be transparent showing the Tabs below. Is there anything that can be done to fix this, or is there a better method?
Code that calls the Preferences Menu from the Options:
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getFragmentManager().popBackStackImmediate();
break;
case R.id.logout:
FirebaseAuth.getInstance().signOut();
finish();
startActivity(new Intent(this, Activity_Main.class));
break;
case R.id.action_settings:
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new Fragment_Settings()).addToBackStack(null)
.commit();
break;
}
return true;
}
Code that calls Tabs Fragments:
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int index) {
switch (index) {
case 0:
// Top Rated fragment activity
return new Fragment_Flower();
case 1:
// Games fragment activity
return new Fragment_Overview();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 2;
}
}
Initialising Transaction in onCreate:
startService(new Intent(this, SensorListener.class));
if (b == null) {
// Create new fragment and transaction
Fragment newFragment = new Fragment();
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(android.R.id.content, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
Any help will be greatly appreciated!
Just set background color in your layout file. It may avoid transparent backgound.

How can I add the activity in Android Sliding Menu which is fragment

http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/
hi all, I have succeeded apply this Android Sliding Menu in my project.
however, how can i add some activity in diffferent page?
In MainActivity, displayView function controls the fragment which i have selected.you can see it only use in "Fragment fragment = null;",so , the CESDemo class is extends Fragment.But i cannot add my activity in the CESDemo, such as onTouch and so on.If i change it to FragmentActivity, it does not allow me for "ragmentManager.beginTransaction().replace(R.id.frame_container,fragment).commit();"
So, how can i apply some activity in different fragment,even i can design the layout but no any activity i can create.
MainActivity.java
private void displayView(int position) {
// update the main content by replacing fragments
//Fragment fragment = null;
Fragment fragment =null;
switch (position) {
case 0:
fragment = new CESHome();
break;
case 1:
fragment = new CESAll();
break;
case 2:
fragment = new CESPending();
break;
case 3:
fragment = new CESInProgress();
break;
case 4:
fragment = new CESCompleted();
break;
case 5:
fragment = new CESDemo();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).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");
}
}
CESDemo.java
public class CESDemo extends Fragment {
public CESDemo(){}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_cesdemo, container, false);
return rootView;
}

Categories