I have a tablayout (with 3 tabs) with viewpager and fragments.
I m trying to send the parsed Json data from MainActivity( When searchview data submitted ) to show in the textview of tabs fragments
See this Image link
The data is succesfully parsing but textview with data(in first tab) is not showing unless scrolled to 3rd tab
//Passing data from MainActivity
public String getMyData() {
return meaning;
}
//Setting value to textview from Fragment
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v=inflater.inflate(R.layout.fragment_meaning, container, false);
MainActivity mainActivity= (MainActivity) getActivity();
assert mainActivity != null;
String data= mainActivity.getMyData();
TextView textView=v.findViewById(R.id.textVIew);
textView.setText(data);
return v;
}
Want to able to show data changes instantly as it is parsed, instead of scrolling to 3rd tab to see changes
Here are some steps that might help you.
On the ViewPager adaptor you have created, make the fragment objects. like below
FragmentOne fragOne; // this should be global
On the viewPager adaptor, do some thing like this,
fragOne = new FragmentOne() // whatever your implementation is.
Then after fetching the data from the server,
if ( fragOne != null ) {
fragOne.setValueOnView( " your data to be passed" );
}
and on the FragmentOne, create a function called setValueOnView
void setValueOnView(String yourString) {
v.findViewById(R.id.textVIew).setText(yourString);
}
And one more thing, while initializing the fragment onCreateView, create an object of View
View v; // global variable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_meaning, container, false);
Use this approach for other fragments as well
Inside getItem() method in ViewPager class use Fragment constructors with String parameter
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
FragmentOne tab1 = new FragmentOne("string parameter");
return tab1;
case 1:
FragmentTwo tab2 = new FragmentTwo("string parameter");
return tab2;
case 2:
FragmentThree tab3 = new FragmentThree("string parameter");
return tab3;
default:
return null;
}
}
Inside your Fragment:
public FragmentOne(String stringParameter) {
yourLocalVariable = stringParameter; // yourLocalVariable is declared inside Fragment class;
//now you can setText() for your TextView inside onViewCreated()
}
Of course you pass your String from MainActivity to ViewPager like you did earlier.
Use Observer
public class FragmentObserver extends Observable {
#Override
public void notifyObservers() {
setChanged(); // Set the changed flag to true, otherwise observers won't be notified.
super.notifyObservers();
}
}
Activity:
public class MyActivity extends Activity {
private MyAdapter mPagerAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.my_activity);
ViewPager pager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new MyAdapter();
pager.setAdapter(mPagerAdapter);
}
private void updateFragments() {
mPagerAdapter.updateFragments();
}
}
Viewpager adapter
public class MyAdapter extends FragmentPagerAdapter {
private Observable mObservers = new FragmentObserver();
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
mObservers.deleteObservers(); // Clear existing observers.
Fragment fragment = new MyFragment();
if(fragment instanceof Observer)
mObservers.addObserver((Observer) fragment);
return fragment;
}
public void updateFragments() {
mObservers.notifyObservers();
}
}
Your Fragment
public class MyFragment extends Fragment implements Observer {
/* Fragment related stuff... */
#Override
public void update(Observable observable, Object data) {
View root = getView();
// Update your views here.
}
}
You will get data to update method even your fragment already loaded
Related
I have an activity and its child Fragment with a LinearLayout that I generate buttons inside of. When the fragment is created, everything runs fine. However, when the parent activity downloads a new item, I call the method in the fragment that is used to generate the buttons and add them to the view, but the LinearLayout returns null and I can't figure out why. I either need to fix it or find a way to "re-display" my fragment. Here is the related code:
SongFragment:
LinearLayout linearLayout;
DatabaseHelper databaseHelper;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_song, container, false);
linearLayout = rootView.findViewById(R.id.songFragmentMainLayout);
databaseHelper = new DatabaseHelper(getActivity());
return rootView;
}
#Override
public void onResume() {
super.onResume();
RefreshButtons();
}
public void RefreshButtons(){
linearLayout.removeAllViews(); //this line is where the NullPointerException is called
...
}
MainActivity:
//refresh fragment view
SongFragment fragment = (SongFragment) sectionsPagerAdapter.getItem(0);
if(downloadQueue.size() == 0){
fragment.RefreshButtons();
Toast.makeText(context, "New songs downloaded", Toast.LENGTH_SHORT).show();
}
...
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new SongFragment();
break;
case 1:
fragment = new PlaceholderFragment();
break;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Songs";
case 1:
return "Playlists";
}
return null;
}
}
Thanks for your help.
The method fragment.RefreshButtons(); returns an NPE because if you implemented SectionsPagerAdapter like you should, getItem() returns a new Instance of that fragment which is not yet attached to the fragment manager, therefore causing a Nullpointer exception.
So what you should do is get a currently active fragment instance like this:
Fragment frag = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, 0);
0 is the position of your fragment, so for example if you have 3 fragments, 0 will return the first fragment instance etc...
I created three tabs with three fragments using view pager.I want to jump to inspiring fragment after clicking on list item defined inside Categories Fragment(Tab Fragment created with view pager).When i click on the list item error occurs.I want to jump to inspiring fragment from categories fragment(fragment defined inside view pager).
Categories (Tab Fragment created with view pager)
public class Categories extends Fragment {
private RecyclerView recyclerView;
private List<CategoriesDataModel> list;
private String[] categories={"Inspiring","Feelings","Strength","Hard Work","Success"};
public Categories() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_categories, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.categoriesList_Id);
list = new ArrayList<>();
for (int i = 0; i < categories.length; i++) {
CategoriesDataModel dataModel = new CategoriesDataModel();
dataModel.cat_name = categories[i];
list.add(dataModel);
}
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setHasFixedSize(true);
CategoryRecyclerViewAdapter adapter = new CategoryRecyclerViewAdapter(list,getContext());
adapter.setOnItemClickListener(new CategoryRecyclerViewAdapter.ClickListener() {
#Override
public void onItemClick(int position, View v) {
switch (position){
case 0:
getFragmentManager().beginTransaction().replace(R.id.frameLayout_inspiring,new Inspiring()).addToBackStack(null).commit();
}
}
});
recyclerView.setAdapter(adapter);
return view;
}
}
Inspiring :-
public class Inspiring extends Fragment {
public Inspiring() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_inspiring, container, false);
}
}
Pager Adapter :-
public class Pager extends FragmentStatePagerAdapter {
int tabCount=0;
public Pager(FragmentManager fm,int tabCount) {
super(fm);
this.tabCount=tabCount;
}
//this will return tab selected
#Override
public Fragment getItem(int i) {
switch(i) {
case 0:
return new Recents();
case 1:
return new Top();
case 2:
return new Categories();
default:
return null;
}
}
#Override
public int getCount() {
return tabCount;
}
}
You might find the AndroidViewModel of use in this case.
What you are doing is attempting to maintain state between different parts of your app.
If you have an AndroidViewModel attached to the Activity Lifecycle, you can observe that state in your Activity and make transactions to the FragmentManager to represent your choices.
An example
ViewModel
This ViewModel contains state data for which navigation item you are in (representing a Fragment with an integer in this case) and using an integer to represent an index for your inspiration row.
public class NavigationViewModel extends AndroidViewModel {
private MutableLiveData<Integer> navigationLiveData = new MutableLiveData<>();
private MutableLiveData<Integer> inspirationLiveData = new MutableLiveData<>();
public NavigationViewModel(#NonNull Application application) {
super(application);
}
public LiveData<Integer> getNavigation() {
return navigationLiveData;
}
public void setNavigation(Integer id) {
navigationLiveData.postValue(id);
}
public LiveData<Integer> getInspiration() {
return inspirationLiveData;
}
public void setInspiration(Integer id) {
inspirationLiveData.postValue(id);
}
}
Activity
The Activity will observe the navigation LiveData provided by our implementation of the AndroidViewModel. This will let it know immediately when a navigation change has been made.
public class NavigationActivity extends AppCompatActivity {
private NavigationViewModel navigationViewModel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
navigationViewModel = ViewModelProviders.of(this).get(NavigationViewModel.class);
navigationViewModel.getNavigation().observe(this, id -> {
switch(id) {
case R.id.recents:
// TODO: Load recent fragment here with a transaction
break;
case R.id.top:
// TODO: Load top fragment here with a transaction
break;
case R.id.categories:
// TODO: Load categories fragment here with a transaction
break;
case R.id.inspiring:
// TODO: Load inspiring fragment here with a transaction
break;
}
});
}
}
Inspiration Fragment
This Fragment will observe the inspiration index provided by our implementation of AndroidViewModel. That lets it know what content needs to be displayed. This can be set from ANYWHERE.
public class InspiringFragment extends Fragment {
private NavigationViewModel navigationViewModel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_inspiring, container, false);
navigationViewModel = ViewModelProviders.of(this).get(NavigationViewModel.class);
navigationViewModel.getInspiration().observe(getViewLifecycleOwner(), inspiration -> {
// TODO: Update the root view UI with data gleaned using the inspiration index given here
});
return root;
}
}
Setting it
Once you have that, all you need to do is call:
navigationViewModel.setInspiration(1);
navigationViewModel.setNavigation(R.id.inspiration);
This should give you a good base to start with.
I have a supported fragment activity which will load diff fragments. The fragment has some textView with id = "score" and I want to get its handle but findViewById for score's textView returns null. Why so?
textView is placed in fragment
public class MyActivity extends extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks{
private TextView scoreBoardTextView = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
scoreBoardTextView = (TextView) findViewById(R.id.score); //this returns null
}
#Override
public void onNavigationDrawerItemSelected(int position) {
//set fragment
}
}
Note:
Directly accessing fragment's views outside fragment is not a good idea. You should use fragment callback interfaces to handle such cases and avoid bugs. The following way works but it is not recommended as it is not a good practice.
If you want to access the TextView of Fragment inside its parent Activity then you should define a method inside your Fragment class like this:
public class MyFragment extends Fragment {
TextView mTextView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main, container, false);
mTextView = (TextView) view.findViewById(R.id.textView1);
return view;
}
public void setTextViewText(String value){
mTextView.setText(value);
}
}
Now you can use this inside your Activity like this:
myFragment.setTextViewText("foo");
here myFragment is of type MyFragment.
If you want to access the whole TextView then you can define a method like this inside MyFragment.java:
public TextView getTextView1(){
return mTextView;
}
By this you can access the TextView itself.
Hope this Helps. :)
It is possible with following way:
Keep reference of inflated view in the Fragment like this :
public class MyFragment extends SherlockFragment{
MainMenuActivity activity;
public View view;
public MyFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if ( getActivity() instanceof MainMenuActivity){
activity = (MainMenuActivity) getActivity();
}
view = inflater.inflate(R.layout.aboutus, container, false);
return view;
}
}
Create a function in the Activity, like this:
public class MainMenuActivity extends SherlockFragmentActivity {
SherlockFragment fragment = null;
public void switchContent(SherlockFragment fragment) {
this.fragment = fragment;
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.mainmenu, fragment)
.commit();
invalidateOptionsMenu();
}
Its purpose is to keep reference of current fragment. Whenever you wanna switch fragment, you call above function, like this (from fragment):
activity.switchContent( new MyFragment_2());
Now you've current fragment reference. So you can directly access Fragment's views in Activity like this: this.fragment.view
You have no need of reference of Fragment view to get its components in Activity. As you can directly access layout components of a Fragment in parent Activity.
Simply you can access any component by this
findViewById(R.id.child_of_fragment_layout);
In order to access the TextView or Button or whatever in your fragment you need to do the following:
public class BlankFragment extends Fragment {
public View view;
public TextView textView;
public Button button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view =inflater.inflate(R.layout.fragment_blank, container, false);
textView = (TextView)view.getRootView().findViewById(R.id.textView_fragment1);
return view;
}
public void changeTextOfFragment(String text){
textView.setText(text);
view.setBackgroundResource(R.color.colorPrimaryDark);
}
Once that is done in your MainActivity or any other where you want to access your TextView from your Fragment you should make sure to set up the fragment in your OnCreate() method other ways it will most likely throw nullPointer. So your activity where you want to change the TextView should look smth like this:
public class MainActivity extends AppCompatActivity {
private Button button1;
private FragmentManager fragmentManager;
private FragmentTransaction fragmentTransaction;
BlankFragment blankFragment = new BlankFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button)findViewById(R.id.button1);
changeFragment();
fragmentManager = getFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment1,blankFragment);
fragmentTransaction.commit();
}
private void changeFragment(){
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
blankFragment.changeTextOfFragment("Enter here the text which you want to be displayed on your Updated Fragment");
}
});
}
Hope this helps :)
You can access with getView method of Fragment class.
For example You have a TextView in Your MyFragment with id of "text_view" In Your Activity make a Fragment of Yours:
MyFragment myFragment = new MyFragment();
And when You need a child just call getView and then find Your childView.
View view = myFragment.getView();
if (view !=null) {
view.findViewById(R.id.text_view).setText("Child Accessed :D");
}
Note: if you want the root view of your fragment, then myFragment.getView(); is simply enough.
Just put in fragment instead of putting in activity:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_new_work_order,
container, false);
TextView scoreBoardTextView = (TextView) rootView.findViewById(R.id.score);
return rootView;
}
Only doing this:
((Your_Activity) this.getActivity()).YouyActivityElements;
If your TextView placed inside Fragment that case you cannot access TextView inside your Fragment Parent Activity you can set the interface for intercommunication between Fragment and Activity and send Data when you click on TextView or anyother thing which you want to happend
You can't access Fragment element in Parent Activity, But You can pass values to your Fragment by following way.
in your onNavigationDrawerItemSelected method of MyActivity do the following
int myScore = 100;
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager
.beginTransaction()
.replace(R.id.container,
MyFragment.newInstance(myScore)).commit();
}
And in MyFragment class create a method called newInstance like following
private static final String SCORE = "score";
public static MyFragment newInstance(int score) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putInt(SCORE, score);
fragment.setArguments(args);
return fragment;
}
And in MyFragment's onCreateView() method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
TextView textView = (TextView) rootView
.findViewById(R.id.score);
textView.setText(Integer.toString(getArguments().getInt(
SCORE)));
return rootView;
}
That's All, I hope this will help you. If not please let me know.
The score textView is in the layout of fragment, it's not in the layout of the MyActivity, i.e. R.layout.activity_home. So you could find the score textview in that fragment once you inflate the corresponding layout file.
It returns null cause the TextView is an element of the Fragment, not the Activity.
Please note that the idea of using Fragment is to encapsulate a module inside the Fragment, which means the Activity should not have direct access to it's properties. Consider moving your logic where you get the TextView reference inside the Fragment
Simply declare TextView as public in fragment, initialize it by findViewById() in fragment's onCreateView(). Now by using the Fragment Object which you added in activity you can access TextView.
You need to call method findViewById from your fragment view.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
scoreBoardTextView = (TextView) mNavigationDrawerFragment.getView().findViewById(R.id.score);
}
This way works for me.
I suggest you to make the textview part of your activity layout. Alternately you can have the textview as a separete fragment. Have a look at my question here. Its similar to yours but in reverse direction. Here's a stripped down version of code I used in my project. The explanation are along the code.
The Activity Class
public class MainActivity extends ActionBarActivity {
PlaceFragment fragment;
TextView fragmentsTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Bundle bundle = new Bundle();
bundle.putString("score", "1000");
fragment = PlaceFragment.newInstance(bundle);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, fragment);
ft.addToBackStack(null);
ft.commit();
// method 1
// fragment is added some ways to access views
// get the reference of fragment's textview
if (fragment.getTextView() != null) {
fragmentsTextView = fragment.getTextView();
}
// method 2
// using static method dont use in production code
// PlaceFragment.textViewInFragment.setText("2000");
// method 3
// let the fragment handle update its own text this is the recommended
// way wait until fragment transaction is complete before calling
//fragment.updateText("2000");
}
}
The fragment class:
public class PlaceFragment extends Fragment {
public TextView textViewInFragment;// to access via object.field same to
// string.length
// public static TextView textViewInFragment;//to access via
// PlaceFragment.textView dont try this in production code
public PlaceFragment() {
}
public static PlaceFragment newInstance(Bundle bundle) {
PlaceFragment fragment = new PlaceFragment();
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.fragment_place, container, false);
textViewInFragment = (TextView) view
.findViewById(R.id.textViewInFragment);
return view;
}
#Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
if (getArguments() != null) {
textViewInFragment.setText(getArguments().getString("score"));
}
}
public TextView getTextView() {
if (textViewInFragment != null) {
return textViewInFragment;// returns instance of inflated textview
}
return null;// return null and check null
}
public void updateText(String text) {
textViewInFragment.setText(text);// this is recommended way to alter
// view property of fragment in
// activity
}
}
Communication from activity to fragment is straight forward. This is because activity contains fragment. Keep the fragment object and access its property via setters and getters or the public fields inside it. But communication from fragment to activity requires an interface.
why you don't access it directly from your FragmentPagerAdapter,
SubAccountFragment subAccountFragment = (SubAccountFragment) mSectionsPagerAdapter.getItem(1);
subAccountFragment.requestConnectPressed(view);
and here is the full example:
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Locale;
public class TabsActivity extends ActionBarActivity implements ActionBar.TabListener {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {#link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {#link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
ActionBar.Tab tab = actionBar.newTab();
View tabView = this.getLayoutInflater().inflate(R.layout.activity_tab, null);
ImageView icon = (ImageView) tabView.findViewById(R.id.tab_icon);
icon.setImageDrawable(getResources().getDrawable(mSectionsPagerAdapter.getPageIcon(i)));
TextView title = (TextView) tabView.findViewById(R.id.tab_title);
title.setText(mSectionsPagerAdapter.getPageTitle(i));
tab.setCustomView(tabView);
tab.setTabListener(this);
actionBar.addTab(tab);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_tabs, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_logout) {
finish();
gotoLogin();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public ProfileFragment profileFragment;
public SubAccountFragment subAccountFragment;
public ChatFragment chatFragment;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
profileFragment = new ProfileFragment();
subAccountFragment = new SubAccountFragment();
chatFragment = new ChatFragment();
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return profileFragment;
case 1:
return subAccountFragment;
case 2:
return chatFragment;
}
return null;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
public int getPageIcon(int position) {
switch (position) {
case 0:
return R.drawable.tab_icon_0;
case 1:
return R.drawable.tab_icon_1;
case 2:
return R.drawable.tab_icon_2;
}
return 0;
}
}
public void gotoLogin() {
Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent);
}
public void requestConnectPressed(View view){
SubAccountFragment subAccountFragment = (SubAccountFragment) mSectionsPagerAdapter.getItem(1);
subAccountFragment.requestConnectPressed(view);
}
}
If the view is already inflated (e.g. visible) on the screen then you can just use findViewById(R.id.yourTextView) within the activity as normal and it will return the handle to the text view or null if the view was not found.
I just use methods to access fragment views from parent activity, because we create a new fragment class object to insert the fragment. So I do like this.
class BrowserFragment : Fragment(), Serializable {
private lateinit var webView: NestedScrollWebView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
webView = view.findViewById(R.id.web_view)
}
fun getWebView(): WebView {
return webView
}
}
In MainActivity
val browserFragment = BrowserFragment()
val fragmentTransaction = supportFragmentManager.beginTransaction()
fragmentTransaction.add(R.id.browser_fragment_placeholder, browserFragment)
fragmentTransaction.commit()
val webView = browserFragment.getWebView()
I am using PagerSlidingTab Library for ViewPager. And I want to change Fragment while scrolling of tabs. It is working fine. Check out my code.
I am using AsynTask() on each Fragment.
When the App opens with the MainActivity, First Fragment is attached to the activity, But It shows two AsynTask() dialog message, one from First and another from Second Fragment. And When I scroll to second tab, It shows dialog message of Third Fragment.
So, If I scroll from left to right in tabs, the Fragment right to the current fragment is displayed and if i scroll from right to left, the Fragment left to the current Fragment is displayed.
Please help me to solve the problem.
My Code:
public class PageSlidingTabStripFragment extends Fragment {
public static final String TAG = PageSlidingTabStripFragment.class
.getSimpleName();
public static PageSlidingTabStripFragment newInstance() {
return new PageSlidingTabStripFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.pager, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) view
.findViewById(R.id.tabs);
ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
MyPagerAdapter adapter = new MyPagerAdapter(getChildFragmentManager());
pager.setAdapter(adapter);
tabs.setViewPager(pager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
private final String[] TITLES = { "Instant Opportunity", "Events",
"Experts" };
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new InstantOpportunity();
case 1:
return new Events();
case 2:
return new Experts();
default:
break;
}
return null;
}
}
}
Explanation:
It turns out there is an easier implementation for scrollable tabs which doesn't involve another library. You can easily implement tabs into your app using normal Android code straight from the default SDK.
The Code
Main Class:
public class PageSlidingTabStripFragment extends Fragment {
//Variables
private ViewPager viewPager;
private PagerTitleStrip pagerTitleStrip;
public PageSlidingTabStripFragment() {
// Required empty public constructor
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Find your pager declared in XML
viewPager = (ViewPager) getView().findViewById(R.id.pager);
//Set the viewPager to a new adapter (see below)
viewPager.setAdapter(new MyAdapter(getFragmentManager()));
//If your doing scrollable tabs as opposed to fix tabs,
//you need to find a pagerTitleStrip that is declared in XML
//just like the pager
pagerTitleStrip = (PagerTitleStrip)
getView().findViewById(R.id.pager_title_strip);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.[your layout name here], container, false);
}
}
Adapter:
//Note: this can go below all of the previous code. Just make sure it's
//below the last curly bracket in your file!
class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
Fragment fragment = null;
if (arg0 == 0) {
fragment = new InstantOpportunity();
}
if (arg0 == 1) {
fragment = new Events();
}
if (arg0 == 2) {
fragment = new Experts();
}
return fragment;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
if (position == 0) {
return "Instant Opportunity";
}
if (position == 1) {
return "Events";
}
if (position == 2) {
return "Experts";
}
return null;
}
}
Conclusion:
I hope this helps you understand another way to make scrollable tabs! I have examples on my Github Page about how to make each type (That being Fixed or Scrollable).
Links:
Fixed Tabs Example - Click Here
Scrollable Tabs Example - Click Here
Hope this helps!
Edit:
When asked what to import, make sure you select the V4 support fragments.
please use this example..its very easy.i already implement that.
reference link
hope its useful to you.its best example of pager-sliding-tabstrip.
Use
framelayout compulsory:
FrameLayout fl = new FrameLayout(getActivity());
fl.addView(urFragementView);
and then set your fragement view in this framelayout.
Problem
A Fragment is not reattached to its hosting ViewPager after returning from another fragment.
Situation
One Activity hosting a Fragment whose layout holds a ViewPager (PageListFragment in the example below). The ViewPager is populated by a FragmentStateViewPagerAdapter. The single Fragments hosted inside the pager (PageFragment in the example below) can open sub page lists, containing a new set of pages.
Behaviour
All works fine as long as the back button is not pressed. As soon as the user closes one of the sub PageLists the previous List is recreated, but without the Page that was displayed previously. Swiping through the other pages on the parent PageList still works.
Code
A sample application can be found on github:
Activity
public class MainActivity extends FragmentActivity {
private static final String CURRENT_FRAGMENT = MainActivity.class.getCanonicalName() + ".CURRENT_FRAGMENT";
public static final String ARG_PARENTS = "Parents";
public void goInto(String mHostingLevel, String mPosition) {
Fragment hostingFragment = newHostingFragment(mHostingLevel, mPosition);
addFragment(hostingFragment);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addBaseFragment();
}
private void addBaseFragment() {
Fragment hostingFragment = newHostingFragment("", "");
addFragment(hostingFragment);
}
private Fragment newHostingFragment(String mHostingLevel, String oldPosition) {
Fragment hostingFragment = new PageListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARENTS, mHostingLevel + oldPosition +" > ");
hostingFragment.setArguments(args);
return hostingFragment;
}
private void addFragment(Fragment hostingFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentSpace, hostingFragment, CURRENT_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
}
PageListFragment
public class PageListFragment extends Fragment {
private String mParentString;
public PageListFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_hosting, container, false);
}
#Override
public void onResume() {
mParentString = getArguments().getString(MainActivity.ARG_PARENTS);
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewPager);
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
super.onResume();
}
private static class SimpleFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private String mHostingLevel;
public SimpleFragmentStatePagerAdapter(FragmentManager fm, String hostingLevel) {
super(fm);
this.mHostingLevel = hostingLevel;
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
PageFragment pageFragment = new PageFragment();
Bundle args = new Bundle();
args.putString(MainActivity.ARG_PARENTS, mHostingLevel);
args.putInt(PageFragment.ARG_POSITION, position);
pageFragment.setArguments(args);
return pageFragment;
}
#Override
public int getCount() {
return 5;
}
}
}
PageFragment
public class PageFragment extends Fragment {
public static final String ARG_POSITION = "Position";
private String mHostingLevel;
private int mPosition;
public PageFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_page, container, false);
setupTextView(contentView);
setupButton(contentView);
return contentView;
}
private void setupTextView(View contentView) {
mPosition = getArguments().getInt(ARG_POSITION);
mHostingLevel = getArguments().getString(MainActivity.ARG_PARENTS);
TextView text = (TextView) contentView.findViewById(R.id.textView);
text.setText("Parent Fragments " + mHostingLevel + " \n\nCurrent Fragment "+ mPosition);
}
private void setupButton(View contentView) {
Button button = (Button) contentView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openNewLevel();
}
});
}
protected void openNewLevel() {
MainActivity activity = (MainActivity) getActivity();
activity.goInto(mHostingLevel, Integer.toString(mPosition));
}
}
After a lengthy investigation it turns out to be a problem with the fragment manager.
When using a construct like the one above the fragment transaction to reattach the fragment to the page list is silently discarded. It is basically the same problem that causes a
java.lang.IllegalStateException: Recursive entry to executePendingTransactions
when trying to alter the fragments inside the FragmentPager.
The same solution, as for problems with this error, is also applicable here. When constructing the FragmentStatePagerAdapter supply the correct child fragment manager.
Instead of
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
do
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getChildFragmentManager(),mParentString));
See also: github
What Paul has failed to mention is, if you use getChildFragmentManager, then you will suffer the "blank screen on back pressed" issue.
The hierarchy in my case was:
MainActivity->MainFragment->TabLayout+ViewPager->AccountsFragment+SavingsFragment+InvestmentsFragment etc.
The problem I had was that I couldn't use childFragmentManagerfor the reason that a click on the item Account view (who resides inside one of the Fragments of the ViewPager) needed to replace MainFragment i.e. the entire screen.
Using MainFragments host Fragment i.e. passing getFragmentManager() enabled the replacing, BUT when popping the back-stack, I ended up with this screen:
This was apparent also by looking at the layout inspector where the ViewPager is empty.
Apparently looking at the restored Fragments you would notice that their View is restored but will not match the hierarchy of the popped state. In order to make the minimum impact and not force a re-creation of the Fragments I re-wrote FragmentStatePagerAdapter with the following changes:
I copied the entire code of FragmentStatePagerAdapter and changed
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
...
}
with
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.detach(f);
mCurTransaction.attach(f);
return f;
}
}
...
}
This way I am effectively making sure that that the restored Fragments are re-attached to the ViewPager.
Delete all page fragments, enabling them to be re-added later
The page fragments are not attached when you return to the viewpager screen as the FragmentStatePagerAdapter is not re-connecting them. As a work-around, delete all the fragments in the viewpager after popbackstack() is called, which will allow them to be re-added by your initial code.
[This example is written in Kotlin]
//Clear all fragments from the adapter before they are re-added.
for (i: Int in 0 until adapter.count) {
val item = childFragmentManager.findFragmentByTag("f$i")
if (item != null) {
adapter.destroyItem(container!!, i, item)
}
}