Current I have a ViewPager which have 3 different tabs(Peer, Sync and Share).
In the Peer fragment, it contain a ListView with clickable items. OnItemClick I wish to open a new fragment which will display the detail of the selected item,
But I am not sure how to properly implement this functionality...
Activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.file_sharing_activity);
// Tabs stuff ...
this.tabsAdapter = new TabsPagerAdapter(this.getSupportFragmentManager());
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(this.tabsAdapter);
// Create tabs bar
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create tab fragments
this.peerListFragment = new PeerListFragment();
this.syncFragment = new SyncFragment();
this.shareFragment = new ShareFragment();
// Create tabs
actionBar.addTab(actionBar.newTab().setText("Peers").setTabListener(this.peerListFragment));
actionBar.addTab(actionBar.newTab().setText("Sync").setTabListener(this.syncFragment));
actionBar.addTab(actionBar.newTab().setText("Share").setTabListener(this.shareFragment));
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When swiping between pages, select the
// corresponding tab.
getActionBar().setSelectedNavigationItem(position);
}
});
try {
ProgramController.getInstance().initializeProgram(this);
} catch (Exception e) {}
}
TabPagerAdapter:
private class TabsPagerAdapter extends FragmentPagerAdapter{
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return peerListFragment;
case 1:
return syncFragment;
case 2:
return shareFragment;
default:
return null;
}
}
#Override
public int getCount() {
return NB_TABS;
}
}
PeerListFragment
public class PeerListFragment extends Fragment implements ActionBar.TabListener{
ListView peerListView;
public PeerListFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_peer_list, container, false);
peerListView = (ListView) view.findViewById(R.id.list_peer);
PeerListAdapter adapter = new PeerListAdapter(getActivity());
peerListView.setAdapter(adapter);
peerListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//Display detail fragment here
}
});
return view;
}
In general, you would have a method on your Activity that would be called from onItemClick() to display the detail view, i,e, showDetail(itemId). The Activity would actually handle the transition to the detail view.
Now, since your ViewPager is in an Activity and not a Fragment, you have two choices:
Have a DetailActivity that is started with an Intent from your current Activity. (Easiest option, but less flexible for tablets)
Rewrite your Activity to put your view with the ViewPager in a Fragment. Then the Activity would replace the current fragment that has the ViewPager with the detail fragment. (Harder option, but you can display side-by-side in a tablet).
Right now, your ViewPager is in your activity layout. In order to make the fragments work, your activity layout would just have one or two child layouts which function as fragment containers, then the ViewPager would go into a fragment layout.
Related
I set up a tab slider in my activity calling 3 separate fragments depending on the fragment selected. The problem is that when the first tab is selected, "Science" is shown - which was set on the onCreateView() method of the first fragment. However, WITHOUT clicking on the other tabs, "Technology" and "Sports" are then shown.
To my knowledge, the way I implemented it the last two should only show once the corresponding tab is selected.
This is my Page adapter class
public class PagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 3; //Represents the number of tabs
private String tabTitles[] = new String[]{"Technology", "Science", "Sports"}; //Tab values defined in an array
private Context context;
public PagerAdapter(FragmentManager fm, Context context)
{
super(fm);
this.context = context;
}
#Override
public int getCount()
{
return PAGE_COUNT;
}
//determines the fragment depending on the selected tab
#Override
public Fragment getItem(int position)
{
if(position==0)
return TechnologyFragment.newInstance(position+1);
else if(position==1)
return ScienceFragment.newInstance(position+1);
else if(position==2)
return SportsFragment.newInstance(position+1);
else
return null;
}
//displays the title for each tab
#Override
public CharSequence getPageTitle(int position)
{
// Generate title based on item position
return tabTitles[position];
}
}
This is the news class - where the view pager and tab layout are set up
public class News extends AppCompatActivity {
//Here the viewPager is connected to the PagerAdapter class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news);
//This component will be used to page between the various fragments created.
final ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager(), News.this));
//the tabLayout is given the viewPager to connect to the pager with the tabs
TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
//the following was used so the tabs fill up the width of the screen being responsive for all devices and orientations
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
}
}
And these are the fragment classes - (the other two are identical but have a different message represented using the Toast)
public class ScienceFragment extends Fragment {
//other methods
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_science_fragment, container, false);
toShow=getAll();
GridView gridView = (GridView)view.findViewById(R.id.gridview);
gridView.setAdapter(new ImageAdapter(getContext(),toShow));
Toast.makeText(getContext(), "Science", Toast.LENGTH_SHORT).show();
return view;
}
}
Any help is appreciated
I have a fragment, fragment A, which holds a ViewPager. The ViewPager loads different fragments which the user can swipe through "indefinitely" (I use a really high number of pages/loops to emulate this). When a user clicks on the current ViewPager fragment, then fragment A with the ViewPager is replaced by fragment B in the fragment manager. When the user returns from fragment B, the backstack is popped using popBackStackImmediate(). If the user repeats this action several times, the heap begins to fill up by about 100kb at a time until the app starts to become sloppy and malfunction as the memory fills up. I'm unsure what exactly is causing this, can anyone help?
My fragment A with the ViewPager:
public class MainFragment extends Fragment {
private MainWearActivity mMainWearActivity;
View view;
private int currentPage;
private ViewPager pager;
private ViewPagerAdapter adapter;
private LinearLayout helpIcons;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMainWearActivity = (MainWearActivity) getActivity();
adapter = new ViewPagerAdapter(this.getChildFragmentManager());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_main, container, false);
// Scrolling menu
pager = (ViewPager) view.findViewById(R.id.watchNavPager);
pager.setAdapter(adapter);
pager.addOnPageChangeListener(adapter);
// Set current item to the middle page
pager.setCurrentItem(Consts.FIRST_PAGE);
currentPage = Consts.FIRST_PAGE;
// Set number of pages
pager.setOffscreenPageLimit(4);
// Set no margin so other pages are hidden
pager.setPageMargin(0);
return view;
}
#Override
public void onDestroyView() {
pager = null;
super.onDestroyView();
}
}
My adapter class:
public class ViewPagerAdapter extends FragmentPagerAdapter implements
ViewPager.OnPageChangeListener {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position)
{
position = position % Consts.PAGES;
switch(position){
case Consts.AUDIO_POS:
return new AdapterAudioFragment();
case Consts.VOICE_POS:
return new AdapterVoiceFragment();
case Consts.MAIL_POS:
return new AdapterMailFragment();
case Consts.INFO_POS:
return new AdapterInfoFragment();
default:
return null;
}
}
#Override
public int getCount()
{
return Consts.PAGES * Consts.LOOPS; // (4 * 1000)
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {}
}
One of my fragments that the adapter loads (they are all pretty much the same):
public class AdapterAudioFragment extends Fragment {
private ImageView menuImg;
private TextView menuText;
private LinearLayout rootView;
private MainWearActivity mMainWearActivity;
private View.OnClickListener imgClickListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMainWearActivity = (MainWearActivity) getActivity();
imgClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
mMainWearActivity.replaceFragment(mMainWearActivity.getFragment(Consts.FRAG_AUDIO), Consts.FRAG_AUDIO);
}
};
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// Get root view of the fragment layout
rootView = (LinearLayout) inflater.inflate(
R.layout.fragment_nav_object, container, false);
// Set the current menu image and text
menuImg = (ImageView) rootView.findViewById(R.id.fragment_image);
menuImg.setImageResource(R.mipmap.ic_audio);
menuImg.setOnClickListener(imgClickListener);
menuText = (TextView) rootView.findViewById(R.id.menuTxt);
menuText.setText(Consts.MENU_HEADER_AUDIO);
// Set the current menu selection
mMainWearActivity.setCurrentSelection(Consts.AUDIO_POS);
return rootView;
}
}
I have a feeling that the adapter's fragments are all being created but never destroyed and piling up in the heap but I can't figure out how to resolve this. Do I need to call destroyItem in the adapter and manually destroy them? Any help would be most appreciated, thanks.
Adding this to Fragment stopped leaks for me:
#Override
public void onDestroyView() {
super.onDestroyView();
viewPager.setAdapter(null);
}
Looking at the source code, the problem seems to be that when calling ViewPager#setAdapter the view will register itself as observer for the adapter. So each time onViewCreated is called your pager adapter instance will have reference of the newly created view.
There is a specific PagerAdapter for your needs - FragmentStatePagerAdapter
This version of the pager is more useful when there are a large number of pages, working more like a list view. When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.
My application has to swipe in between fragments when a button is pressed. If I was hosting swipe tab and view pager inside an activity, I would do something like this.
((ParentActivityName) getActivity()).setCurrentItem(2, true);
Now I have a parent Fragment that hosts the slide tabs. It has the following method to set current child Fragment to viewpager.
public void setCurrentItem (int item, boolean smoothScroll) {
pager.setCurrentItem(item, smoothScroll);
}
On Click of "Next" button in one of the sliding tab Fragments, I am trying to call the method as
new FragUserRegistration().setCurrentItem(1,true);
But is simply returning a null object reference error. Any help would be much appreciated.
I worked it out simply by calling viewpager from parent Fragment to each sliding tab fragments and then the associated setCurrentItem method.
viewPager = (ViewPager)getActivity().findViewById(R.id.pager);
viewPager.setCurrentItem(int position, true);
//four swipe-able fragments so position - -> 1-3 (total count 4)
I am not sure where your click happens to set the current item.
Maybe you'll find this useful:
Your MainFragment:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//init view
MainViewPageAdapter mainViewPageAdapter = new MainViewPageAdapter(getChildFragmentManager());
yourViewPager.setAdapter(mainViewPageAdapter);
return view;
}
private class MainViewPageAdapter extends FragmentStatePagerAdapter {
private static final int MAX_COUNT = 2;
public MainViewPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 1:
fragment = YourChildFragmentOne.getInstance();
break;
case 2:
fragment = YourChildFragmentTwo.getInstance();
break;
}
return fragment;
}
#Override
public int getCount() {
return MAX_COUNT;
}
}
In your ChildFragment(s):
(or create an abstract ChildFragment, which handles the click listener and create two instances of the abstract one)
private OnChildFragmentClickListener mClickListener;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mClickListener = (OnChildFragmentClickListener) getParentFragment();
}
//call somewhere in your ChildFragment mClickListener.onChildFragClick(index);
public interface OnChildFragmentClickListener{
void onChildFragClick(int index);
}
Now let your MainFragment implement OnChildFragmentClickListener and call there:
#Override
public void onChildFragClick(int index){
yourViewPager.setCurrentItem(index);
}
This is giving me headache. Lets say my app has a ViewPager which contains 4 tabs. I want to have multiple sub-fragments within each tab. that means each tab would have more than just one view. I totally have no clue how to achieve this....
I have a FragmentActivity which gets load first and set my ViewPager
public class FragActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frag_main);
ViewPager pager = (ViewPager) findViewById(R.id.pager);
PagerAdapter adapter = new FFNPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
pager.setOffscreenPageLimit(3);
tabs.setViewPager(pager);
}
}
I then have my FragmentPagerAdapter
public class PagerAdapter extends FragmentPagerAdapter implements TextAndIconTabProvider {
private final String[] TITLES = { "FIRST", "SECOND", "THIRD", "FORTH" };
public PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment frag = new Fragment();
switch (position) {
case 1:
frag = new FirstFrag();
break;
case 2:
frag = new SecondFrag();
break;
case 3:
frag = new ThirdFrag();
break;
case 4:
frag = new ForthFrag();
break;
}
return frag;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return TITLES.length;
}
}
the above would give me a working ViewPager with 4 active tabs. Then I need to do all 4 individual Fragments. I'm giving out one example below.
public class FirstFrag extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.firstfrag, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Button btn1 = (Button) getActivity().findViewById(R.id.btn1);
btn1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// what should I put in this block??????
Fragment fragment = new FirstFragSub1();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.pager, fragment); //<<------what should i replace???????
transaction.commitAllowingStateLoss();
}
});
}
}
The OnCreateView in FirstFragSub1 gets called but I don't see anything displayed on the screen. Basically just a blank. I know by replacing R.id.pager should not be the correct way, I'm just giving out an example of what I initial thought was.
Here is my FirstFragSub1
public class FirstFragSub1 extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.i("FirstFragSub1","onCreateView is called");
return inflater.inflate(R.layout.subone, container, false);
}
}
Can someone please help me? I really out of idea...Thanks
there is a great tutorial and github here that covers this in detail.
http://tausiq.wordpress.com/2014/06/06/android-multiple-fragments-stack-in-each-viewpager-tab/
https://github.com/tausiq/ViewPagerMultipleFragmentDemo
this covers handling the backstack and multiple tabs with multiple views per tab. hope this help I was searching for a similar solution when i read your question.
Have FrameLayouts in the view that is being inflated by the Fragment. And onCreateView, replace the FrameLayout by the sub fragments that you want.
Also, be careful not to use the Activity's FragmentManager. getFragmentManager returns the Activity's FragmentManager and that will lead to an undesirable result (Only one fragment inside your ViewPager would have the sub fragments loaded). Use the getChildFragmentManager function instead.
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.