In the CustomPagerAdapter of the ViewPager, in instantiateItem() method I'm trying to create an TextView and then for each page set a different text depending on certain condition. Text is read from a pages Cursor. Here is a code:
#Override
public Object instantiateItem(ViewGroup collection, int position) {
sc = new ScrollView(context);
sc.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
sc.setFillViewport(true);
tv = new TextView(context);
if(position < count) {
tv.setText(pages.getString(1));
pages.moveToPosition(position);
}else {
tv.setText("LOCKED");
}
tv.setTag(TAG_PAGE + position);
tv.setGravity(Gravity.CENTER);
tv.setTextColor(Color.BLACK);
tv.setTextSize(30);
sc.addView(tv);
((ViewPager) collection).addView(sc);
return sc;
}
However ViewPager behaves not as expected. The first and the second page have the same text, rest of the pages has a sign "LOCKED" as expected. When I swipe into the 4th page and come back to the first page then the first page consists of the text that suppose to be in the second page. I also tried to use myViewPager.setOffscreenPageLimit(numberOfPages) however it doesn't help.
I found this answer:
"Inside of instantiateItem, the position parameter is the position that is in need of rendering. It is NOT the position of the currently focused item that the user would see. The pages to the left and right of the currently displayed view need to be pre rendered in memory so that the animations to those screens will be smooth. "
It make sense to me but how then can I correctly display the pages content and then update it if desired? Please advise if there is different way to do it with skipping instantiateItem() method that introduce the mess and confusion into the problem. Thank you.
I have solved this problem by using a different implementation:
// Adapter class
private static class MyFragmentPagerAdapter extends FragmentPagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
return PageFragment.newInstance(pages[index]); // Pages is an array of Strings
}
#Override
public int getCount() {
return numberOfPages;
}
}
// PageFragment class
public class PageFragment extends Fragment {
TextView tv;
public static PageFragment newInstance(String page) {
PageFragment pageFragment = new PageFragment();
Bundle bundle = new Bundle();
bundle.putString("pageContent", page);
pageFragment.setArguments(bundle);
return pageFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);
tv = (TextView) view.findViewById(R.id.text_view);
tv.setText(getArguments().getString("pageContent"));
return view;
}
}
You can Create ViewPager Object and then set Listener onthis object.
ViewPager myPager = (ViewPager) findViewById(R.id.yourPagerid);
myPager.setAdapter(adapter);
myPager.setCurrentItem(0);
myPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
//You can change textview word according to current page
switch (position) {
case 0:
break;
case 1:
break;
case 2:
break;
}
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// Log.d("check","onPageScrolled");
}
#Override
public void onPageScrollStateChanged(int arg0) {
// Log.d("check","onPageScrollStateChanged");
}
});
Related
I am currently using Material Design in an Android app that I am making. In this app, I am using the Material Design tab layout to display some information that I am receiving. However when I tap the tabs, the animation is not smooth, and it is very abrupt. Sliding to go to the other tab, however is very smooth.
mTabLayout = (TabLayout) findViewById(R.id.chem_tab_layout);
mGenericAdapter = new GenericPagerAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.view_pager);
mPager.setAdapter(mGenericAdapter);
//Notice how the Tab Layout links with the Pager Adapter
mTabLayout.setTabsFromPagerAdapter(mGenericAdapter);
//Notice how The Tab Layout and View Pager object are linked
mTabLayout.setupWithViewPager(mPager);
mPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout){
#Override
public void onPageSelected(int position) {
mGenericAdapter.notifyDataSetChanged();
}
});
That is my code for setting the adapter, etc.
This is my custom adapter code for the tabs:
class GenericPagerAdapter extends FragmentStatePagerAdapter {
public GenericPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
ChemGridActivity.MyFragment myFragment = new ChemGridActivity.MyFragment();
return myFragment;
}
#Override
public int getCount() {
return 3; //returns number of tabs that need to be created
}
#Override
public CharSequence getPageTitle(int position) {
if (position == 0) return "Chemistry";
if (position == 1) return "Mathematics";
if (position == 2) return "Physics";
else return null;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
I feel that the choppy transition between tabs is caused by the overriden method onPageSelected method when I add onPageChangeListener. What do I add to this method to make tapping on tabs a smoother animation?
Without knowing much about the internals of your classes, I imagine the problem is not that you have a listener, but what you are doing inside that listener.
In the case of most adapters notifyDataSetChanged() will cause it to re-render the entire view again (including all pages).
Seeing as you haven't specified what the intent here with the notification is, it's hard to tell you how you can do this in an alternative way, but you do need to do something less intensive if you want the animation to remain smooth.
I suspect you just want to change which fragment is shown, in which case just use the FragmentManager where necessary, remembering to reuse fragments which have already been seen once.
EDIT Based on additional info in comments
#Override
public Fragment getItem(int position) {
//POSITION_SOMETHINHG would be one of a set of constants to indicate hwa to display
return ChemGridActivity.MyFragment.newInstance(ChemGridActivity.MyFragment.POSITION_SOMETHINHG);
}
public class ChemGridActivity.MyFragment ... {
private static final String KEY_DISPLAY_TYPE = "KEY_DISPLAY_TYPE";
public static final int POSITION_SOMETHINHG = 11111;
public static MyFragment newInstance(int display) {
MyFragment f = new MyFragment();
Bundle bund = new Bundle();
bund.putInt(KEY_DISPLAY_TYPE, display);
f.setArguments(bund);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mDisplay = args.getInt(KEY_DISPLAY_TYPE, 0);
}
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.my_layout, container, false);
//TODO: change something based on mDisplay
return view;
}
I have created two fragments in a ViewPager , when I click on first one , Second fragment is taking the click.
This issue puts me in another position, when I create two instance from same fragment but with different data.
{
#Override
public Fragment getItem(int index) {
switch (index) {
case 1:
return FragmentBrandList.getInstance(tabs.getBrandList2(), 19,
title);
case 0:
return FragmentBrandList.getInstance(tabs.getBrandList1(), 19,
title);
}
return null;
}
#Override
public int getCount() {
return 2;
}
}
After creating ViewPager , both the fragments get created correctly , but when I click on any thing in the first fragment , the click event gets fired in second fragment not in the first fragment.
EDIT
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 1:
return FragmentBrandList.getInstance(tabs.getBrandList2(), 19,
title);
case 0:
return FragmentBrandList.getInstance(tabs.getBrandList1(), 19,
title);
}
return null;
}
#Override
public int getCount() {
return 2;
}
in FragmentBrandList
public class FragmentBrandList extends Fragment {
ArrayList<Brand> brandList = new ArrayList<Brand>();
int discoverID;
RecyclerView listView;
LinearLayoutManager mLayoutManager;
public static FragmentBrandList getInstance(ArrayList<Brand> brandList,
int discoverID, String title) {
FragmentBrandList frag = new FragmentBrandList();
Bundle b = new Bundle();
b.putSerializable("brandList", brandList);
b.putInt("discoverID", discoverID);
b.putString("title", title);
frag.setArguments(b);
return frag;
}
public FragmentBrandList() {
}
String title = "";
View v;
boolean isInflated = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (v == null) {
v = inflater.inflate(R.layout.fragment_list_view_brownbg,
container, false);
isInflated = true;
} else {
isInflated = false;
((ViewGroup) v.getParent()).removeView(v);
}
return v;
}
MainActivity activity;
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (isInflated) {
activity = (MainActivity) getActivity();
initView();
}
}
public void initView(){
title = getArguments().getString("title");
discoverID = getArguments().getInt("discoverID");
listView = (RecyclerView) v.findViewById(R.id.listView);
mLayoutManager = new LinearLayoutManager(getActivity());
listView.setItemAnimator(new DefaultItemAnimator());
listView.setHasFixedSize(true);
listView.setLayoutManager(mLayoutManager);
listView.setAdapter(new BrandListRecAdapter(getActivity(),
R.layout.single_item_listview, brandList));
}
#Override
public void onResume() {
// handle on click
((BrandListRecAdapter) listView.getAdapter())
.setOnItemClickListener(new ItemClickListener() {
#Override
public void onItemClickListener(final int pos, View v) {
activity.replaceCurrentFragment(
FragmentBrandDetails.getInstance(
brandList.get(pos), "bank"), true,
true);
}}
EDIT
i think problem cause
when create second fragment , listview.onclick is overwrite first one !!
how can solve this peb?
EDIT
thank you to every one try to help me
problem is already because i use same adapter and same fragment
when second fragment created it is overwrite on item click
so when click in item is called second one !!!
Just put this android:clickable="true" in every fragment layout, and this will not happen again.
This is just an educated guess, but because a ViewPager will always create at least one extra Fragment on either side of the currently visible fragment, you may be creating two virtually identical Fragments in parallel, assigning them both onItemClickListeners in onResume and as such they are both responding to item clicks when an item is pressed on either Fragment.
You could try moving the onItemClickListener to the ViewHolder in your Adapter, rather assigning it in onResume. In addition, I wonder what a Brand object looks like in your RecyclerView, and whether it wouldn't be simpler to pass the current ViewPager page as a parameter in getInstance, and use this to access an Array containing the information necessary to fill your RecyclerView rows.
Here is a very brief example of how your ViewHolder may look:
class MyRecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
public MyRecyclerViewHolder(View itemView) {
itemView.setOnClickListener(this);
//etc.
I have seen a lot of answered questions about this, but none about what I exactly want so here it goes (if there's an answered thread about this I'd appreciate it):
I want to create a kind of "level selection" app, where you basically have to swipe from right to left in order to be able to see the next list of levels, however I want to do it WITHOUT tabs (haven't found out how to do it yet).
Thanks.
EDIT: Solved it by simply using a ViewPager without even bothering or paying attention to the ActionBar part Android tells you to add (I just created my few fragments, my viewpager, and this last one did the rest, didn't even need to use a gesture detector for swipes as viewpager already provides this animation).
Any ViewPager Tutorial teaching you how to swipe between tabs basically has all the information I needed :) Thanks everyone!
For doing this you shiuld use ViewPager
Its easy !
Layout ViewPager
<android.support.v4.view.ViewPager
android:id="#+id/vpPager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
Define Fragments
public class FirstFragment extends Fragment {
// Store instance variables
private String title;
private int page;
// newInstance constructor for creating fragment with arguments
public static FirstFragment newInstance(int page, String title) {
FirstFragment fragmentFirst = new FirstFragment();
Bundle args = new Bundle();
args.putInt("someInt", page);
args.putString("someTitle", title);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
// Store instance variables based on arguments passed
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
title = getArguments().getString("someTitle");
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_first, container, false);
TextView tvLabel = (TextView) view.findViewById(R.id.tvLabel);
tvLabel.setText(page + " -- " + title);
return view;
}
}
Setup FragmentPagerAdapter
public class MainActivity extends FragmentActivity {
// ...
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return FirstFragment.newInstance(0, "Page # 1");
case 1: // Fragment # 0 - This will show FirstFragment different title
return FirstFragment.newInstance(1, "Page # 2");
case 2: // Fragment # 1 - This will show SecondFragment
return SecondFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
}
Apply the Adapter
public class MainActivity extends FragmentActivity {
FragmentPagerAdapter adapterViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ViewPager vpPager = (ViewPager) findViewById(R.id.vpPager);
adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
vpPager.setAdapter(adapterViewPager);
}
// ...
}
Setup OnPageChangeListener
// Attach the page change listener inside the activity
vpPager.setOnPageChangeListener(new OnPageChangeListener() {
// This method will be invoked when a new page becomes selected.
#Override
public void onPageSelected(int position) {
Toast.makeText(HomeActivity.this,
"Selected page position: " + position, Toast.LENGTH_SHORT).show();
}
// This method will be invoked when the current page is scrolled
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Code goes here
}
// Called when the scroll state changes:
// SCROLL_STATE_IDLE, SCROLL_STATE_DRAGGING, SCROLL_STATE_SETTLING
#Override
public void onPageScrollStateChanged(int state) {
// Code goes here
}
});
if you need more info see this link (it also explain how to use tabs) :
https://github.com/codepath/android_guides/wiki/ViewPager-with-FragmentPagerAdapter
You have to use HorizontalScrollView (http://developer.android.com/reference/android/widget/HorizontalScrollView.html) which will manage horizontall scroll by himself. Juste place other view inside and you're good.
Edit: Solved it by simply using a ViewPager without even bothering or paying attention to the ActionBar part Android tells you to add (I just created my few fragments, my viewpager, and this last one did the rest, didn't even need to use a gesture detector for swipes as viewpager already provides this animation).
Any ViewPager Tutorial teaching you how to swipe between tabs basically has all the information I needed :) Thanks everyone!
I am using PagerSlidingTab Library for ViewPager. And I want to change Fragment while scrolling of tabs. It is working fine. Check out my code.
I am using AsynTask() on each Fragment.
When the App opens with the MainActivity, First Fragment is attached to the activity, But It shows two AsynTask() dialog message, one from First and another from Second Fragment. And When I scroll to second tab, It shows dialog message of Third Fragment.
So, If I scroll from left to right in tabs, the Fragment right to the current fragment is displayed and if i scroll from right to left, the Fragment left to the current Fragment is displayed.
Please help me to solve the problem.
My Code:
public class PageSlidingTabStripFragment extends Fragment {
public static final String TAG = PageSlidingTabStripFragment.class
.getSimpleName();
public static PageSlidingTabStripFragment newInstance() {
return new PageSlidingTabStripFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.pager, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) view
.findViewById(R.id.tabs);
ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
MyPagerAdapter adapter = new MyPagerAdapter(getChildFragmentManager());
pager.setAdapter(adapter);
tabs.setViewPager(pager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
private final String[] TITLES = { "Instant Opportunity", "Events",
"Experts" };
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new InstantOpportunity();
case 1:
return new Events();
case 2:
return new Experts();
default:
break;
}
return null;
}
}
}
Explanation:
It turns out there is an easier implementation for scrollable tabs which doesn't involve another library. You can easily implement tabs into your app using normal Android code straight from the default SDK.
The Code
Main Class:
public class PageSlidingTabStripFragment extends Fragment {
//Variables
private ViewPager viewPager;
private PagerTitleStrip pagerTitleStrip;
public PageSlidingTabStripFragment() {
// Required empty public constructor
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Find your pager declared in XML
viewPager = (ViewPager) getView().findViewById(R.id.pager);
//Set the viewPager to a new adapter (see below)
viewPager.setAdapter(new MyAdapter(getFragmentManager()));
//If your doing scrollable tabs as opposed to fix tabs,
//you need to find a pagerTitleStrip that is declared in XML
//just like the pager
pagerTitleStrip = (PagerTitleStrip)
getView().findViewById(R.id.pager_title_strip);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.[your layout name here], container, false);
}
}
Adapter:
//Note: this can go below all of the previous code. Just make sure it's
//below the last curly bracket in your file!
class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
Fragment fragment = null;
if (arg0 == 0) {
fragment = new InstantOpportunity();
}
if (arg0 == 1) {
fragment = new Events();
}
if (arg0 == 2) {
fragment = new Experts();
}
return fragment;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
if (position == 0) {
return "Instant Opportunity";
}
if (position == 1) {
return "Events";
}
if (position == 2) {
return "Experts";
}
return null;
}
}
Conclusion:
I hope this helps you understand another way to make scrollable tabs! I have examples on my Github Page about how to make each type (That being Fixed or Scrollable).
Links:
Fixed Tabs Example - Click Here
Scrollable Tabs Example - Click Here
Hope this helps!
Edit:
When asked what to import, make sure you select the V4 support fragments.
please use this example..its very easy.i already implement that.
reference link
hope its useful to you.its best example of pager-sliding-tabstrip.
Use
framelayout compulsory:
FrameLayout fl = new FrameLayout(getActivity());
fl.addView(urFragementView);
and then set your fragement view in this framelayout.
I am developing application using viewpager with fragment.In my application i have a items which i showing in List.After that when i click i have calling SherlockFragmentActivity which calling ViewPager with adapter.Now the problem is getItem in FragmentPagerAdapter give multiple position at a single time.Also when i flip backword then also giveing wrong position.Here is my code
ViewPager Code:-
private void initialisePaging() {
//Adapter Context;
this.mPagerAdapter = new MyPagerAdapter(
super.getSupportFragmentManager(), getApplicationContext(),
title, link, description);
ViewPager pager = (ViewPager) super.findViewById(R.id.viewpager);
pager.setAdapter(this.mPagerAdapter);
//Take position from ListView & set postion .
pager.setCurrentItem(post_position);
}
My Adapter Class which responsible for set fragment:-
Problem:- The problem is getItem Calling 3 time & suppose i click on 4 item its giving me 3,4,5 number.
public MyPagerAdapter(FragmentManager fm, Context cont,
ArrayList<String> title, ArrayList<String> link,
ArrayList<String> description) {
super(fm);
this.context = cont;
this.key_desc = description;
this.key_link = link;
this.key_title = title;
viewPagerApplication = (RssItem) cont;
}
#Override
public Fragment getItem(int position) {
return Fragment0.newInstance(position, this.context, key_title,
key_link, key_desc);
}
#Override
public int getCount() {
return key_title.size();
}
My Fragment Class:-
Problem:-Here if i show postion in textview its correct position but if i want take position in logcat for further parsing its giving me again 4,3,5 number which is also diffrent from getItem();
public static Fragment0 newInstance(int num,Context cont, ArrayList<String> key_title, ArrayList<String> key_link, ArrayList<String> key_desc) {
context=cont;
Fragment0 f = new Fragment0();
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
};
public int getShownIndex() {
return getArguments().getInt("num", 0);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.newsdetailfragment_screen, container, false);
tv = v.findViewById(R.id.headingtextview_id);
((TextView)tv).setText(String.valueOf(getShownIndex()));
((TextView)tv).setTextColor(Color.BLACK);
((TextView)tv).setTextSize(20);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
Now kindly let me know where i am wrong & how can i get only one exact position for further process.
Inside of getItem(), the position parameter is the position that is in need of rendering. It is NOT the position of the currently focused item that the user would see. The pages to the left and right of the currently displayed view need to be pre rendered in memory so that the animations to those screens will be smooth. To get the item at current position use:
pager.getCurrentItem();
If you need an actual position of the page you can implement onPageChangeListener
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
}
position in onPageSelected will give an accurate current position of the page.