I need to create an app with one activity and 3 fragments in it. Pages don't need to be dynamically created but its a plus. My question is: do I need a separate fragment for every view or I can reuse one with different view?I've read the android tutorial here https://developer.android.com/training/animation/screen-slide.html#viewpager
for view pager and it left me with that impression. Its an important project. I am a noob so pls explain for such.
I'm assuming you want 3 full screen fragments. Use a ViewPager with a FragmentPagerAdapter.
public class MyFragment extends Fragment {
#BindView(R.id.view_pager)
ViewPager viewPager;
MyPagerAdapter pagerAdapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.my_fragment, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pagerAdapter = new MyPagerAdapter(getFragmentManager());
viewPager.setAdapter(pagerAdapter);
}
}
my_fragment.xml:
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
MyPagerAdapter.java:
public class MyPagerAdapter extends FragmentPagerAdapter {
static final int NUM_PAGES = 3;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Fragment1();
case 1:
return new Fragment2();
case 2:
return new Fragment3();
}
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
This will allow swiping right or left to switch between the fragments. You will have to use a TabLayout, bottom navigation, buttons, or some other way to switch between them besides swiping. I'll leave that for you to figure out ;)
Related
So currently my code can move between objects from the same fragment, but I want to move between different fragments that have different layouts.What code do I need to add to viewpager to make it work? Do I need to make use of a FragentManager? Can anyone guide me on how to go about it? Thanks.
Below if my code:
ScreenSlidePagerActivity.java
public class ScreenSlidePagerActivity extends FragmentActivity {
private static final int NUM_PAGES = 5;
private ViewPager mPager;
private PagerAdapter pagerAdapter;
/**
* The pager adapter, which provides the pages to the view pager widget.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slide_screen_viewpager);
//declare viewpager and pageradapter
mPager = findViewById(R.id.ViewPageSlide);
pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(pagerAdapter);
}
#Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0){
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
}
else {
mPager.setCurrentItem(mPager.getCurrentItem() -1 );
}
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position) {
return new ScreenSlidePageFragment();
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
ScreenSlidePageFragment.java
public class ScreenSlidePageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.slide_content_page, container, false
);
return rootView;
}
}
You have only one class i.e.,ScreenSlidePageFragment that extends fragments. If you want different layouts for that, its better if you create different classes that inflates different layouts. eg: if you want two layouts, create two classes and both classes should inflate different layouts. The changes need to be done are :
//inside ScreenSlidePagerAdapter
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ScreenSlidePageFragment();
case 1:
return new NewClass();
//and so on
}
}
You have to create the new Class similar to ScreenSlidePageFragment. The only change is inflate a different layout.
public class NewClass extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ViewGroup rootView = (ViewGroup) inflater.inflate(
R.layout.new_layout, container, false
);
return rootView;
}
}
You can create a new_layout similar to slide_content_page and customize it as you want. You can also increase the no of fragment objects and layout as you wish.
But a new way of doing this things has come. Its better if you extend FragmentStateAdapter instead of FragmentStatePagerAdapter. This is more easy and efficient. You have to override createFragment in this case instead of getItem. Ignore of you are okay with it.
Hope this is the question you have asked and this helps. Thankyou.
Following is my onCreate code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "Inside Base Drawer...");
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager){
#Override
public void onTabSelected(TabLayout.Tab tab){
tabPosition = tab.getPosition();
}
});
}
And following is my FragmentPageAdapter, for sliding tab layouts
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
Tab1Fragment tab1 = new Tab1Fragment();
return tab1;
case 1:
Tab1Fragment tab2 = new Tab2Fragment();
return tab2;
case 2:
Tab1Fragment tab3 = new Tab3Fragment();
return tab3;
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
}
Following is the tabFragment code:
public class Tab1Fragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState){
return inflater.inflate(R.layout.tab_activity_sheet_details_tab1, viewGroup, false);
}
}
I have a custom autocompleteTextView inside the tab layout (tab_activity_sheet_details_tab1)
Following is the code for the same:
<com.example.user.package.TabLayoutActivity.AutoCompleteAdapter.HistoryAutoCompleteTextView
android:id="#+id/history_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapCharacters"
android:imeOptions="flagNoExtractUi|actionSearch"/>
However, I'm not being able to access this element from TabLayoutActivity. What is the best way to access this after the fragment view is inflated?
And do note that there are similar items in all the three Tab Layouts.
Is there a need of a separate adapter holding all the three fragment layouts and access them? If so, from which lifecycle element can I access them?
P.S.: I'm looking for a non-adapter access to fragments, if possible (possibly by "layout id")?
Something like this would expose the view to the outside world:
public class Tab1Fragment extends Fragment {
View mView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState){
mView = inflater.inflate(R.layout.tab_activity_sheet_details_tab1, viewGroup, false);
return mView;
}
public HistoryAutoCompleteTextView getTextView() {
return (HistoryAutoCompleteTextView)mView.findViewById(R.id.history_text);
}
}
Then you can get it from the fragment:
textView = ((Tab1Fragment)fragment).getTextView()
But from a software design point of view, you should probably not do that and consider instead managing this view entirely in the Fragment and only expose the data collected.
Scenarios:
I have a Fragment with a ViewPager, that it has a FragmentPagerAdapter that provides 3 Fragments.
So the first time my application loads, the 3 tab fragments looks just fine.
When I navigate in the application, i do a FragmentManager.replace to load another fragment.
When i go back, or navigate to the Main View (the tabbed View) my first and second tabs are blank.
I debugged the app, and the Fragment.onDestroyView never gets call on the Tab fragment, so when it shows again, the Fragment.onCreateView never gets called again, so my view is blank.
If I navigate to the third Tab in the Tabbed Fragment, then the Fragment.onDestroy gets called by the PageAdapter (i supposed because of the 1 offLimit on the ViewPager)
So, my question is, once another Fragment is loaded in my Activity, and then i go back, or navigate to the Tabbed View, how can i force the ViewPager, or the PageAdapter, or even the Fragment itself to be recreated.
So far i try to do a FragmentManager.remove(fragment) with the TabView without any look, also, every time, i navigate to the Tabbed View i pass a new instance to the FragmentManager.replace method, it seems that every time, he pulls the same object from the FragmentManager.
TabView (Fragment):
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.tab_view, container, false);
viewPager = (ViewPager) view.findViewById(R.id.view_iam);
final PagerAdapter pagerAdapter = new MyFragmentAdapter(getActivity().getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
return view;
}
PageAdapter:
private static class MyFragmentAdapter extends FragmentPagerAdapter {
private Fragment[] tabs;
private String[] names;
public MyFragmentAdapter(FragmentManager fm) {
super(fm);
tabs = new Fragment[]{new FlightsView(), new MyFlightsRequestView(),
new MyFlightsView()};
names = new String[]{"VUELOS", "SOLICITUDES", "MIS VUELOS"};
}
#Override
public Fragment getItem(int position) {
return tabs[position];
}
#Override
public int getCount() {
return tabs.length;
}
#Override
public String getPageTitle(int position) {
return names[position];
}
}
FlightsView (One of the Tab Fragments)
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_flight, container, false);
recycle_view = (RecyclerView) view.findViewById(R.id.recycler_view);
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
setHasOptionsMenu(true);
return view;
}
Can you please try to extend your adapter from FragmentStatePagerAdapter instead of FragmentPagerAdapter
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.
I have an app using SlidingMenu, Action Bar Sherlock and now I am trying to rewrite my previous code to using the nested fragments introduced in support lib with the release of Android 4.2.
The problem is that when I swipe through the fragments, they are visible for a split second and then they disappear (black screen). Sometimes they stay on screen, and sometimes the screen is entirely black and the fragment doesn't appear at all. I suspect I have a lack of understanding of the fragment lifecycle, but I really can't see the error here.
Swiping through them gets me different results. On initial load the first fragment is black. If I swipe to nr 4 and back to nr 1, then nr 1 fragment is OK. If I swipe fast to nr 2 and then to nr 1, the nr 1 is black again. If I swipe slowly from nr 2 to nr 1, then nr 1 stays OK :-/
Here is my code:
public class LeagueInfoFragment extends SherlockFragment {
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container != null) {
container.removeAllViews();
}
setRetainInstance(true);
setHasOptionsMenu(true);
mExampleId = getArguments().getInt("mExampleId");
View view = inflater.inflate(R.layout.viewpager_tournament, container,
false);
ViewPager awesomePager = (ViewPager) view.findViewById(R.id.pager);
awesomePager.setAdapter(new ExamplePagerAdapter(this, getChildFragmentManager(), createFragments()));
TabPageIndicator titleIndicator = (TabPageIndicator) view
.findViewById(R.id.titles);
titleIndicator.setViewPager(awesomePager);
return view;
}
private List<Fragment> createFragments() {
List<Fragment> list = new ArrayList<Fragment>();
list.add(LeagueTableFragment.newInstance(0));
list.add(FixturesFragment.newInstance(1));
list.add(NewsFragment.newInstance(2));
list.add(TopscorerFragment.newInstance(3));
return list;
}
private class ExamplePagerAdapter extends FragmentPagerAdapter {
String[] pages;
LeagueInfoFragment _activity;
List<Fragment> fragments;
private ExamplePagerAdapter(LeagueInfoFragment a,
FragmentManager fragManager, List<Fragment> frags) {
super(fragManager);
this.fragments = frags;
_activity = a;
pages = new String[] { _activity.getString(R.string.table),
_activity.getString(R.string.fixtures),
_activity.getString(R.string.news),
_activity.getString(R.string.top_scorers) };
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public Fragment getItem(int arg0) {
return fragments.get(arg0);
}
public String getPageTitle(int position) {
return pages[position];
}
}
And here is one of my fragments (simplified to reduce code posted here):
public class NewsFragment extends SherlockFragment implements IAsynchData
{
public static NewsFragment newInstance(int notUsed) {
NewsFragment f = new NewsFragment();
return f;
}
#Override
public View onCreateView(android.view.LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
if (container != null) {
container.removeAllViews();
}
View view = inflater.inflate(R.layout.fragment_news, container,
false);
//Code left out to load the URL in the webview
updateRssFeed("http://www.sportspage.com/myteam");
return view;
}
}
Sorry, but why are you doing this while onCreateView in Fragment:
if (container != null) {
container.removeAllViews();
}
As I know, in this moment, container is your ViewPager and removeAllViews() - remove all created View of your Fragments in ViewPager.