I am using I am using view pager and fragments in my project,
I am trying to set title of Actionbar from fragment class.
My following code showing title of next fragment on current visible fragment.
can you have any ideas how to show current visible fragments title in Action Bar
public class MyFragment extends Fragment {
TextView textView;
int mCurrentPage;
String name = null, data = null;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** Getting the arguments to the Bundle object */
Bundle data = getArguments();
/** Getting integer data of the key current_page from the bundle */
mCurrentPage = data.getInt("current_page", 0);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
setData();
View view = inflater.inflate(R.layout.fragment_Item, container, false);
textView = (TextView) view.findViewById(R.id.fragmentItemTextView);
textView.setText(data);
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(name);
//this sets title of actionbar
//but it set name of next item's name in actionbar
return view;
}
void setData() {
//here I call database to get name of item and data of item
ItemProcess sp = new ItemProcess(getActivity().getApplicationContext());
ArrayList temp;
temp = sp.getSingleItem(mCurrentPage);
name = temp.get(0).getmItemName();
data = temp.get(0).getmItemData();
}
}
but it set name of next item's name in actionbar.
By default, ViewPager Adapter will create the current and the next fragment view for you, refer to:
Book "Android.Programming.The.Big.Nerd.Ranch.Guide" P207
Life cycle methods:
// when first in page0
D/Adapter (25946): getItem(0)
D/Adapter (25946): getItem(1)
D/Fragment1(25946): newInstance(Hello World, I'm li2.)
D/Fragment0(25946): onAttach()
D/Fragment0(25946): onCreate()
D/Fragment0(25946): onCreateView()
D/Fragment1(25946): onAttach()
D/Fragment1(25946): onCreate()
D/Fragment1(25946): onCreateView() // that's why it set name of next item.
So it would be better to update ActionBar title in Activity:
// init title
mViewPager.setCurrentItem(i);
// update title
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int pos) {
setTitle(...);
}
});
it is because viewpager loads onCreateView method of next fragment after calling it on current fragment, and you can't set viewPagerOffset limit to 0.
you can change your action bar title from your fragment by this code :
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
m_iAmVisible = isVisibleToUser;
if (m_iAmVisible) {
Log.d(localTAG, "this fragment is now visible");
//change your actionbartitle
} else {
Log.d(localTAG, "this fragment is now invisible");
}
}
Related
How to load one tab of viewpager at a time ??
I want develop dynamic Tabs with same kind of Fragments.But the problem is ViewPager loads the 2 tab at time and when i change some data in one fragment it will reflects on every fragments.
You can override this method inside of fragment, this will return true if this fragment is in front of screen
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
//You can do inside this method
}
}
}
you can use yourViewPager.setOffScreenPageLimit(value) method. But minimum value of pre-loaded pages is 1, so at least 1 page always will be cached.
To set correct data to page of viewPager you can do something like this:
public class YourFragment extends Fragment{
static final String ARGUMENT_PAGE_NUMBER = "arg_page_number";
int pos;
static YourFragment newInstance(int page) {
YourFragment yourFragment = new YourFragment();
Bundle arguments = new Bundle();
arguments.putInt(ARGUMENT_PAGE_NUMBER, page);
yourFragment.setArguments(arguments);
//save fragment position
return yourFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pos = getArguments().getInt(ARGUMENT_PAGE_NUMBER);
//now you have position of this fragment
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View yourView = inflater.inflate(R.layout.your_fragment_layout, container, false);
//use position of the fragment you received in onCreate to set up your views
return yourView;
}
I'm trying to update a textview in my fragment based on what a user clicks. When I first load the activity it sets the textview. But later, even though the textview.settext does get called, nothing seems to change.
In my activity I send the new variable like this:
getSupportFragmentManager().beginTransaction().add(R.id.pager1, SecondFragment.newInstance(2, "Page # 2", nonStaticRandomInfoSt), "tag").commit();
My Fragment:
public static SecondFragment newInstance(int page, String title, String randomInfo) {
SecondFragment fragmentSecond = new SecondFragment();
Bundle args = new Bundle();
args.putInt("someInt", page);
args.putString("someTitle", title);
args.putString("randomInfo", randomInfo);
fragmentSecond.setArguments(args);
return fragmentSecond;
}
// Store instance variables based on arguments passed
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
randomInfo = this.getArguments().getString("randomInfo");
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_second, container, false);
TextView randomInfoTV = (TextView) view.findViewById(R.id.randomInfo);
randomInfoTV.setText(randomInfo); //this is getting called, but it's not changing the textview
randomInfoTV.setMovementMethod(new ScrollingMovementMethod());
return view;
}
Edit:
I have a fragment in a viewpager. When the activity is first entered, a default value is set to the textview in the fragment. From a listview in my activity layout, the user can make a selection. When an item is selected, I call the fragment manager and pass the new randomInfo variable. I want to update the textview in the fragment. I know the correct value is being passed by debugging, and I know that the textview.settext is being called as well. But for some reason, the textview remains unchanged. Do you have any suggestions as to why this is happening? I don't even know where to start in fixing it.
How I create the fragments:
public static class MyPagerAdapter1 extends FragmentPagerAdapter {
private static int NUM_ITEMS = 2;
public MyPagerAdapter1(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return FirstFragment.newInstance(0, "Page # 1", imageURL);
case 1: // Fragment # 0 - This will show FirstFragment different title
return SecondFragment.newInstance(2, "Page # 2", randomInfoSt);
default:
return null;
}
}
Click event code;
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long id) {
// TODO Auto-generated method stub
if (!fromservice) {
Log.i(TAG, "about to start service");
//starting service code...
initFragmentVars(position); //this runs the fragmentmanager transaction
}
Set the text in public void onViewCreated(final View view, final Bundle savedInstanceState); instead of onCreateView().
The later is ok for what you're doing (findViewById()) but the binding of the data + the view, should be done after the views have been created, especially inside a Fragment.
I know this is confusing, but Android Lifecycle is a mess created by dozens of different software engineers and here we areā¦
I have a viewPager with say 4 pages. All 4 pages uses same Xml. When i do an event in 1st page somehow it always triggers in the last page.
Here is my PagerAdapter
#Override
public Object instantiateItem(ViewGroup container, int pos) {
View desktopView;
OnTouchListener tl = null;
desktopView = act.getLayoutInflater().inflate(
act.getViewPagerLayout(groupName), null);
RelativeLayout rr_appContainer, rr_dialogContainer;
ImageView rr_home_container = (ImageView) desktopView
.findViewById(R.id.imageView_forClick);
Button buttonChange = (Button)desktopView.findViewById(R.id.B1);
Button buttonDelete = (Button)desktopView.findViewById(R.id.B2);
rr_appContainer = (RelativeLayout) desktopView
.findViewById(R.id.rr_home_container);
rr_dialogContainer = (RelativeLayout) desktopView
.findViewById(R.id.rr_dialogView);
..........
buttonDelete.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
deletestuff();
}
buttonChange.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
changeColorOfStuff();
}
.....
return desktopView;
}
What is happening is, When i click on buttonChange from 1st page it supposed to change the color of text on 1st page, but actually it is changing color of the last page. Similarly buttonDelete is deleting color from last page.
Regardless of what page i am in, its reflecting those changes on last page.
Any help would be appreciated.
From the context given here, the deleteStuff() and changeColorOfStuff() can only be members of the Fragment/Activity that owns the adapter, or the adapter itself. So these methods can only act on members of those classes. ViewPager asks the adapter for the fragments it is going to display. However, the text in the fragment being shown by the ViewPager belong to the that fragment. To act on that text, you need a method that's a member of that fragment. The usual way to do this is to use a custom fragment. For example:
Custom Fragment (inner class):
public static class CustomFragment extends Fragment {
//members of the fragment
TextView yourTextView;
...
public static CustomFragment newInstance(int pos) {
CustomFragment fragment = new CustomFragment();
//get whatever info you need for this page
Bundle args = getInfoSomehow(pos);
fragment.setArguments(args)
return fragment;
}
#Override
public View onCreateView(Layout inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(....
yourTextView = root.findViewById(...) //this is the text view you want to change things in
//all the stuff you're currently doing in instantiateItem()
return root;
}
private void deleteStuff() {
//whatever you need to do. But notice that here it's acting on the TextView that belongs to this particular fragment
}
private void changeColorOfStuff() {...}
...
}
Then in your instantiateItem(...)
#Override
public Object instantiateItem(ViewGroup container, int pos) {
return CustomFragment.newInstance(pos);
}
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 was experimenting on Android fragments, hence I created two fragments ListFragment and DetailFragment. The problem is that when I click on the ListFragment and call a DetailFragment method to show the selected item from the ListFragment no result is shown on the DetailFragment. Here is the DetailFragment Code :
private static final String DETAIL_FRAG_TAG = "detail_fragment";
private Context appContext = null;
private TextView lblItemDetail = null;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// inflate the fragment layout
View rootView = inflater.inflate(R.layout.fragments_detail_fragment, container, false);
lblItemDetail = (TextView) rootView.findViewById(R.id.lbl_itemDetail);
//at this point the TextView is not null===>see L0g.i
Log.i(DETAIL_FRAG_TAG, " ---MyDetailFragment---oncreateView()--lblItemDetail =[" + lblItemDetail + "]");
// get the fragment activity context
appContext = this.getActivity();
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
/**
* show the details of the item selected on the listFragment.
* #param itemDetail - the details of the item selected on ListFragment.
*/
public void showLstItemDetail(String itemDetail) {
if (lblItemDetail != null) {
// the View to show Text should not be Null.
lblItemDetail.setText(itemDetail);
}
//at this point calling this method shows
that the `TextView` is Null yet it's
initialized in the
oncreate() as a class member variable ---why am i
getting Null after the `oncreate` is finished.
Log.i(DETAIL_FRAG_TAG, "------showItemDetail---------msg=[" + itemDetail + "] txt=[" + lblItemDetail + "]");
}
//when I create an instance of `MYDetailFragment` and call the method to show the details of item Selected on the `DetailFragment` the `TextView` will be null. Why?
MYDetailFragment detailFrag = new MyDetailFragment();
detailFrag.showLstItemDetail("Selected List Item");
Please verify the following tutorial about fragments if any useful information Click here
during those two lines:
MYDetailFragment detailFrag = new MyDetailFragment();
detailFrag.showLstItemDetail("Selected List Item");
the onCreateView() was not called yet. That means the fragment rootView was never created and the TextView was never created YET!
the view will only be created after you use a fragment transaction, to put that fragment in the layout, the fragment will then be attached to the activity (onAttach()) and after a few more callbacks onCreateView() will be called. Only then anything can be set to it.
The standard good practice to pass parameters to a fragment is using a Bundle. Look an example code:
on the activity:
MYDetailFragment detailFrag = new MYDetailFragment();
Bundle b = new Bundle();
detailFrag.setArguments(b);
b.putString("detail", value);
// then proceed to the fragment transaction
then on your fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// inflate the fragment layout
View rootView = inflater.inflate(R.layout.fragments_detail_fragment, container, false);
lblItemDetail = (TextView) rootView.findViewById(R.id.lbl_itemDetail);
Bundle b = getArguments();
lblItemDetail.setText(b.getString("details"));