I am working on a project with TabLayout.I have 20 tabs. I use one RecyclerView Adapter and Fragment. When I click any tabs I want recyclerview and fragment to change data. How can I do that in TabLayout's getItem function? Thanks.
I think you want to add an OnPageChangeListener on your ViewPager. You will be able to detect when you change your active tab.
I would suggest something like this :
private int lastPosition = -1;
viewPager.addOnPageChangeListener(new OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
public void onPageSelected(int position) {
if(position != lastPosition){
lastPosition = position;
// refresh recyclerview and fragment
}
}
});
Related
When I get a child view from items 0 to 2 in viewpager, it works fine. When I try to get a child view from 3 onward, it returns null. How can I get all the current selected child view of viewpager?
Edited:
View view = viewPager.getChildAt(viewPager.getCurrentItem());
When viewPager.getCurrentItem() reached 3 onward, the view return null.
You need to access the Fragments which you use in your ViewPager.
In this answer https://stackoverflow.com/a/39274141/1559852 i tried to explain how to modify your ViewPager's adapter o make the fragments which you use in your ViewPager accessible.
After you implemented the code in link, you'll be able to access your fragments and it's views.
Define a public method to your Fragments like below:
public View getMyFragmentView(){
return this.mView();
}
Finally add an OnPageChangeLsitener to your ViewPager like the following code.
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Here's your instance
final YourFragment fragment =(YourFragment)yourPagerAdapter.getRegisteredFragment(position);
final View theViewYouWantToAccess = yourFragment.getMyView();
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Edit: In your ViewPager adapter you can register the Fragment to SparseArray
#Override
public Fragment getItem(int position) {
final YourFragment fragment = new YourFragment();
// Register your fragment to Sparse Array here
registeredFragments.put(position, fragment);
return fragment;
}
I have implemented a viewpager adapter, the scrolling and contents returned works fine but the issue is, when I start my app, the screen is blank and only when I click anywhere on the blank screen does the viewpager load the first page (item 0) and everything else works fine after that. How can I get my app to load viewpager items without having to click first:
MainActivity:
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(new ViewPagerAdapter(getApplicationContext(), userid, names, status, phonenumbers, rates, urls, dobyear, dobmonth, dobday, starrate));
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
public void onPageSelected(int position) {
}
});
}
ViewPagerAdapter:
#Override
public int getCount() {
return this._userid.size();
}
#Override
public int getCount() {
return this._userid.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == (object);
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
ImageView imgDisplay, ivRateBar;
TextView tvName, tvPhoneNumber, tvRate, tvStatus, tvYear, tvDistance;
inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View viewLayout = inflater.inflate(R.layout.viewpager_item, container,false);
....
//set my textviews and imges
I tried:
private static int currentPage = 0;
public void onPageSelected(int position) {
currentPage = position;
}
OK, it works when I use a handler.postDelayedof half a second before setting my viewPager adapter, the logical reason behind this may be that the viewpager loads before all my data can be retrieved from the database.
After you get the data you are looking for try calling
myAdapter.notifyDataSetChanged();
You just have to save the Adapter instance like so:
// Change this
viewPager.setAdapter(new ViewPagerAdapter(getApplicationContext(), userid, names, status, phonenumbers, rates, urls, dobyear, dobmonth, dobday, starrate));
// To this
ViewPagerAdapter myAdapter = new ViewPagerAdapter(getApplicationContext(), userid, names, status, phonenumbers, rates, urls, dobyear, dobmonth, dobday, starrate);
viewPager.setAdapter(myAdapter);
...
// When the data is finished loading (wherever you load the data)
if (myAdapter != null) {
myAdapter.notifyDataSetChanged();
}
And the adapter should refresh itself with the correct data.
The only way worked for me:
if(viewPager.getAdapter()!=null){
viewPager.getAdapter().notifyDataSetChanged();
container.removeView(viewPager);
container.addView(viewPager);
}
I am working on an viewpager with previous and next page. What I need is to increase the text of the current page, after loading the page. But while I am trying, text on the next page is changing (I know that next and previous page load on viewpager). How can I get the focused on one selected page?
What I have done is,
viewPager.setClipChildren(false);
unfortunately it doesn't work..
I recommed using position parameter in activity and you can update text based on the position recieved.
This example is for Fragments though
#Override
public Fragment getItem(int position) {
return PageFragment.newInstance(position);
}
And in fragment you recieve this position as an argument:
public static PageFragment newInstance(int position) {
Bundle args = new Bundle();
args.putInt("position", position);
PageFragment page = new PageFragment();
page.setArguments(args);
return page;
}
In onCreateView you update your textview based on your position.
If you want to update TextView something like this:
TextView tv = (TextView) view.findViewById(R.id.yourId);
int position = getArguments().getInt("position");
tv.setText("This is page number: " + position);
i didn't really understand what you need but i think you may use this:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//Edit
if(position==int requiredPosition)
{
// resize your text
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
I have ViewPager with 3 Fragments. I just want to know is it possible to move elements (ImageView, TextView, e.t.c) in Fragment when user start to scroll the page and go to another page? What the best way to do that? Here below my code that I used before. I used it in my MainActivity. Only after test I understand that I am on the wrong way cause these code will work every time when user scroll. So is it possible to set it in Fragment?
My code that i used before in MainActivity:
#Override
public void transformPage(View page, float position) {
// transformation here
int pageWidth = page.getWidth();
ImageView mImageViewCloud = (ImageView) getView().findViewById(R.id.cloud);
ImageView mImageButterfly = (ImageView) getView().findViewById(R.id.butterfly);
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
page.setAlpha(0);
} else if (position <= 1) { // [-1,1]
if(mImageViewCloud!=null)mImageViewCloud.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth));
if(mImageButterfly!=null)mImageButterfly.setTranslationX((float) ((1 - position) * 1.5 * pageWidth));
// The 0.5, 1.5, 1.7 values you see here are what makes the view move in a different speed.
// The bigger the number, the faster the view will translate.
// The result float is preceded by a minus because the views travel in the opposite direction of the movement.
} else { // (1,+Infinity]
// This page is way off-screen to the right.
page.setAlpha(0);
}
}
Any help is appreciated. Thanks!
EDIT:
AdapterFragment.java
public abstract class AdapterFragment extends Fragment {
SparseArray<AdapterFragment> registeredFragments = new SparseArray<AdapterFragment>();
#Override
public Object instantiateItem(ViewGroup container, int position) {
AdapterFragment fragment = (AdapterFragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public void pass(int farFarAway) {
for(int i = 0, nSize = registeredFragments.size(); i < nSize; i++)
registeredFragments.valueAt(i).pass(farFarAway);
}
final int pageWidth = ViewPager.getMeasuredWidth(); //after ViewPager drawn, probably its also screen width
final int scrollRange = (AdapterFragment.getCount()-1)*pageWidth;
ViewPager.OnPageChangeListener OPCL = new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
float farFarAway=(float)(position*pageWidth+positionOffsetPixels), scrollToFactor = farFarAway/scrollRange;
AdapterFragment.pass(farFarAway);
}
#Override
public void onPageScrollStateChanged(int state) {
}
};
}
have you tried ViewPager.OnPageChangeListener? there is a method in this interface onPageScrolled(int position, float positionOffset, int positionOffsetPixels), last two variables might be useful for your purposes - pass move offset to all Fragments, inside of them move Views
edit:
final int pageWidth=mainViewPager.getMeasuredWidth(); //after ViewPager drawn, probably its also screen width
final int scrollRange = (viewPagerCustomAdapter.getCount()-1)*pageWidth;
OnPageChangeListener onpcl = new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
float farFarAway=(float)(position*pageWidth+positionOffsetPixels),
scrollToFactor = farFarAway/scrollRange;
viewPagerCustomAdapter.pass(farFarAway);
}
#Override
public void onPageScrollStateChanged(int state) {
}
};
viewPagerCustomAdapter is an adapter dispatching farFarAway - how much distance ViewPager is moved starting left edge of 0 position Fragment. how to dispatch moved value to currently existing Fragments? - check this and create for loop over all registered fragments inside adapter's pass(int farFarAway). inside each Fragment you may calculate proper value for setTranslationX. you may also pass and use scrollToFactor (0.0-1.0) and position, these might be useful. e.g. position might determine if you are on current or next Fragment. note that default ViewPager memory is set to one, so there can't be more than 3 registered Fragments at once (current+both next)
edit 2:
create new class and extend all your Fragments used in your adapter
public abstract class AdapterFragment extends Fragment{
public abstract pass(int farFarAway);
}
add these lines to your adapter:
SparseArray<AdapterFragment> registeredFragments = new SparseArray<AdapterFragment>();
#Override
public Object instantiateItem(ViewGroup container, int position) {
AdapterFragment fragment = (AdapterFragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public void pass(int farFarAway) {
for(int i = 0, nsize = registeredFragments.size(); i < nsize; i++)
registeredFragments.valueAt(i).pass(farFarAway);
}
set above OnPageChangeListener for your ViewPager. In this way every Fragment gets current scroll position. so an example of use in one of your Fragments
public void pass(int farFarAway){
imageView.setTranslationX(farFarAway/10); //sample value 10, farFarAway is too big value for moving any View
}
your ImageView should move when while swiping ViewPager, adjust as you want. This whole post is almost full solution, should be useful...
PS. code not tested, might be some syntax or other bugs
Try reading about Fragment shared elements. Perhaps this is what you are looking for.
I am a newbie in Android programming and this is my first question on this site. I have spent lots of time searching for this issue but haven't find an answer that suit my case.
I had two pages in ViewPager, one for the current, one for the next page. When the second fragment shows, I set its index to 0, remove the first one and create a new fragment as a replacement for the second. Here is my code.
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int pageSelected) {
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == 1) {
currentQuestFr = nextQuestFr;
nextQuestFr = newQuest();
mPager.setCurrentItem(0, false);
mPagerAdapter.notifyDataSetChanged();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
And the Adapter
private class QuestPagerAdapter extends FragmentStatePagerAdapter {
public QuestPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if (position == 0) return currentQuestFr;
else return nextQuestFr;
}
#Override
public int getCount() {
return NUM_PAGES;
}
#Override
public int getItemPosition(Object object)
{
return POSITION_NONE;
}
}
The code works well, but notifyDataSetChanged() seems to refresh my View with no need of that. It annoys users a little. Is there any way to refresh the Adapter without redraw the view, or other way to reach the same purpose?
Thanks very much
Do you want it to work in a way that it should load all data initially and then manually redraw the view on some event? Then you can use
mPager.setOffscreenPageLimit(n)
where n is your number of pages in mPager. This will draw all the pages on loading.