Viewpager and Sherlock Fragments. How to do somethng inside fragment from FragmentActivity? - android

I have a parent SherlockFragmentActivity class that contains ViewPager with 4 Fragments inside.
One of them extends from SherlockListFragment and I want to scroll it to top by click on it's tab.
MainActivity class:
public class MainActivity extends SherlockFragmentActivity {
ViewPager viewPager;
TabAdapter tabAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
setTheme(Constants.THEME);
viewPager = new ViewPager(this);
viewPager.setId(R.id.pager);
viewPager.setBackgroundResource(R.color.background_color);
tabAdapter = new TabAdapter(this,viewPager);
super.onCreate(savedInstanceState);
setContentView(viewPager);
// Action bar setup
setupTabs(savedInstanceState);
}
private void setupTabs(Bundle savedInstanceState) {
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (int i = 1; i <= 4; i++) {
ActionBar.Tab tab = getSupportActionBar().newTab();
switch (i) {
case 1:
tab.setText(R.string.feed).setTabListener(tabAdapter);
tabAdapter.addTab(EventListFragment.class);
break;
case 2:
tab.setText(R.string.downloads).setTabListener(tabAdapter);
tabAdapter.addTab(LocalEventListFragment.class);
break;
case 3:
tab.setText(R.string.tags).setTabListener(tabAdapter);
tabAdapter.addTab(TagsFragment.class);
break;
case 4:
tab.setText(R.string.settings).setTabListener(tabAdapter);
tabAdapter.addTab(SettingsFragment.class);
break;
}
getSupportActionBar().addTab(tab);
}
}
TabAdapter class:
public static class TabAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final Context mContext;
private final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
private final ActionBar mActionBar;
private final ViewPager mViewPager;
public TabAdapter(SherlockFragmentActivity activity, ViewPager pager){
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(Class<?> clss){
classes.add(clss);
mFragments.add(Fragment.instantiate(mContext, clss.getName(),
null));
}
#Override
public Fragment getItem(int i) {
return mFragments.get(i);
}
public int getId(int index){
return mFragments.get(index).getId();
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// fixed double call onTabReselected
if (mActionBar.getSelectedNavigationIndex() != position)
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int i) {
}
#Override
public int getCount() {
return 4;
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
final int position = tab.getPosition();
final Fragment fragment = mFragments.get(position);
if (fragment != null) {
switch (position) {
case 0:
// call tab's ListFragment scroll to top item
((EventListFragment) fragment).scrollToTop();
break;
case 1:
// do something
break;
}
}
}
onTabReselected called, then user press current tab, so I try to do EventListFragment scrolling:
EventListFragment class:
public class EventListFragment extends SherlockListFragment {
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
mAdapter = new EventListAdapter(getSherlockActivity());
setListAdapter(mAdapter);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
}
#Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View eventListLayout = inflater.inflate(R.layout.eventlist_fragment,null);
ListView lv = (ListView) eventListLayout.findViewById(android.R.id.list);
ViewGroup parent = (ViewGroup) lv.getParent();
//Remove ListView and add PullToRefreshListView in its place
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
mPullToRefreshListView = onCreatePullToRefreshListView(inflater, savedInstanceState);
parent.addView(mPullToRefreshListView, lvIndex, lv.getLayoutParams());
return eventListLayout;
}
public void scrollToTop() {
if (getSherlockActivity() != null) { // null after screen rotation
final ListView listView = getListView();
listView.post(new Runnable(){
public void run() {
listView.smoothScrollToPosition(0);
}});
}
}
It works on application start, but after screen rotation scrollToTop - getSherlockActivity() returns null.
If remove this condition check, have an exception:
java.lang.IllegalStateException: Content view not yet created
at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
at com.project.fragment.EventListFragment.scrollToTop(EventListFragment.java:337)
at com.project.MainActivity$TabAdapter.onTabReselected(MainActivity.java:411)
at com.actionbarsherlock.internal.app.ActionBarWrapper$TabWrapper.onTabReselected(ActionBarWrapper.java:327)
I haven't totally understatinding how to ViewPager and its FragmentPagerAdapter works. So can't find a problem, that occurs.

Use this FragmentPageAdapter:
public class TestFragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
protected static final String[] CONTENT = new String[] { "CATEGORIAS", "PRINCIPAL", "AS MELHORES", };
protected static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar,
R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms,
};
private int mCount = CONTENT.length;
public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {Fragment f = null;
switch(position){
case 0:
{
f = new ArrayListFragment();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 1:
{
f = new HomeFragment();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 2:
{
f = new EndlessCustomView();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
default:
throw new IllegalArgumentException("not this many fragments: " + position);
}
return f;
}
#Override
public int getCount() {
return mCount;
}
#Override
public CharSequence getPageTitle(int position) {
return TestFragmentAdapter.CONTENT[position % CONTENT.length];
}
#Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
This Activity:
public class BaseSampleActivity extends SlidingFragmentActivity {
private static final Random RANDOM = new Random();
TestFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;
protected ListFragment mFrag;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.themed_titles);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mAdapter = new TestFragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(1);
mIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}

Applied solution according to this post:
MainActivity class:
//...
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
FragmentManager manager = getSupportFragmentManager();
for (int i = 0; i < tabAdapter.getClasses().size(); i++) {
String className = tabAdapter.getClasses().get(i).getName();
if (manager.findFragmentByTag(className) != null) {
manager.putFragment(outState, className, manager.findFragmentByTag(className));
}
}
}
//...
TabAdapter class:
//...
public void addTab(Class<?> clss, FragmentManager manager, Bundle savedInstanceState) {
classes.add(clss);
String className = clss.getName();
tags.add(className);
Fragment fragment;
if (savedInstanceState != null) {
fragment = manager.getFragment(savedInstanceState, className);
if (fragment == null) {
fragment = createFragment(className);
manager.beginTransaction().add(fragment, className);
}
} else {
fragment = createFragment(className);
manager.beginTransaction().add(fragment, className);
}
mFragments.add(fragment);
}
//...
where createFragment is a simple method, that creates needed fragment by passed class name.

Related

ViewPager : Navigating Back to Parent Fragment From Child Fragment Closes The Application

I am implementing nested fragments in a ViewPager. When I perform the transaction by replacing the child fragment in the parent fragment after executing addToBackStack(), I am able to see the view shown below. But when I press back button and the code reaches the MainActivity's onBackPressed() method, I notice the stack size is 1, and I successfully popout the Fragment. The problem starts now
My app closes and for a brief amount of time, I see my child fragment closing and then the app closing.
MainActivity
public class MainActivity extends FragmentActivity implements FragmentCommunicationListener {
ViewPager viewPager;
PagerAdapter pagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//createTabs();
viewPager = (ViewPager) findViewById(R.id.pager);
Fragment[] fragments = new Fragment[]{
new ViewStudentsFragment(),
new AddStudentFragment()
};
pagerAdapter = new PagerAdapter(getSupportFragmentManager(), this, fragments);
viewPager.setAdapter(pagerAdapter);
}
#Override
public void passMsg(Fragment fragment, Bundle msg) {
int currentItem = viewPager.getCurrentItem();
Fragment targetFragment;
if (currentItem == 0) {
targetFragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 1);
((AddStudentFragment) targetFragment).renderData(msg);
viewPager.setCurrentItem(1);
} else {
targetFragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 0);
((ViewStudentsFragment) targetFragment).updateList(msg,viewPager);
viewPager.setCurrentItem(0);
}
}
#Override
public void onBackPressed() {
ViewStudentsFragment fragment = (ViewStudentsFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 0);
super.onBackPressed();
if (fragment.getChildFragmentManager().getBackStackEntryCount() != 0) {
fragment.getChildFragmentManager().popBackStack();
}
}
}
Parent Fragment
public class ViewStudentsFragment extends Fragment {
ArrayList<Student> studentList = new ArrayList<Student>();
ListView list;
ListViewAdapter listAdapter;
GridView grid;
FragmentCommunicationListener fragComm = null;
int resIdView, resIdSort;
GridViewAdapter gridAdapter;
static ImageButton toggleView, toggleSort;
View view;
ViewPager viewPager=null;
public ViewStudentsFragment() {
}
private static ViewStudentsFragment viewStudentsFragment;
FragmentTransaction transaction;
Fragment details ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_view_students, container, false);
toggleView = (ImageButton) view.findViewById(R.id.viewImageButton);
toggleSort = (ImageButton) view.findViewById(R.id.sortImageButton);
transaction= getChildFragmentManager().beginTransaction();
view.findViewById(R.id.container).setVisibility(View.GONE);
...
toggleView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
...
}
});
toggleSort.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
...
}
});
registerForContextMenu(list);
registerForContextMenu(grid);
return view;
}
public void updateList(Bundle bundle,ViewPager vp) {
viewPager=vp;
...
}
listAdapter.notifyDataSetChanged();
gridAdapter.notifyDataSetChanged();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FragmentCommunicationListener) {
fragComm = (FragmentCommunicationListener) activity;
} else {
throw new ClassCastException();
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
...
}
#Override
public boolean onContextItemSelected(MenuItem item) {
...
switch (menuItemIndex) {
case Constant.VIEW_STUDENT_DETAIL:
bundle.putSerializable("viewField", student); view.findViewById(R.id.container).setVisibility(View.VISIBLE);
transaction.addToBackStack(null);
details = new Details();
transaction.replace(R.id.container, details, "task");
transaction.commit();
details.setArguments(bundle);
break;
...
default:
}
listAdapter.setStudentList(studentList);
gridAdapter.setStudentList(studentList);
listAdapter.notifyDataSetChanged();
gridAdapter.notifyDataSetChanged();
return true;
}
}
ChildFragment
public class Details extends Fragment {
View view;
static Details details;
Context context;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
context=container.getContext();
Bundle bundle = getArguments();
view=inflater.inflate(R.layout.display_details, container, false);
...
return view;
}
#Override
public void onDetach() {
super.onDetach();
view.findViewById(R.id.displayDetails).setVisibility(View.GONE);
}
#Override
public void onDestroyView() {
super.onDestroyView();
view.findViewById(R.id.displayDetails).setVisibility(View.GONE);
}
#Override
public void setArguments(Bundle bundle) {
super.setArguments(bundle);
}
}
PagerAdapter
public class PagerAdapter extends FragmentPagerAdapter {
private String[] tabMenu;
private int pageCount;
private Context context;
private Fragment[] fragments;
public PagerAdapter(FragmentManager fm, Context context, Fragment[] fragments) {
super(fm);
this.context = context;
tabMenu = context.getResources().getStringArray(R.array.tab_menu);
pageCount = tabMenu.length;
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return fragments[position];
}
#Override
public int getCount() {
return fragments.length;
}
#Override
public CharSequence getPageTitle(int position) {
return tabMenu[position];
}
}
If you use FragmentTransaction.addToBackStack(), the back button is handled automatically for you.
When you do this:
#Override
public void onBackPressed() {
ViewStudentsFragment fragment = (ViewStudentsFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 0);
super.onBackPressed();
if (fragment.getChildFragmentManager().getBackStackEntryCount() != 0) {
fragment.getChildFragmentManager().popBackStack();
}
}
you are basically popping the backstack twice, which is why your application quit.
Replace the onBackPressed() method in your Activity with this:
#Override
public void onBackPressed() {
ViewStudentsFragment fragment = (ViewStudentsFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + 0);
if (fragment.getChildFragmentManager().getBackStackEntryCount() != 0) {
fragment.getChildFragmentManager().popBackStack();
}
else {
super.onBackPressed();
}
}

How to count fragments?

I have an activity and pager adapter in it which displays 3 fragments. The fragments are shuffled. I need to know the number of each page when I am swiping through them and that number needs to be displayed in a textView. For example, when I am in the first page number 1 is displayed, second page - number 2 and so on.
PagerAdapter.java
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int arg0) {
return this.fragments.get(arg0);
}
#Override
public int getCount() {
return this.fragments.size();
}
public void setFragments(List<Fragment> fragments) {
this.fragments = fragments;
}
}
mainActivity.java
public class testActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pager_adapter);
initialisePaging();
}
private void initialisePaging() {
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this,fragment1.class.getName()));
fragments.add(Fragment.instantiate(this,fragment2.class.getName()));
fragments.add(Fragment.instantiate(this,fragment3.class.getName()));
PagerAdapter mPagerAdapter = new PagerAdapter(this.getSupportFragmentManager(), fragments);
Collections.shuffle(fragments, new Random(System.nanoTime()));
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(mPagerAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_test, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
If you want to be displaying the number in your fragment, use this
In your Activity
#Override
public Fragment getItem(int position) {
// Here you can add an argument that will be passed to the fragment
// In your case you need to pass the page number
Fragment fragment = this.fragments.get(arg0);
Bundle b = new Bundle();
b.putInt("page_number", position);
fragment.setArguments(b);
return fragment;
}
In you fragment do this
int number;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Read the data that Activity passed to us
if (savedInstanceState == null) {
Bundle args = getArguments();
if (args != null) {
number = args.getInt("page_number") + 1;
}
}
else {
number = savedInstanceState.getInt("page_number");
}
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
// Here you need to find your TextView and show the number
View v = inflater.inflate(R.layout.some_layout, container, false);
((TextView) v.findViewById(R.id.someTextView)).setText(String.format("%d", number));
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("page_number", number);
}
If you want to be displaying the number in your Activity, use this
private void initialisePaging() {
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this,fragment1.class.getName()));
fragments.add(Fragment.instantiate(this,fragment2.class.getName()));
fragments.add(Fragment.instantiate(this,fragment3.class.getName()));
PagerAdapter mPagerAdapter = new PagerAdapter(this.getSupportFragmentManager(), fragments);
Collections.shuffle(fragments, new Random(System.nanoTime()));
// !!! Change ME!!!!!
textView = (TextView) findViewById(R.id.someTextView);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
textView.setText("Position: " + i);
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
pager.setAdapter(mPagerAdapter);
}
Use PageChangeListener as:
yourPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position)
{
yourTextView.setText("Page: " + position);
}
... ...
});

Show a detail fragment when clicking an item in a ListFragment in Android Studio

My app has a tab bar that should be visible at all times. The first tab contains a ListFragment. When I click on an item within, it loads a new activity that creates a detail fragment displaying the contents of the object in the list. I would like to display this content without having to start a new activity because it also destroys the tab bar!
Any help would be greatly appreciated!
To illustrate, here are some screenshots and code:
This is the code for the FragmentActivity that creates the tabs:
public class MainFragmentActivity extends FragmentActivity
implements ActionBar.TabListener {
SectionsPagerAdapter sectionsPagerAdapter = null;
ViewPager viewPager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
getActionBar().setDisplayShowHomeEnabled(false);
getActionBar().setDisplayShowTitleEnabled(false);
sectionsPagerAdapter =
new SectionsPagerAdapter
(
getSupportFragmentManager());
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(sectionsPagerAdapter);
viewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
}); // End of sectionPageAdapter.
Tab browseTab = actionBar.newTab();
browseTab.setIcon(R.drawable.search);
browseTab.setTabListener(this);
actionBar.addTab(browseTab);
Tab myStuffTab = actionBar.newTab();
myStuffTab.setIcon(R.drawable.my_stuff);
myStuffTab.setTabListener(this);
actionBar.addTab(myStuffTab);
Tab profileTab = actionBar.newTab();
profileTab.setIcon(R.drawable.profile);
profileTab.setTabListener(this);
actionBar.addTab(profileTab);
Tab settingsTab = actionBar.newTab();
settingsTab.setIcon(R.drawable.settings);
settingsTab.setTabListener(this);
actionBar.addTab(settingsTab);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onTabSelected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Fragment browseFragment = new BrowseFragment();
Bundle browseArgs = new Bundle();
browseArgs.putInt(BrowseFragment.sectionNumberKey, position + 1);
browseFragment.setArguments(browseArgs);
return browseFragment;
case 1:
Fragment myStuffFragment = new MyStuffFragment();
Bundle myStuffArgs = new Bundle();
myStuffArgs.putInt(BrowseFragment.sectionNumberKey, position + 1);
myStuffFragment.setArguments(myStuffArgs);
return myStuffFragment;
case 2:
Fragment profileFragment = new ProfileFragment();
Bundle profileArgs = new Bundle();
profileArgs.putInt(BrowseFragment.sectionNumberKey, position + 1);
profileFragment.setArguments(profileArgs);
return profileFragment;
case 3:
Fragment settingsFragment = new SettingsFragment();
Bundle settingsArgs = new Bundle();
settingsArgs.putInt(BrowseFragment.sectionNumberKey, position + 1);
settingsFragment.setArguments(settingsArgs);
return settingsFragment;
}
return null;
}
// There are always 4 tabs
#Override
public int getCount() {
return 4;
}
// Return a CharSequence for the selected tab
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase();
case 1:
return getString(R.string.title_section2).toUpperCase();
case 2:
return getString(R.string.title_section3).toUpperCase();
case 3:
return getString(R.string.title_section4).toUpperCase();
}
return null;
}
}
} // End of class.
This is the code for the first tab:
public class BrowseFragment extends ListFragment {
public static String sectionNumberKey = "sec_num";
private String activityName = "Browse";
int currentPosition = 0;
List<Listing> listings = new ListingData().getListings();
public BrowseFragment() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BrowseArrayAdapter adapter = new BrowseArrayAdapter(getActivity(),
R.layout.browselist_item,
listings);
setListAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_browse,
container, false);
TextView tv = (TextView) rootView.findViewById(R.id.section_label);
int intSectionNumber = getArguments().getInt(sectionNumberKey);
String numAsString = Integer.toString(intSectionNumber);
tv.setText(numAsString);
activityName += " " + numAsString;
return rootView;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
void showDetails(int index) {
currentPosition = index;
Intent intent = new Intent();
intent.setClass(getActivity(), BrowseDetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
And here is the code for the Detail Activity:
public class BrowseDetailsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
BrowseDetailFragment details = new BrowseDetailFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
Basicly you just have to use the content of the onCreate method from your BrowseDetailActivity in the showDetails method of your BrowseFragment. In this way, you can drop your BrowseDetailsActivity.
BrowseFragment.java
void showDetails(int index) {
BrowseDetailFragment details = BrowseDetailFragment.newInstance(index);
getChildFragmentManager().beginTransaction().add(details).commit();
}
And use the static newInstance method inside your BrowseDetailFragment like so:
BrowseDetailFragment.java
public class BrowseDetailFragment extends Fragment {
private int position;
public static BrowseDetailFragment newInstance(int position) {
BrowseDetailFragment fragment = new BrowseDetailFragment();
fragment.position = position;
return fragment;
}
public BrowseDetailFragment() {
//Required empty constructor
}
//Lifecycle methods and logics
}
Make sure to provide some navigation option so users can return to your list.

NullPointerException a call tag fragment ViewPager

Need help, trying to invoke a method fragment of Activity, I think that is not correct ask tags for fragments.
so ask tags:
public class TitleAdapter extends FragmentPagerAdapter {
public final String titles[] = new String[] { "A", "B", "C" };
public final Fragment frags[] = new Fragment[titles.length];
public TitleAdapter(FragmentManager fm) {
super(fm);
frags[0] = new FragmentA();
fm.beginTransaction().add(frags[0], "fragA").commit();
frags[1] = new FragmentB();
fm.beginTransaction().add(frags[1], "fragB").commit();
frags[2] = new FragmentC();
fm.beginTransaction().add(frags[2], "fragC").commit();
}
#Override
public CharSequence getPageTitle(int position) {
Log.v("TitleAdapter - getPageTitle=", titles[position]);
return titles[position];
}
#Override
public Fragment getItem(int position) {
Log.v("TitleAdapter - getItem=", String.valueOf(position));
return frags[position];
}
#Override
public int getCount() {
return frags.length;
}
}
Feel right from causing onCreate(Bundle savedInstanceState)
public class MainActivity extends FragmentActivity {
TitleAdapter titleAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.pager);
TitleAdapter titleAdapter = new TitleAdapter(getSupportFragmentManager());
mViewPager.setAdapter(titleAdapter);
mViewPager.setCurrentItem(1);
mViewPager.setOffscreenPageLimit(2);
FragmentManager fm = getSupportFragmentManager();
FragmentA fragment = (FragmentA)fm.findFragmentByTag("fragA");
fragment.bgStop();
Here the method itself
public class FragmentA extends Fragment {
final static String LOG_TAG = "myLogs";
static Button btnPlay;
public FragmentA() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_a, container, false);
btnPlay = (Button) rootView.findViewById(R.id.btnStart);
return rootView;
}
public void bgPlay(){
btnPlay.setText("Play");
btnPlay.setBackgroundResource(R.drawable.play_button);
}
public void bgStop(){
btnPlay.setText("Stop");
btnPlay.setBackgroundResource(R.drawable.stop_button);
}
}
There are so many problems with that code. Here, let me fix that for you.
The following is untested, just edited in my favourite text editor.
public class TitleAdapter extends FragmentPagerAdapter {
public final String titles[] = new String[] { "A", "B", "C" };
public final Fragment frags[] = new Fragment[titles.length];
public TitleAdapter(FragmentManager fm) {
super(fm);
// do not commit any fragments here, the adapter handles that.
frags[0] = new FragmentA();
frags[1] = new FragmentB();
frags[2] = new FragmentC();
}
#Override
public CharSequence getPageTitle(int position) {
Log.v("TitleAdapter - getPageTitle=", titles[position]);
return titles[position];
}
#Override
public Fragment getItem(int position) {
Log.v("TitleAdapter - getItem=", String.valueOf(position));
return frags[position];
}
#Override
public int getCount() {
return frags.length;
}
}
Then in the activity:
public class MainActivity extends FragmentActivity {
TitleAdapter titleAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.pager);
final TitleAdapter titleAdapter = new TitleAdapter(getSupportFragmentManager());
mViewPager.setAdapter(titleAdapter);
mViewPager.setCurrentItem(1);
mViewPager.setOffscreenPageLimit(2);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
Fragment fragment = titleAdapter.getItem(position);
// Ideally use some sort of interface here.
if (fragment instanceof FragmentA) {
((FragmentA) fragment).bgStop();
}
}
});
}
}

Android, How to mix ActionBar.Tab + View Pager + ListFragment

I've been trying to test how to mix all these things together and I'm having problems!!
I just want an app with three tabs using the ActionBar.Tab. For example, this tabs can be movies genres Action, Adventure and Animation, the user can swipe through the tabs, so it will use the ViewPager and each tab will show a list of movies of that genre. There's no need to have three different fragments classes because all tabs will be the same format a simple list.
And I'm having problems because when I select the second tab, the position for onPageSelected is 1,
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mCollectionPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
});
This causes the call to the method public Fragment getItem(int i) inside the CollectionPagerAdapter class, but then the value of i is 2 NOT 1, so then it calls the createView for the TabFragment class with a value of 2 NOT 1, so tabs are not refreshing successfully.
Any help will be really appreciated!!
Code to create the tabs,
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mCollectionPagerAdapter.getCount(); i++) {
mActionBar.addTab(mActionBar.newTab()
.setText(mGenres.get(i).getName())
.setTabListener(this));
//Let's request the movies for the first three genres
new GetMoviesByGenre().execute(mGenres.get(i).getId());
}
When a tab is selected,
#Override
public void onTabSelected(ActionBar.Tab tab, android.app.FragmentTransaction arg1) {
//Let's update the dataset for the selected genre
TabFragment fragment =
(TabFragment) getSupportFragmentManager().findFragmentByTag(
"android:switcher:"+R.id.pager+":"+tab.getPosition());
if(fragment != null) // could be null if not instantiated yet
{
if(fragment.getView() != null)
{
fragment.updateDisplay(tab.getPosition()); // do what updates are required
}
}
mViewPager.setCurrentItem(tab.getPosition());
}
CollectionPageAdapter class
public class CollectionPagerAdapter extends FragmentPagerAdapter {
final int NUM_ITEMS = 3; // number of tabs
List<Fragment> fragments = new ArrayList<Fragment>();
public Fragment getItem(int pos) {
return fragments.get(pos);
}
public void addFragment(Fragment f) {
fragments.add(f);
}
public CollectionPagerAdapter(FragmentManager fm) {
super(fm);
//Let's add the fragments
for (int i=0;i<NUM_ITEMS;i++)
{
Fragment fragment = new TabFragment();
Bundle args = new Bundle();
args.putInt(TabFragment.ARG_OBJECT, 0);
fragment.setArguments(args);
addFragment (fragment);
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
}
TabFragment class
public class TabFragment extends ListFragment {
public static final String ARG_OBJECT = "object";
private MoviesAdapter m_Adapter;
private ArrayList <Movie> mMovies = new ArrayList<Movie>();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// you only need to instantiate these the first time your fragment is
// created; then, the method above will do the rest
if (m_Adapter == null) {
m_Adapter = new MoviesAdapter(getActivity(), mMovies);
}
setListAdapter(m_Adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
int position = getArguments().getInt(ARG_OBJECT); // to check is the right fragment
View rootView = inflater.inflate(R.layout.tabs, container, false);
return rootView;
}
public void updateDisplay (int type)
{
GlobalVars gv = (GlobalVars)getActivity().getApplicationContext();
switch (type)
{
case 0:
mMovies = gv.getActionMovies();
break;
case 1:
mMovies = gv.getAdventureMovies();
break;
case 2:
mMovies = gv.getAnimationMovies();
break;
}
m_Adapter.notifyDataSetChanged();
}
}
I don't what I'm doing wrong, I guess that the fragments are messed up, because when I press the second tab, data from the first tab is updated, and so on ...
Thanks!
Instead of using CollectionPageAdapter, I changed to use the TabsAdapter class shown in Android documentation of ViewPager and it works!
public class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private final List<Fragment> fragments = new ArrayList<Fragment>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
Fragment fr = Fragment.instantiate(mContext, info.clss.getName(), info.args);
//addFragment (fr, position);
return fr;
}
public void addFragment(Fragment f, int location) {
if (fragments.size() == 0)
fragments.add(f);
else
fragments.add(location, f);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
updateDatasetMovies (i);
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
public void updateDatasetMovies (int pos)
{
//Let's update the dataset for the selected genre
TabFragment fragment =
(TabFragment) ((FragmentActivity)mContext).getSupportFragmentManager().findFragmentByTag(
"android:switcher:"+R.id.pager+":"+pos);
//TabFragment fragment = (TabFragment) getItem(pos);
if(fragment != null) // could be null if not instantiated yet
{
if(fragment.getView() != null)
{
// no need to call if fragment's onDestroyView()
//has since been called.
fragment.updateDisplay(pos); // do what updates are required
}
}
}
}`
I agree with nirvik on this, however there is one cruciual improvement that should be made. This implementation has one flaw - when swiping to a next fragment the onPageSelected method is invoked, which in turn invokes onTabSelected method by calling mActionBar.setSelectedNavigationItem(position);. This causes a flicker in the animation.
This:
viewPager.setCurrentItem(i);
should be replaced by this:
if(i != viewPager.getCurrentItem()) {
viewPager.setCurrentItem(i);
}
resulting in a smooth transition.
You can try including the following code in your FragmentPagerAdapter and see if this addresses the issue.
public int getItemPosition(Object object) {
return POSITION_NONE;
}
You could also try using a FragmentStatePagerAdapter.

Categories

Resources