I'm trying to get an activity to launch when a specific tab is selected but when I return from that activity, I want the previous to show instead of the tab I clicked. Just like when you click the plus button on Instagram.
Like this:
Default Fragment 1/Tab 1
Go to Fragment 5/Tab 5
Click tab 3, activity pops up
Go back, see Fragment 5/Tab 5
Right now, I'm storing the last visited tab index in a variable, then when Tab 3 is clicked, it just goes to the last visited tab.
tabLayout.setOnTabSelectedListener(
new TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
#Override
public void onTabSelected(TabLayout.Tab tab) {
//super.onTabSelected(tab); -- Should keep this or leave it commented out?
int pos = tab.getPosition();
switch (pos) {
case 0:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Home");
pre_pos = pos;
pre_title = "Home";
break;
case 1:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Trending");
pre_pos = pos;
pre_title = "Trending";
break;
case 2:
viewPager.setCurrentItem(pre_pos, false);
getSupportActionBar().setTitle(pre_title);
Intent intent = new Intent(MainActivity.this, NewEvent_Activity.class);
startActivity(intent);
Toast.makeText(getApplicationContext(),
"Curr: "+ viewPager.getCurrentItem()+
" Prev: " + pre_pos +
" Clicked: " +tab.getPosition(),
Toast.LENGTH_SHORT).show();
break;
case 3:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Notifications");
pre_pos = pos;
pre_title = "Notifications";
break;
case 4:
viewPager.setCurrentItem(tab.getPosition(), false);
getSupportActionBar().setTitle("Profile");
pre_pos = pos;
pre_title = "Profile";
break;
}
}
});
In ViwPager.java it calls this function when setCurrentItem() is called
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (mAdapter == null || mAdapter.getCount() <= 0) {
setScrollingCacheEnabled(false);
return;
}
//I think my problem lies in the following line (mCurItem == item)
if (!always && mCurItem == item && mItems.size() != 0) {
setScrollingCacheEnabled(false);
return;
}
if (item < 0) {
item = 0;
} else if (item >= mAdapter.getCount()) {
item = mAdapter.getCount() - 1;
}
final int pageLimit = mOffscreenPageLimit;
if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
// We are doing a jump by more than one page. To avoid
// glitches, we want to keep all current pages in the view
// until the scroll ends.
for (int i = 0; i < mItems.size(); i++) {
mItems.get(i).scrolling = true;
}
}
final boolean dispatchSelected = mCurItem != item;
if (mFirstLayout) {
// We don't have any idea how big we are yet and shouldn't have any pages either.
// Just set things up and let the pending layout handle things.
mCurItem = item;
if (dispatchSelected) {
dispatchOnPageSelected(item);
}
requestLayout();
} else {
populate(item);
scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}
}
I think this is where my problem is but I can't edit it.
Any suggestions?
Thanks.
implement ViewPager.OnPageChangeListener on activity. set listner on viewpager
view_pager.setOnPageChangeListener(this);
in OnPageSelected() method:
#Override
public void onPageSelected(int position) {
if (position == 3) {
startActivity(new Intent(this,activity.class));
}
}
override activity onResume method and write:
#Override
public void onResume() {
super.onResume();
view_pager.setCurrentItem(0);
}
To do this You have to follow these Simple Steps
Step : 1 Override below method in all ViewPager Frgment
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
}
this method will be called when your fragment become visible.
step : 2 Put a condition in Fragmenr3 to start new Activity when your Fragment become visible
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
if(menuVisible){
Intent intent = new Intent(MainActivity.this, NewEvent_Activity.class);
startActivity(intent);
}
}
Now it will open you activity in front. but your one requirement remaining which is, if user press back from activity, you have to show second Last fragment, so as you have mention you are storing index position of Last fragment so follow below step .
Step : 3 Override onRestart() in Your ViewPager Actvity
#Override
protected void onRestart() {
super.onRestart();
view_pager.setCurrentItem(Stored last Index);
}
it will solve your problem, its working for me.
Related
I know there are similar questions to the one I'm asking but none of them was able to solve the issue I'm having.
I Have a bottom navigation view with five fragments that use viewpager, one of these fragments opens an activity.
Problem
When I open the activity from the fragment it works fine but the issue is the when I press back it goes back to the same fragment that opens the activity.
Solution
I want when I press back out of the activity that it goes to a previous fragment apart from the fragment that calls the activity.
For example: if the user is on HomeFragment and the user clicks the fragment that opens the activity(NewsFragment), and the user press back they Should go back to HomeFragment, not NewsFragment.
What I tried so far:
MainActivity for the BottomnNvigationView and it's On Back Press
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_library:
viewPager.setCurrentItem(0);
temp = temp.replace("-0", "") + "-0";
break;
case R.id.nav_technology:
viewPager.setCurrentItem(1);
temp = temp.replace("-1", "") + "-1";
break;
case R.id.nav_home:
viewPager.setCurrentItem(2);
temp = temp.replace("-2", "") + "-2";
break;
case R.id.nav_science:
viewPager.setCurrentItem(3);
temp = temp.replace("-3", "") + "-3";
break;
case R.id.nav_news:
viewPager.setCurrentItem(4);
temp = temp.replace("-4", "") + "-4";
Intent intent = new Intent(MainActivity.this,BrowserActivity.class);
startActivity(intent);
return true;
}
return true;
}
};
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else {
String[] words = temp.split("-");
if(words.length<=2)
if (viewPager.getCurrentItem() != 2) {
temp = "";
viewPager.setCurrentItem(2);
}else
finish();
else {
temp = temp.replace("-" + words[words.length - 1], "");
int pos = viewPager.getCurrentItem();
if (viewPager.getCurrentItem() == pos)
pos = 2;
else
pos = 1;
viewPager.setCurrentItem(Integer.parseInt(words[words.length - pos]));
}
}
}
The Activity that is call from the fragment (BrowersActivity) On Back Press
#Override
public void onBackPressed() {
if (viewPager.getCurrentItem() != 0) {
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1,false);
}else{
finish();
}
}
Any help would be appreciated.
Quickest solution would be to finish the first activity after starting the second one so:
case R.id.nav_news:
viewPager.setCurrentItem(4);
temp = temp.replace("-4", "") + "-4";
Intent intent = new Intent(MainActivity.this,BrowserActivity.class);
startActivity(intent);
finish()
return true;
And in the second activity in onBackPressed, restart the first activity
#Override
public void onBackPressed() {
super.onBackPressed()
startActivity(new Intent(this, FirstActivity.class))
}
I have one activity. This activity has a view pager. This viewpager has five pages and these pages open a fragment in their contents. The problem occurs, for example, when I open two fragments in the first page and then open one fragment in a second page. I go back to first page. I click back button in toolbar. And I use popBackStack() code to remove fragment which is visible currently.
But it removes all backstacks. How can I solve this?
getSupportFragmentManager().popBackStack(str,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
My algorithm :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if(getSupportFragmentManager() != null){
int count = getSupportFragmentManager().getBackStackEntryCount();
Log.i("Fragment Stack Count : ", count+"");
if (count <= 0) {
super.onBackPressed();
} else {
checkBackStack();
}
}
}
private void checkBackStack(){
Log.i("BackStack", "Home Activity Count > 0");
FragmentManager fm= getSupportFragmentManager();
if(fm.getBackStackEntryCount() > 0){
Log.i("BackStack", "Count > 0");
for(int i = (fm.getBackStackEntryCount()-1) ; i >= 0 ; i--){
FragmentManager.BackStackEntry backStackEntry = fm.getBackStackEntryAt(i);
String str= backStackEntry.getName();
Log.i("BackStack", " Name : "+str);
BaseMenuFragment fragment= (BaseMenuFragment) fm.findFragmentByTag(str);
if(((ViewGroup) fragment.getView())!= null && ((ViewGroup) fragment.getView().getParent()) != null){
int contentId = ((ViewGroup) fragment.getView().getParent()).getId() ;
if(contentId == frames[viewPager.getCurrentItem()]){
Log.i("BackStack", "equals = true");
getSupportFragmentManager().popBackStack(str, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return;
}
}
}
}
}
I think this can help you. I've faced this some time ago and I found a solution.
This is not a library, it is a demo app. I'm sorry if the structure is
Eclipse-like. It's been a while I did this.
I have an "activity A" that launches two fragments, with the home button being part of the activity A, and when the back button is pressed from the createFragment it should go back to the activity before activity A, which it does fine with the finish() method but when I have the second fragment, followersFragment which is added ontop of createFragment and hides createFragment (because I do not want the information being lost in the create), then I hit the back button and it switches back to the create fragment but then when I hit the back button from createFragment it does not go back to activity A anymore and does nothing... no error...
This is my code on the activity that holds the fragments(not activity A):
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
switch (item.getItemId()) {
// lets user travel back to where they came from
case android.R.id.home:
if(displayShown == 1) {
displayView(2, 0);
} else {
}
return true;
private void displayView(int i, int position) {
Log.d(Constants.DEBUG, "display view called " +position);
boolean createPost = true;
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
//avoid recreating createPostFragment if already created because all data will be erased
if(createPostFragment == null){
createPost = false;
Log.d(Constants.DEBUG, "fragment create DOES NOT EXIST ");
createPostFragment = new CreatePostFragment();
}
fragment = createPostFragment;
break;
case 1:
followerFragment = new FollowerFragment();
fragment = followerFragment;
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
trans = fragmentManager.beginTransaction();
//if createpostfrag already created just show
if (createPost && position == 0) {
trans.remove(followerFragment);
trans.show(createPostFragment);
trans.commit();
//hide createpostfrag so we can reuse
} else {
if(position == 1) {
Bundle extraData = new Bundle();
extraData.putInt("follow", i);
fragment.setArguments(extraData);
trans.add(R.id.frame_container, fragment, null).commit();
trans.hide(createPostFragment);
}
if(position == 0) {
trans.add(R.id.frame_container, fragment, "keepAlive").commit();
}
}
} else {
// error in creating fragment
Log.d(Constants.DEBUG, "Error in creating fragment or no fragment needed");
}
}
I have an activity with 2 fragments. Fragment A has TextViews used as search fields. Fragment B shows the results based on the search.
I have button in my actionbar to clear the search fields. This button is for the activity and can be clicked from both fragments.
This is the code for the action button:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//Delete
if (id == R.id.action_delete) {
if (fragmentA != null) {
getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentA.clearAll();
}
}
return super.onOptionsItemSelected(item);
}
With the above code, I return back to the first fragment (it's not added to the backstack). However the textviews are not cleared.
The clearAll method is called correctly because I'm also clearing properties of a custom object. However, the text in the textviews stay there. I have to click the button a second time (when fragment A is displayed) so that the text is cleared.
This is the method:
public void clearAll() {
searchClass.name = "";
searchClass.surname = "";
tvName.setText(null);
tvSurname.setText(null);
}
I'm setting null and not "" so that the hints should be displayed again.
What am I missing? Could it be that the fragment is is not shown so its view is still not available?
You can try this
tvName.setText("");
tvSurname.setText("");
Instead of this
tvName.setText(null);
tvSurname.setText(null);
You can try this-
public void clearAll() {
searchClass.name = "";
searchClass.surname = "";
tvName.setText("");
tvSurname.setText("");
}
To get it to work the following changes were done:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//Delete
if (id == R.id.action_delete) {
if (fragmentA != null) {
getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (currentFragment == fragmentA ) {
fragmentA.clearAllImmediate();
}
else {
fragmentA.clearAll();
}
}
}
return super.onOptionsItemSelected(item);
}
And then in the fragment itself:
#Override
public void onResume() {
super.onResume();
if (needToClear) {
clearAllImmediate();
needToClear = false;
}
}
public void clearAll() {
needToClear = true;
}
public void clearAllImmediate() {
searchClass.name = "";
searchClass.surname = "";
tvName.setText(null);
tvSurname.setText(null);
}
I'm creating ViewPager with three viewsin it. On the first view is a ListView, where onItemClick replaces that fragment new fragment with WebView in it. And I have two problems: when adding 'transaction.addToBackStack(null)', or 'transaction.setCustomAnimations(...)' Fragment with WebView stopps to show. Without these lines it shows, but I can't do BACK button to return to list.
I was creating code based on that tutorial and this SO question. In that question there is used PagerAdapter, and I'm using FragmentPagerAdapter. Also I don't need more fragments to be replaced. It can be only once (from list to webView and back).
Here is my adapter's code:
public Fragment getItem( int position )
{
Fragment fragment = null;
switch ( position )
{
case 0: // news
if ( mFragmentAtPos0 == null )
{
mFragmentAtPos0 = new NewsListFragment( new FirstPageFragmentListener()
{
#Override
public void onSwitchToNewsFragment( String url, ViewGroup container )
{
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations( R.anim.rotate_in, R.anim.rotate_out, R.anim.rotate_in, R.anim.rotate_out );
WebViewFragment wv = new WebViewFragment( url, context );
transaction.replace( container.getId(), wv );
transaction.commit();
mFragmentAtPos0 = wv;
notifyDataSetChanged();
}
} );
}
fragment = mFragmentAtPos0;
break;
case 1:
fragment = new NewsInfoFragment( context, true );
break;
case 2:
fragment = new NewsInfoFragment( context, false );
break;
}
return fragment;
}
and snippet from onCreateView() of that List's fragment:
listView.setOnItemClickListener( new OnItemClickListener()
{
#Override
public void onItemClick( AdapterView<?> parent, View view, int position, long id )
{
if ( position < listNewsAdapter.getCount() - 1 )
{
if ( listener != null )
{
listener.onSwitchToNewsFragment( listNewsAdapter.getItem( position ).getNewsUrl(), container );
}
}
}
} );
Check out my new answer to mentioned question: https://stackoverflow.com/a/11974777/685292
You can see there an example how to implement simple back stacking with ViewPager by your own since addToBackStack(null) does not work for ViewPager fragments. Also note that main problem about your issue is probably the missing getItemId(int position) overriden method.
In new design support library, i use this solution
You can use stack to store the tabpositon by pushing the position in stack and getting back by using pop in stack.
In the main activity where there are 3 fragment in viewpager i create stack
and push and pop data.
private Stack<Integer> stackkk;
private ViewPager mPager;
private int tabPosition = 0;
mTabLayout.setupWithViewPager(mPager);
mPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
tabPosition = tab.getPosition();
mPager.setCurrentItem(tab.getPosition());
if (stackkk.empty())
stackkk.push(0);
if (stackkk.contains(tabPosition)) {
stackkk.remove(stackkk.indexOf(tabPosition));
stackkk.push(tabPosition);
} else {
stackkk.push(tabPosition);
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
tabPositionUnselected = tab.getPosition();
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
and in the onBackPressed in activity,
#Override
public void onBackPressed() {
if (stackkk.size() > 1) {
stackkk.pop();
mPager.setCurrentItem(stackkk.lastElement());
} else {
//do wat you want
}
}
Hope this may help