I have a ViewPager with a FragmentPageAdapter. When a fragment is displayed, I want it to start an animation (fade-in a view in the fragment).
However, the animation runs inconsistently, it runs on every few pages when I swipe left/right. I think I need to start the animation on the onPageSelected event but I can't figure out how to get the fragment and start the animation.
My code is below. TourFragment is the fragment I add to the ViewPager using the FragmentPageAdapter while TourActivty contains the ViewPager.
TourFragment
public class TourFragment extends Fragment {
Tour tour;
ImageView ivTitle;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_tour,
container, false);
RelativeLayout rlImageContainer = (RelativeLayout) v.findViewById(R.id.tour_image_container);
Resources resources = getActivity().getResources();
ivTitle = (ImageView) v.findViewById(R.id.tour_title);
ivTitle.setImageDrawable(resources.getDrawable(tour.getDrawableTitleId()));
Animation fadeInAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.fadein);
ivTitle.startAnimation(fadeInAnimation );
return v;
}
#Override
public void onResume() {
super.onResume();
Animation fadeInAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.fadein);
ivTitle.startAnimation(fadeInAnimation );
}
public static Fragment newInstance(Tour tour) {
TourFragment f = new TourFragment();
f.tour = tour;
return f;
}
}
TourActivity
public class TourActivity extends FragmentActivity {
MyPageAdapter pageAdapter;
String tourType;
Drawable drawableSelected;
Drawable drawableNotSelected;
LinearLayout llIndicators;
int prevPagePosition = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tour);
List<Fragment> fragments = getFragments();
pageAdapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(pageAdapter);
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
}
private List<Fragment> getFragments(){
List<Fragment> fList = new ArrayList<Fragment>();
List<Tour> tours = new ArrayList<Tour>();
messages = getResources().getStringArray(R.array.guess_tour_messages);
Tour tour = new Tour();
tour.setDrawableImageId(R.drawable.tu_guest_image_1);
tour.setDrawableTitleId(R.drawable.tu_guest_text_1);
tour.setMessage(messages[0]);
tour.setPageIndex(0);
tour.setTotalPages(messages.length);
tours.add(tour);
tour = new Tour();
tour.setDrawableImageId(R.drawable.tu_guest_image_2);
tour.setDrawableTitleId(R.drawable.tu_guest_text_2);
tour.setMessage(messages[1]);
tour.setPageIndex(1);
tour.setTotalPages(messages.length);
tours.add(tour);
tour = new Tour();
tour.setDrawableImageId(R.drawable.tu_guest_image_3);
tour.setDrawableTitleId(R.drawable.tu_guest_text_3);
tour.setMessage(messages[2]);
tour.setPageIndex(2);
tour.setTotalPages(messages.length);
tours.add(tour);
tour = new Tour();
tour.setDrawableImageId(R.drawable.tu_guest_image_4);
tour.setDrawableTitleId(R.drawable.tu_guest_text_4);
tour.setMessage(messages[3]);
tour.setPageIndex(3);
tour.setTotalPages(messages.length);
tours.add(tour);
for (Tour tour : tours) {
fList.add(TourFragment.newInstance(tour));
}
return fList;
}
}
class MyPageAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
You should use in your fragment
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
Log.v(TAG, "run now");
Animation animationFadeIn = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_view);
iv.startAnimation(animationFadeIn);
animationFadeIn.setFillAfter(true);
}
else { }
}
I figured it out.
On onPageSelected, I used getView from the fragment to get the view that I want to animate.
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int position) {
View v = pageAdapter.getItem(position).getView();
ImageView ivTitle = (ImageView) v.findViewById(R.id.tour_title);
Animation fadeInAnimation = AnimationUtils.loadAnimation(TourActivity.this, R.anim.fadein);
ivTitle.startAnimation(fadeInAnimation );
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
Inside of your FragmentPagerAdapter implementation you you need to override public Object instantiateItem(viewGroup container, int index). In the base class fragments are only added with a FragmentManager instance when the adapter is first created. Whenever you page away the offscreen fragments are detached but not removed. The FragmentManager caches the instances with a tag on the object. They are then attached when they are paged back to. The default implementation of instantiateItem item tags each Fragment inside of the FragmentAdapter with a hardcoded tag. You need to tag each Fragment you use with a unique tag. With this is place you can retrieve fragment instances from any FragmentManager instance in your app with public abstract Fragment findFragmentByTag (String tag).
String[] tags = {"tag1", "tag2", "tag3", "tag4", "tag5"};
#Override
public Object instantiateItem(ViewGroup container, int index) {
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = fm.findFragmentByTag(tags[index]);
if (fragment == null) {
fragment = getItem(index);
ft.add(container.getId(), fragment, mTags[index]);
}
else {
ft.attach(fragment);
}
ft.commit();
return fragment;
}
public String getTag(int index) {
return mTags[index];
}
You should be able to access the the instances in onPageSelected now.
I had a similar problem and here what solved it:
Animation of nested fragment within ViewPager fragment is triggered before render
In context of your case the same solution would look like this:
java:
v.post(new Runnable() {
#Override
public void run() {
ivTitle.startAnimation(fadeInAnimation)
}
})
kotlin:
v.post(Runnable {
ivTitle.startAnimation(fadeInAnimation)
})
It ensures that the view is indeed drawn
Related
I'm using a Fragment on my Activity that will have a picture "swiper". I've created a FragmentStatePagerAdapter which I'm trying to call from this Fragment and for some reason my getItem() method is never being called.
I've searched and found that I need to use getChildFragmentManager() when instantiating my FragmentStatePagerAdapter because I'm calling it from a Fragment. I've tried this as well as getSupportFragmentManager() with no luck from either.
Any ideas?
here's my Fragment that I'm using on my MainActivity with the method that shoudl setup the FragmentStatePagerAdapter:
public class PhotoFlipper extends Fragment {
// properties and fields
// primitive types
String currentImage;
int friendShareType = 0;
ImageView share;
ViewPager pager;
PhotoFlipperItemAdapter pagerAdapter;
LatLng itemPosition;
Activity activity;
FragmentActivity fragActivity;
public ArrayList<MarkerModel> picsAndVids;
// end properties and fields
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View photoFlipperFragmentView = inflater.inflate(R.layout.photo_flipper_layout, container, false);
InitializeFragment(photoFlipperFragmentView);
return photoFlipperFragmentView;
}
private void InitializeFragment(View photoFlipperFragmentView) {
activity = getActivity();
fragActivity = (FragmentActivity)activity;
pager = (ViewPager)photoFlipperFragmentView.findViewById(R.id.photoflipper_pager);
share = (ImageView)photoFlipperFragmentView.findViewById(R.id.photoflipper_share);
share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
IPictureFlipper iPictureFlipper = (IPictureFlipper)activity;
iPictureFlipper.ShareVideoOrImage(friendShareType, itemPosition, currentImage);
}
});
}
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
pager.setVisibility(View.GONE);
}
}
public void SetTappedPicture(int index) {
pagerAdapter = new PhotoFlipperItemAdapter(getChildFragmentManager(), picsAndVids, picsAndVids.size());
pager.setAdapter(pagerAdapter);
pager.setCurrentItem(index);
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
}
});
}
}
And here's my FragmentStatePagerAdapter:
public class PhotoFlipperItemAdapter extends FragmentStatePagerAdapter {
ArrayList<MarkerModel> _markers;
int NUM_PAGES;
String TAG = "home";
public PhotoFlipperItemAdapter(FragmentManager fm, ArrayList<MarkerModel> markers, int numpages){
super(fm);
Log.d(TAG,"in adapter in constructor");
_markers = markers;
NUM_PAGES = numpages;
}
#Override
public Fragment getItem(int position) {
Log.d(TAG,"in adapter in get item");
Fragment fragment = PhotoFlipperItemFragment.create(position, _markers);
return fragment;
}
#Override
public int getCount() {
Log.d(TAG,"in adapter in get count: "+NUM_PAGES);
return NUM_PAGES;
}
}
logcat is showing me that NUM_PAGES is > 0 so that's not my issue. I see my log in the constructor and in getCount() but nothing in getItem().
TIA
I got this sorted out. I was hiding my fragment in my InitializeActivity() right after I added it to my FragmentManager so it was never fully building the Fragment with the ViewPager etc.
I'm going to have to come up with a different solution for hiding/showing the fragment but that was my problem.
I want to get the hidden value which is set in Fragment Page in order to work on it. I am setting the hidden value in Fragment Page and want to get that hidden value in the activity page's Viewpager onPageSelected value in oreder to update the fragment with detail information. Is this possible?
My Fragment page
public class CountryFragment extends Fragment {
public static final String STARTUP_ID = "startupID";
private String st_id;
public CountryFragment() {
// emtpy
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String st_id = getArguments().getString(STARTUP_ID);
this.st_id = st_id;
View v = inflater.inflate(R.layout.country_fragment, container, false);
TextView hiddenstatupid= (TextView) v.findViewById(R.id.hiddenstatuptextview);
hiddenstatupid.setText(st_id);
return v;
}
}
Activity Page
public class IndividualPage extends ActionBarActivity{
ViewPager pager;
#Override
public void onCreate (Bundle savedInstanceState)
{
pager = (ViewPager)findViewById(R.id.viewpager);
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//here is where i need to get the hidden id of startup which is in the countryfragment
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
My CountryPageAdapter
public class CountryPageAdapter extends FragmentPagerAdapter {
public CountryPageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
mFragmentTags = new HashMap<Integer, String>();
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
}
Iy your CountryFragment part of the viewpager? If so, then you can have a local store of your fragments in your pager adapter and then get the fragment from the viewpager adapter using the position.
If your adapter extends FragmentStatePagerAdapter you have to implement the getItem() method.
You will have something like this:
#Override
public void onPageSelected(int position) {
CountryFragment frag = pager.getAdapter().getItem(position);
}
Hope this helps.
I'm trying to start an animation when the fragment is showed on screen(I'm working with a ViewPager).
This a part of my code
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
mFragmentManager = fm;
mFragmentTags = new HashMap<Integer, String>();
}
public ScreenSlidePageFragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return (ScreenSlidePageFragment) mFragmentManager.findFragmentByTag(tag);
}
#Override
public Fragment getItem(int position) {
return ScreenSlidePageFragment.create(position);
}
#Override
public int getCount() {
return NUM_PAGES;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
// record the fragment tag here.
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
System.out.println("holi");
}
return obj;
}
}
public class ScreenSlideActivity extends FragmentActivity {
(...)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
// Instantiate a ViewPager and a PagerAdapter.
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
(...)
SimpleOnPageChangeListener mPageChangelistener = new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When changing pages, reset the action bar actions since they are dependent
// on which page is currently active. An alternative approach is to have each
// fragment expose actions itself (rather than the activity exposing actions),
// but for simplicity, the activity provides the actions in this sample.
ScreenSlidePageFragment currentFgm = mPagerAdapter.getFragment(position);
Animation animacion = AnimationUtils.loadAnimation(ScreenSlideActivity.this, R.anim.glasses);
currentFgm.getView().findViewById(R.id.image).startAnimation(animacion);
invalidateOptionsMenu();
}
(...)
The problem is when onPageSelected is called returns a NullPointer Exception in
currentFgm.getView().findViewById(R.id.image).startAnimation(animacion);
How could I start the animation when the fragment is showed on screen?
If you are trying to add animation to the ViewPager then you can implement the ViewPager.PageTransformer interface and supply it to the view pager to display a different animation than the default screen slide animation.
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
...
mPager.setPageTransformer(true, new CustomTransformer());
You will find here two examples of PagerTransformers.
I have problem with FragmentPagerAdapter ,I have set fragments in viewpager through FragmentPagerAdapter,
I have to show viewpager dynamically,I have listview data , which I need to show in viewpager,
when I click on the listview , I have to load exact position in the viewpager
so i just set the total size of the item to show in FragmentPagerAdapter, But the problem is that when I select the viewpager position through mPager.setCurrentItem(listposition) it show correct position of the viewpager,
but the data load at wrong place, it load in next fragement in viewpager position,after some tracking in FragmentPagerAdapter, I show that instantiateItem method initailize one fragment in advance, like i set the currentitem (from listview)of viewpager 2
then instantiateItem method initalize 0 to 3 fragment, I think that the reason the data load in 3rd fragment,I tried a lot with FragmentStatePagerAdapter also but no any success , please help me , thanks in advance.
Mainactivity class(Fragmnetactivity) :
public class NewsDetail extends FragmentActivity implements OnClickListener {
public static ViewPager mPager;
private static int NUM_PAGES;
private PagerAdapter mPagerAdapter;
public static ArrayList<Integer> exist_detail = new ArrayList<Integer>();
public static ArrayList<PageFragment> detailfragment = new ArrayList<PageFragment>();
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
NUM_PAGES = topList.size();
PageFragment fragment = new PageFragment();
Bundle args = new Bundle();
args.putInt("page", i);
fragment.setArguments(args);
detailfragment.add(fragment);
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
if (PageFragment.getInstance() != null) {
Log.d("LOG","PageFragment || "+ PageFragment.getInstance());
PageFragment.getInstance().startLoadingNews(
MusicList.topMusicList.get(arg0)._id);
}
return;
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
#Override
public void onPageScrollStateChanged(int arg0) {}
});
mPagerAdapter.notifyDataSetChanged();
mPager.setCurrentItem(listposition);// setcurrent item from here , it is selected from list. "listposition" indicate list position click
private class ScreenSlidePagerAdapter extends FragmentPagerAdapter {
private FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
private Fragment mCurrentPrimaryItem = null;
private static final boolean DEBUG = false;
public ScreenSlidePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
this.mFragmentManager = fragmentManager;
}
#Override
public Fragment getItem(int position) {
return detailfragment.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return super.getItemId(position);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.v("LOG", "On InstantiateItem " + position);// it indicate that this method initialize one fragment in advance.
return super.instantiateItem(container, position);
}
public String makeFragmentName(int viewId, long index) {
return "android:switcher:" + viewId + ":" + index;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG)
Log.e("LOG", "Detaching item #" + position + ": f=" + object
+ " v=" + ((Fragment) object).getView());
mCurTransaction.detach((Fragment) object);
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
PageFragment
public class PageFragment extends Fragment implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = getArguments().getInt(ARG_PAGE);
mDetailPageFragment = this;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout containing a title and body text.
rootView = (ViewGroup) inflater.inflate(R.layout.newsdetail, container,
false);
//init();
return rootView;
}
public void startLoadingNews(String _id) {
if (NetworkUtil.cheackNetwork(mActivity)) {
executeTask(_id);
} else {
showRetryCancelDialog();
}
}
}
I can see two issues in the code you've posted:
Only instantiate your fragments in FragmentPagerAdapter.getItem. Don't instantiate them and save them to some list or array, let the FragmentPagerAdapter do that for you. In FragmentPagerAdapter.instantiateItem it checks if the Fragment was already created and if so it returns it, if not, it'll call your getItem to create the fragment.
Don't use the Singleton scheme for your fragment, create a new fragment using a constructor or a .newInstance() static helper.
I have an application that Implements ActionBarSherlock, it's mainly composed of
ViewPager with different content of fragments (for each page), with ViewPager indicator.
Here is my onCreate Method of the Activity that extends SherlockFragmentActivity
// Assume that tabs,sources,types are string arrays e.g. tabs = ["tab1","tab2","tab3"]
// types = ["listview","listview","webview"]
// according to the type of each tab, the type of content of the fragment associated to that tab is determined (e.g. WebView or ListView)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.main);
srcContext = getBaseContext();
srcActivity = SaudiActivity.this;
int selectPos = 0;
Intent sender = getIntent();
FragmentPagerAdapter mAdapter = new NewsListAdapter(
getSupportFragmentManager());
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(mAdapter);
TabPageIndicator indicator = (TabPageIndicator) findViewById(R.id.indicator);
indicator.setViewPager(pager);
pager.setOffscreenPageLimit(tabs.length);
pager.setCurrentItem((tabs.length - 1));
currentPosition = (tabs.length - 1);
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
currentPosition = position;
if ((type[position] == "listview" || type[position]
.equals("listview")) && loaded[position] == false) {
loaded[position] = true;
getNews(listViews[position], position);
}
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
getSupportActionBar().setCustomView(R.layout.logo);
getSupportActionBar().setDisplayShowCustomEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayShowHomeEnabled(false);
Context ctx = getSupportActionBar().getThemedContext();
SourcesAdapter adapter = new SourcesAdapter(ctx,
R.layout.navigation_list_item, src_name, icons, src_value);
}
Here are my News List Adapter (that creates the fragments),
public static class MyViewHolder {
public TextView title;
public ImageView icon;
}
class NewsListAdapter extends FragmentPagerAdapter {
public NewsListAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return new NewsFragment(MyActivity.this, position);
}
// This is the number of pages -- 5
#Override
public int getCount() {
return tabs.length;
}
// This is the title of the page that will apppear on the "tab"
public CharSequence getPageTitle(int position) {
return tabs[position];
}
}
public List<NewsItem> NewsItems;
Finally here's my NewsFragment:
public static class NewsFragment extends Fragment {
private int position;
public NewsFragment() {
}
public NewsFragment(Context ctx, int pos) {
this.position = pos;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = null;
if (type[position].equals("listview")) {
// Put a ListView in the Fragment
} else {
// Put a WebView in the Fragment
}
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
}
Let the fragment handle it's state by overriding onSaveInstanceState and placing the necessary values into outState. Recover that state in onCreateView using savedInstanceState. Also I'm pretty sure that if you're using Actionbarsherlock fragments need to extend SherlockFragment rather than Fragment.