The Android 4.1 ActionBar provides a useful navigation mode as a list or tab. I am using a SpinnerAdapter to select from three fragments to be displayed in view android.R.id.content.
The onNavigationItemSelected() listener then inflates each fragment to the view and adds it to the back stack using FragmentTransaction.addToBackStack(null).
This all works as advertised, but I don't know how to update the ActionBar to reflect the current back stack. Using the ActionBar.setSelectedNavigationItem(position) works but also triggers a new OnNavigationListener() which also creates another FragmentTransaction (not the effect I want). The code is shown below for clarification. Any help with a solution is appreciated.
public class CalcActivity extends Activity {
private String[] mTag = {"calc", "timer", "usage"};
private ActionBar actionBar;
/** An array of strings to populate dropdown list */
String[] actions = new String[] {
"Calculator",
"Timer",
"Usage"
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
// may not have room for Title in actionbar
actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
actionBar.setListNavigationCallbacks(
// Specify a SpinnerAdapter to populate the dropdown list.
new ArrayAdapter<String>(
actionBar.getThemedContext(),
android.R.layout.simple_list_item_1,
android.R.id.text1,
actions),
// Provide a listener to be called when an item is selected.
new NavigationListener()
);
}
public class NavigationListener implements ActionBar.OnNavigationListener {
private Fragment mFragment;
private int firstTime = 0;
public boolean onNavigationItemSelected(int itemPos, long itemId) {
mFragment = getFragmentManager().findFragmentByTag(mTag[itemPos]);
if (mFragment == null) {
switch (itemPos) {
case 0:
mFragment = new CalcFragment();
break;
case 1:
mFragment = new TimerFragment();
break;
case 2:
mFragment = new UsageFragment();
break;
default:
return false;
}
mFragment.setRetainInstance(true);
}
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (firstTime == 0) {
firstTime++;
ft.add(android.R.id.content, mFragment, mTag[itemPos]);
} else {
ft.replace(android.R.id.content, mFragment, mTag[itemPos]);
ft.addToBackStack(null);
}
ft.commit();
Toast.makeText(getBaseContext(), "You selected : " +
actions[itemPos], Toast.LENGTH_SHORT).show();
return true;
}
}
public static class CalcFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_calc, container, false);
return v;
}
}
public static class TimerFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_timer, container, false);
return v;
}
}
public static class UsageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_usage, container, false);
return v;
}
}
You could do something like this:
Create a boolean to track when you are selecting a navigation item based on the back button:
private boolean mListIsNavigatingBack = false;
Override onBackPressed, in the override, check if the backstack has items, if so handle yourself, if not call the superclass:
public void onBackPressed() {
if(getFragmentManager().getBackStackEntryCount() > 0){
mListIsNavigatingBack = true;
//You need to get the previous index in the backstack through some means
//possibly by storing it in a stack
int previousNavigationItem = ???;
getActionBar().setSelectedNavigationItem(previousNavigationItem);
}
else{
super.onBackPressed();
}
}
Inside NavigationListener, handle the mListIsNavigatingBack state, manually pop the back stack and unset the state:
if(mListIsNavigatingBack){
if(fm.getBackStackEntryCount() > 0){
fm.popBackStack();
}
mListIsNavigatingBack = false;
}
Related
So let me try to explain this: I have a Bottom navigation view with three buttons, each one when pressed will load a fragment. However, when pressing the back button, i have programmed the back stack to go back to the fragment it was previously. However, the colour of the navigation button does not change after the back button is changed. I know this has something to do with the state checked thing but i do not know how to implement it on my codes. Here are the codes
This is the menu page, it sets the bottomnavigation view only in which the main_frame is where the fragments are going to be:
public class menuPage extends AppCompatActivity {
BottomNavigationView mainNav;
FrameLayout mainFrame;
private MoviesFragment moviesFragment;
private HomeFragment homeFragment;
private ProfileFragment profileFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu_page);
mainFrame= (FrameLayout) findViewById(R.id.main_frame);
mainNav = (BottomNavigationView) findViewById(R.id.main_nav);
moviesFragment= new MoviesFragment ();
homeFragment = new HomeFragment();
profileFragment = new ProfileFragment ();
removeFragment(homeFragment);
mainNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_movies :
setFragment(moviesFragment);
return true;
case R.id.nav_home :
setFragment(homeFragment);
return true;
case R.id.nav_profile:
setFragment(profileFragment);
return true;
default:
return false;
}
}
});
}
private void setFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_frame, fragment);
fragmentTransaction.addToBackStack("detail");
fragmentTransaction.commit();
}
private void removeFragment(Fragment fragment){
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.main_frame, fragment);
fragmentTransaction.disallowAddToBackStack();
fragmentTransaction.commit();
}
}
Here is the codes for the Home Fragment, Movies Fragment and Profile Fragment respectively. You can ignore the codes written inside cos i know it correctly goes to another activity when launched and that has nothing to do with this issue
Home Fragment
public class HomeFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_agenda, container, false);
return view;
}
}
Movies Fragment
public class MoviesFragment extends Fragment {
ListView listofmovies;
ArrayList<String> genres;
ArrayAdapter<String> listview;
NowShowing nowShowing;
ComingSoon comingsoon;
#Override//inflate this
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_movies, container, false);
listofmovies = (ListView) view.findViewById(R.id.movielist);
genres = new ArrayList<String>();
listview = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_activated_1, genres);
listofmovies.setAdapter(listview);
//The types of options
genres.add("Now Showing");
genres.add("Coming Soon");
genres.add("July");
genres.add("June");
nowShowing = new NowShowing();
comingsoon = new ComingSoon();
listofmovies.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 0) {
Intent nextPage = new Intent(view.getContext(), NowShowing.class);
startActivityForResult(nextPage,0);
}
if (position == 1){
Intent nextPage = new Intent(view.getContext(),ComingSoon.class);
startActivityForResult(nextPage,1);
}
}
});
return view;
}
}
Profile Fragment
public class ProfileFragment extends Fragment {
ListView management;
ArrayList<String> mis;
ArrayAdapter<String> Adapter;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile,container, false );
management= (ListView) view.findViewById(R.id.management);
mis= new ArrayList<String>();
Adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_activated_1, mis);
management.setAdapter(Adapter);
//add management settings
mis.add("Settings");
mis.add("Favourites");
mis.add("Log Out");
userprofilefragment userprofilefragment = new userprofilefragment();
FragmentManager manager = getFragmentManager();
manager.beginTransaction()
.replace(R.id.profilelayout, userprofilefragment, userprofilefragment.getTag())
.commit();
return view;
}
Help is much appreciated. The context is that I'm just making a simple movie app for school assignment and i am still kinda beginner at Java..
Thanks
I have implemented Navigation drawer given in the Android Studio 1.5.1.
I have 5 navigation drawer items with a fragment to each of them. Each Fragment has Share method (Not common).
Inside 1st Navigation drawer item's fragment lets say OldStory Fragment, I am having Swipe view with Viewpager consisting 3 fragments with FragmentStatePagerAdapter. It has Share method.
Problem
- Share Method from Story Fragment is getting called every time even when other fragment is shown on screen. After debugging I came to know that method from Story fragment is getting called.
- If I disable OldStory Fragment then everything works fine.
I am unable to solve this problem. I read so many Question/answers but they are related to Activity and Fragment methods. Please help me to solve this problem.
Note - OldStory fragment has inner class that extends FragmentStatePagerAdapter class. This class creates Many Story Fragments. Other implementation is same.
public class OldStory extends Fragment {
private StoryPagerAdapter storyPagerAdapter;
private InfiniteViewPager viewPager;
SharedPreferences sharedPreferences;
private int TotalCount;
public OldStory() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Notify the system to allow an options menu for this fragment.
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View rootView = inflater.inflate(R.layout.fragment_old_story, container, false);
viewPager = (InfiniteViewPager) rootView.findViewById(R.id.pager);
viewPager.setOffscreenPageLimit(0);
sharedPreferences = getActivity().getSharedPreferences(Startup.PreferenceSETTINGS, Context.MODE_PRIVATE);
TotalCount = sharedPreferences.getInt(Startup.StoryCount, 4);
storyPagerAdapter = new StoryPagerAdapter(getFragmentManager());
PagerAdapter wrappedAdapter = new InfinitePagerAdapter(storyPagerAdapter);
viewPager.setAdapter(wrappedAdapter);
viewPager.setCurrentItem(TotalCount-1);
return rootView;
}
public class StoryPagerAdapter extends FragmentStatePagerAdapter {
public StoryPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return Story.newInstance(position+1);
}
#Override
public int getCount() {
return TotalCount;
}
}
}
Story Fragment method Implementation -
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.story, menu);
getActivity().getMenuInflater().inflate(R.menu.main, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.Refresh:
// We make sure that the SwipeRefreshLayout is displaying it's refreshing indicator
if(!visiblity) {
if (!RefreshLayout.isRefreshing()) {
ErrorLayout.setVisibility(View.GONE);
RefreshLayout.setRefreshing(true);
}
// Start our refresh background task
initiateRequest(Today);
}
return true;
case R.id.Share:
//InShort = sharedPreferences.getString(Startup.InShort, null);
Toast.makeText(getContext(), "Stories", Toast.LENGTH_SHORT).show();
if (InShort!= null && !InShort.isEmpty())
{
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "Hi From Story");
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
MainActivity used for switching fragments.
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
displayView(item.getItemId());
return true;
}
//method to replace Views in ID = content_frame in content_main
public void displayView(int viewID)
{
fragment = null;
title = getString(R.string.app_name);
switch (viewID)
{
case R.id.nav_frag0:
fragment = new OldStory();
title = getString(R.string.story);
viewIsAtHome = true;
break;
case R.id.nav_frag1:
fragment = new Fragment1();
title = getString(R.string.fragment1);
viewIsAtHome = false;
break;
case R.id.nav_frag2:
fragment = new Fragment2();
title = getString(R.string.fragment2);
viewIsAtHome = false;
break;
case R.id.nav_frag3:
fragment = new Fragment3();
title = getString(R.string.fragment3);
viewIsAtHome = false;
break;
case R.id.nav_frag4:
fragment = new Fragment4();
viewIsAtHome = false;
title = getString(R.string.fragment4);
break;
case R.id.nav_share:
fragment = new Fragment5();
title = getString(R.string.fragment5);
viewIsAtHome = false;
break;
}
if (fragment != null)
{
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame,fragment);
ft.commit();
}
//set the toolbar title
if(getSupportActionBar() != null)
{
getSupportActionBar().setTitle(title);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
I am not sure if it is really the answer to your question, but I noticed one error in your code:
storyPagerAdapter = new StoryPagerAdapter(getFragmentManager());
will not work correctly becasuse you need to use getChildFragmentManager() to manage fragments within fragments.
I was trying to reproduce your issue and wrote this app, which as I understood from the question is copying your app's behaviour:
I've uploaded the source code for it into my Dropbox - feel free to check it out
As you can see, the fragments handle Share button clicks properly.
There's always a chance, that I didn't fully understand your question, but here's how I've done it:
All fragments inflating this menu (but with different onOptionsItemSelected):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/nav_share"
android:icon="#drawable/ic_menu_share"
app:showAsAction="always"
android:title="Share" />
</menu>
My SubFragment class (the one I'm using inside ViewPager) in FragmentA:
public class SubFragment extends Fragment {
String msg;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.subfragmnet, container, false);
setHasOptionsMenu(true);
rootView.findViewById(R.id.subfragmentFrameLayout).setBackgroundColor(getArguments().getInt("background"));
msg = getArguments().getString("msg");
return rootView;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_fragment, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.nav_share) {
Snackbar.make(getView(), "Hello from SubFragment " + msg, Snackbar.LENGTH_LONG).show();
}
return super.onOptionsItemSelected(item);
}
}
FragmentA, the first Fragment, which hosts ViewPager and nested Fragments:
public class FragmentA extends Fragment {
PagerAdapter pagerAdapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_a, container, false);
Bundle bundle1 = new Bundle();
bundle1.putInt("background", Color.RED);
bundle1.putString("msg", "page 1");
Bundle bundle2 = new Bundle();
bundle2.putInt("background", Color.YELLOW);
bundle2.putString("msg", "page 2");
Bundle bundle3 = new Bundle();
bundle3.putInt("background", Color.BLUE);
bundle3.putString("msg", "page 3");
Fragment[] fragments = {
Fragment.instantiate(getContext(), SubFragment.class.getName(), bundle1),
Fragment.instantiate(getContext(), SubFragment.class.getName(), bundle2),
Fragment.instantiate(getContext(), SubFragment.class.getName(), bundle3),
};
if (pagerAdapter == null) {
pagerAdapter = new PagerAdapter(getChildFragmentManager(), fragments);
}
ViewPager viewPager = (ViewPager)rootView.findViewById(R.id.viewPager);
viewPager.setAdapter(pagerAdapter);
return rootView;
}
}
FragmentB (and pretty much the same FragmentC):
public class FragmentB extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_b, container, false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_fragment, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.nav_share) {
Toast.makeText(getContext(), "Hello from Fragment B", Toast.LENGTH_LONG).show();
}
return super.onOptionsItemSelected(item);
}
}
Hosting Activity is standard NavigationDrawer Activity with is switching Fragments on Drawer's item click.
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
....
getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentA.class.getName())).commit();
}
...
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_camera) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentA.class.getName())).commit();
} else if (id == R.id.nav_gallery) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentB.class.getName())).commit();
} else if (id == R.id.nav_slideshow) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentC.class.getName())).commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
Let me know, if I understood your question properly!
Anyway, I hope, it helps.
Having a look at this thread, I have a fundamental question.
1) Imagine I have a multi-pane layout like this one:
2) Now lets imagine that the underlying xml is like this one (for simplicity's sake most attributes are missed):
somefragment_land.xml:
<LinearLayout orientation="horizontal" ...>
<!--our side menu-->
<ListView id="#+id/menu" />
<!--our details fragment container-->
<FrameLayout id="#+id/container"/>
</LinearLayout>
3) Ok, so we have this SomeFragment class:
public class SomeFragment extends Fragment {
public static final String TAG = "TAGTAGTAG";
private static final String STATE_SELECTED_POSITION = "selected_position";
private int currentSelectedPosition;
private ListView mMenu;
private MyAdapter mAdapter;
private boolean isMultipaneMode;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isMultipaneMode = getResources().getBoolean(R.bool.show_fragment_multiplane);
if (savedInstanceState != null) {
currentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION, 0);
} else if (isMultipaneMode) {
currentSelectedPosition = 0;
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int resId = isMultipaneMode ? R.layout.fragment_somefragment_land : R.layout.fragment_somefragment;
View root = inflater.inflate(resId, container, false);
mMenu = (ListView) root.findViewById(R.id.menu);
mMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SomeItem item = mAdapter.getItem(position);
showDetails(item);
}
});
///do some stuff creating adapter
mMenu.setAdapter(mAdapter);
if (isMultipaneMode) {
showDetails(mAdapter.getItem(currentSelectedPosition));
}
return root;
}
#Override
public void onDestroyView() {
//remove details fragment
destroyDetails();
super.onDestroyView();
}
private void destroyDetails() {
if (isMultipaneMode) {
//schedule a transaction to remove a fragment
//it will happen after SomeFragment is removed
FragmentManager fm = getFragmentManager();
Fragment fragmentByTag = fm.findFragmentByTag(FragmentDetails.TAG);
if (fragmentByTag == null) {
L.e(this.getClass(), "Details fragment removed");
return;
}
fm.beginTransaction()
.remove(fragmentByTag)
.commit();
}
}
private void showDetails(SomeItem item) {
if (isMultipaneMode) {
FragmentDetails details = new FragmentDetails();
Bundle args = new Bundle();
args.putString(FragmentDetails.ARG_ID, item.getId());
details.setArguments(args);
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment, details, FragmentDetails.TAG)
.commit()
;
} else {
ActivityDetail.launch(getActivity(), item.getTitle(), item.getType());
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (isMultipaneMode) {
outState.putInt(STATE_SELECTED_POSITION, currentSelectedPosition);
}
}
}
So the logic is straightforward, show details in Fragment (for multipane mode) or start Details activity if we are running on a smartphone etc
What I want to know is - how much wrong is this approach in terms of Fragment management?
I imagine myself the following case:
SomeFragment is added to FragmentManager
user decides to go elsewhere
Transaction_1 is started to remove SomeFragment
this calls to onDestroyView() which schedules a transaction to
remove DetailsFragment
Transaction_1 is complete, however, DetailsFragment is not yet
removed. It possibly holds some part of SomeFragment view hierarchy
in memory
Transaction_2 is started to remove DetailsFragment
Transaction_2 is complete, DetailsFragment is destroyed
???
These question marks stand for some uncertainty - have I created a memory leak? Or something worse? Any off-top-of-your-head consequences of using this approach?
I have 2 fragments (tabs) that share some data. When one changes the data, I'd like to have that reflected on the other tab. I researched this on stackOverflow and I think the relevant answer has to do with a .notifyDataSetChanged() call, but I can't make it work. Here's the relevant code...
public class EnterCourseData extends FragmentActivity implements ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Pars", "Handicaps" };
private int courseNumber, teeNumber;
private Tee tee;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter_tees);
// Initilization
Intent mIntent = getIntent();
courseNumber = mIntent.getIntExtra("courseNumber",0);
Course course = Global.getCourse(courseNumber);
teeNumber = mIntent.getIntExtra("teeNumber",0);
tee = course.getTee(teeNumber);
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager(), courseNumber, teeNumber);
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
and further down, here is the onClick method that necessitates the refresh...
public void savePars(View view){
tee.setSlope(Integer.parseInt(((EditText) findViewById(R.id.enter_tee_slope)).getText().toString()));
tee.setRating(Double.parseDouble(((EditText) findViewById(R.id.enter_tee_rating)).getText().toString()));
mAdapter.notifyDataSetChanged();
}
Here is the TabsPagerAdapter...
public class TabsPagerAdapter extends FragmentPagerAdapter {
int courseNumber, teeNumber;
public TabsPagerAdapter(FragmentManager fm, int courseNumber, int teeNumber) {
super(fm);
this.courseNumber = courseNumber;
this.teeNumber = teeNumber;
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
// Par Entry activity
Fragment parFragment = new ParFragment();
Bundle args = new Bundle();
args.putInt(ParFragment.ARG_COURSE_NUMBER, courseNumber);
args.putInt(ParFragment.ARG_TEE_NUMBER, teeNumber);
parFragment.setArguments(args);
return parFragment;
case 1:
// Handicap Entry fragment activity
Fragment hcpFragment = new HandicapFragment();
args = new Bundle();
args.putInt(HandicapFragment.ARG_COURSE_NUMBER, courseNumber);
args.putInt(HandicapFragment.ARG_TEE_NUMBER, teeNumber);
hcpFragment.setArguments(args);
return hcpFragment;
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 2;
}
}
Here is one Fragment...
public class ParFragment extends Fragment {
public static final String ARG_COURSE_NUMBER = "courseNumber", ARG_TEE_NUMBER = "teeNumber";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_par, container, false);
Bundle args = getArguments();
Course course = Global.getCourse(args.getInt(ARG_COURSE_NUMBER));
((TextView) rootView.findViewById(R.id.display_course_name)).setText(course.getName());
Tee tee = course.getTee(args.getInt(ARG_TEE_NUMBER));
((TextView) rootView.findViewById(R.id.display_tee_name)).setText(tee.getTeeName());
((TextView) rootView.findViewById(R.id.enter_tee_slope)).setText(Integer.toString(tee.getSlope()));
((TextView) rootView.findViewById(R.id.enter_tee_rating)).setText(Double.toString(tee.getRating()));
return rootView;
}
}
And here is the other...
public class HandicapFragment extends Fragment {
public static final String ARG_COURSE_NUMBER = "courseNumber", ARG_TEE_NUMBER = "teeNumber";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_handicap, container, false);
Bundle args = getArguments();
Course course = Global.getCourse(args.getInt(ARG_COURSE_NUMBER));
((TextView) rootView.findViewById(R.id.display_course_name)).setText(course.getName());
Tee tee = course.getTee(args.getInt(ARG_TEE_NUMBER));
((TextView) rootView.findViewById(R.id.display_tee_name)).setText(tee.getTeeName());
((TextView) rootView.findViewById(R.id.enter_tee_slope)).setText(Integer.toString(tee.getSlope()));
((TextView) rootView.findViewById(R.id.enter_tee_rating)).setText(Double.toString(tee.getRating()));
return rootView;
}
}
When the button is clicked, I want to save the values and I want these values to show up on the other fragment.
Help a noob out.
Thanks
You need to communicate between fragments, but a fragment cannot directly communicate with other fragment, all the communication should be done through the activity which holds these fragments.
The steps to follow are :
Define an Interface in the fragment where you have implemented the onClickListener (let it be Fragment A)
Implement the Interface in the activity which holds these fragments
In the method overridden, retrieve the fragment instance from the viewpager adapter and deliver a message to Fragment B by calling it's public methods.
refer this answer to retrieve fragment instance from adapter
For more details about Communicating with Other Fragments, refer here
So there is a trick: just let the fragments have the object reference of one another and call the other's function to load data when you handle the onClickListener of the button.
E.g:
protected void onClickListener(View view) {
if (view == myButton) {
// Do other stuffs here
fragment1.reloadData();
}
}
P/S : I re-post this as answer to have the code formatter.
I'm new to Android programming.
I have a list of items, when the user clicks on an item it takes them to a screen with that item details.
I want the user to have the ability to swipe right and left to view other items' details in the list, instead of going back to the list and choosing another item.
I read that I need to use ViewPager for the ability to swipe right and left, so I did that.
ViewPager works fine, but my problem when I click any item on the list I always get to the first page in the ViewPager.
I don't want that, what I want is if I click on item 4 on the list it takes me to page 4 in the view pager and still have the ability to swipe right and left to view the details of other items.
I know how to set the page in viewpager by using mPager.setCurrentItem(0)
But I don't know how to set it according to which item was selected from the list (i.e which item launched the activity).
Here is my code:
Main activity which contains the listview:
public class Main extends SherlockListActivity implements OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView mylist = (ListView) findViewById(android.R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.simple_list_reda_1, R.id.list_content, getResources().getStringArray(R.array.items_list_array) );
mylist.setAdapter(adapter);
mylist.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> arg0,View arg1, int position, long arg3)
{
Intent n = null;
switch (position){
case 0:
n = new Intent(getApplicationContext(), ViewPagerClass.class);
break;
case 1:
n = new Intent(getApplicationContext(), ViewPagerClass.class);
break;
case 2:
n = new Intent(getApplicationContext(), ViewPagerClass.class);
break;
case 3:
n = new Intent(getApplicationContext(), ViewPagerClass.class);
break;
}
if(null!=n)
startActivity(n);
}
});
}
}
ViewPagerClass
public class ViewPagerClass extends SherlockFragmentActivity{
static final int NUM_ITEMS = 4;
MyAdapter mAdapter;
ViewPager mPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.viewpager_layout);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.viewpager);
mPager.setAdapter(mAdapter);
//mPager.setCurrentItem(2);
final ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayUseLogoEnabled(false);
ab.setDisplayShowHomeEnabled(false);
}
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
switch(position){
case 0: return FirstPageFragment.newInstance();
case 1: return SecondPageFragment.newInstance();
case 2: return ThirdPageFragment.newInstance();
case 3: return FourthPageFragment.newInstance();
}
return null;
}
}
public static class FirstPageFragment extends Fragment {
public static FirstPageFragment newInstance() {
FirstPageFragment f = new FirstPageFragment();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View V = inflater.inflate(R.layout.fragment1, container, false);
return V;
}
}
public static class SecondPageFragment extends Fragment {
public static SecondPageFragment newInstance() {
SecondPageFragment f = new SecondPageFragment();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View V = inflater.inflate(R.layout.fragment2, container, false);
return V;
}
}
public static class ThirdPageFragment extends Fragment {
public static ThirdPageFragment newInstance() {
ThirdPageFragment f = new ThirdPageFragment();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View V = inflater.inflate(R.layout.fragment3, container, false);
return V;
}
}
public static class FourthPageFragment extends Fragment {
public static ThirdPageFragment newInstance() {
ThirdPageFragment f = new ThirdPageFragment();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View V = inflater.inflate(R.layout.fragment4, container, false);
return V;
}
}
Finally viewpager_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<android.support.v4.view.ViewPager
android:id="#+android:id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
So in short What I want is:
If I click on item 3 in the list I go to screen with the details on item 3, and if I swipe to the right I get to item 4, and if I swipe to the left I get to item 2.
In the onItemClickListener() you need to add an extra to the intent so you can get it when that activity launches.
n.putExtra("POSITION_KEY", position);
In the ViewPagerClass onCreate() using the
int position = getIntent().getIntExtra("POSITION_KEY", 0);
mPager.setCurrentItem(position);
That should do what you are wanting to do.