How to Implement PageTransformer with Swipeable Tabs - android

In my example code i have three Swipeable Tabs in MainActivity.java namely : Android, IOS and WINDOWS and i am using swipe to switch between Tabs.
Now, i have to implement PageTransformer with Swipeable Tabs, so here i need your help, is it possible, if yes so how ?
MainActivity.java:-
public class MainActivity extends FragmentActivity {
ViewPager Tab;
TabPagerAdapter TabAdapter;
ActionBar actionBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabAdapter = new TabPagerAdapter(getSupportFragmentManager());
Tab = (ViewPager)findViewById(R.id.pager);
Tab.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar = getActionBar();
actionBar.setSelectedNavigationItem(position);
}
});
Tab.setAdapter(TabAdapter);
..............
}
}
Here is what i want to implement in my program :
and this is how my Tab looks :

You have to use setPageTransformer() to do this type of navigation..
use below code to your pager..
Add This Code To Your MainActivity.java
Tab = (ViewPager)findViewById(R.id.pager); // you have defined view pager as `TAB`
Tab.setPageTransformer(false, new PageTransformer() {
public void transformPage(View page, float position) {
page.setRotationY(position * -30); // animation style... change as you want..
}
});
Tab.setCurrentItem(pos);
}
Get More Animation Styles From Here.. Customize the Animation with PageTransformer or ViewPager transitions

I found my solution here, its really easy to implement
Usage is pretty straightforward, just attach a PageTransformer to the ViewPager:
viewpager.setPageTransformer(false, new ViewPager.PageTransformer() {
#Override
public void transformPage(View page, float position) {
// do transformation here
}
});
rotates the pages around their Z axis by 30 degrees; you don’t need to normalize for this one. The effect is similar to the cover flow UI pattern:
#Override
public void transformPage(View page, float position) {
page.setRotationY(position * -30);
}
so here is my final code, which i used:
viewPager = (ViewPager)findViewById(R.id.pager);
viewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar = getActionBar();
actionBar.setSelectedNavigationItem(position);
}
});
viewPager.setAdapter(tabAdapter);
viewPager.setPageTransformer(false, new PageTransformer() {
public void transformPage(View page, float position) {
page.setRotationY(position * -30); // animation style... change as you want..
}
});

Create an inner class of your Activity...
public class MyPageTransformer implements ViewPager.PageTransformer {
public void transformPage(View view, float position) {
// Do your transform here
}
}
Then in your Activity you can set it on your ViewPager. Example...
Tab.setPageTransformer(true, new MyPageTransformer());
Read more at Customize the Animation with PageTransformer There are even a couple of examples of transforms to try out and to customize yourself.

Related

Issue with tablayout, on switching to the second tab it will jump back to the first tab

I am trying to create a tab layout for my program.
There are two tabs. If I try to switch to Tab2 instead of staying on Tab2, it changes back to Tab1. I have 0 clue what is causing this problem.
Here is my code
MainActivity:
tabLayout = findViewById(R.id.tablayout);
viewPager2 = findViewById(R.id.viewpager);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentAdapter = new CustomAdapter(fragmentManager, getLifecycle());
viewPager2.setAdapter(fragmentAdapter);
tabLayout.addTab(tabLayout.newTab().setText("Tab1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab2"));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager2.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageScrollStateChanged(int state) {
tabLayout.selectTab(tabLayout.getTabAt(state));
}
});
CustomAdapter:
public class CustomAdapter extends FragmentStateAdapter {
public CustomAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
if(position == 1) return new BlankFragment1();
return new BlankFragment2();
}
#Override
public int getItemCount() {
return 2;
}
Following the official docs here you can use a TabLayoutMediator to link the tab layout and pager instead of doing it with your own listeners.
However, the root of the problem you observed is that state in onPageScrollStateChanged is not the position that it scrolled to - it is an integer representing the scroll state. Since SCROLL_STATE_IDLE is 0, and SCROLL_STATE_DRAGGING is 1, as soon as you stopped dragging it would snap back to tab 0.
Using TabLayoutMediator (recommended)
To use the TabLayoutMediator replace your addOnTabSelectedListener, registerOnPageChangeCallback, and manually setting the tabs (addTab) with this, which links the tabs to the view pager and provides a method to set the tab titles
// remove the "addTab" calls, "addOnTabSelectedListener",
// and "registerOnPageChangeCallback"
new TabLayoutMediator(tabLayout, viewPager2,
(tab, position) -> tab.setText("Tab" + (position + 1))
).attach();
Using your own listeners
It is still possible to use your own listeners, but you have to change the view pager listener to use onPageSelected instead of onPageScrollStateChanged, like this:
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageSelected(int position) {
tabLayout.selectTab(tabLayout.getTabAt(position));
}
});
Note: The positions are 0-based, so you are showing "BlankFragment2" in position 0 and "BlankFragment1" in position 1 (not sure if that is what you intended).

Viewpage+tablayout: Why fragment 2 3 start when fragment 1 called?

When I start application then Tab Home started but tab Cung Hoàng Đạo also starts .When I select tab Cung Hoàng Đạo then tab 12 Con Giap and Tử Vi start.
I want them to start only when they are selected.
Sorry for my grammar.
Thanks everybody.
This is my code:
public class ViewPageContainerFragment extends BaseFragment {
private ViewPager viewPager;
private TabLayout tabLayout;
private final String TAG = getClass().getSimpleName();
private ViewPagerAdapter adapter;
private boolean[] isTabsSelected = new boolean[5];
private OnTabChangeListener mOnTabChangeListener;
private int countSelectedTab = 1;
#Override
public void init() {
tabLayout = (TabLayout)getView().findViewById(R.id.tab_layout);
viewPager = (ViewPager) getView().findViewById(R.id.view_pager);
adapter = new ViewPagerAdapter(getFragmentManager());
}
#Override
public void setEvent() {
setupViewPager(viewPager);
isTabsSelected[0] = true;
tabLayout.setupWithViewPager(viewPager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Log.d(TAG, "onPageSelected: "+position);
if (position != 0) {
if (!isTabsSelected[position]
&& adapter.getItem(position).getChildFragmentManager().getBackStackEntryCount() == 1
&& getCurrentFragment(position) instanceof OnTabChangeListener) {
mOnTabChangeListener = (OnTabChangeListener) getCurrentFragment(position);
mOnTabChangeListener.onTabSelected();
}
} else if (adapter.getItem(0).getChildFragmentManager().getBackStackEntryCount() == 1) {
Log.d(TAG, "position = 0");
}
if (!isTabsSelected[position]) {
isTabsSelected[position] = true;
countSelectedTab++;
viewPager.setOffscreenPageLimit(countSelectedTab);
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
#Override
public void setValue() {
}
#Override
public int getLayoutId() {
return R.layout.fragment_viewpage;
}
private void setupViewPager(ViewPager viewPager) {
adapter.addFrag(new HomeContainerFragment(), "Home");
adapter.addFrag(new CungHoangDaoContainerFragment(), "Cung Hoàng Đạo");
adapter.addFrag(new ConGiapContainerFragment(), "12 Con Giáp");
adapter.addFrag(new TuViContainerFragment(), "Tử Vi");
viewPager.setAdapter(adapter);
}
public Fragment getCurrentFragment(int position) {
FragmentManager fm = getChildFragmentManager();
return fm.findFragmentById(R.id.container_framelayout);
}
public interface OnTabChangeListener {
void onTabSelected();
}
}
ViewPager by default preload several page in advanced for smoother navigation. You customize this behavior by extending ViewPager and overriding setOffscreenPageLimit method:
Documentation Link Here
public void setOffscreenPageLimit (int limit)
Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this
limit will be recreated from the adapter when needed.
This is offered as an optimization. If you know in advance the number of pages you will need to support or have lazy-loading mechanisms in place on your pages, tweaking this setting can have benefits in perceived smoothness of paging animations and interaction. If you have a small number of pages (3-4) that you can keep active all at once, less time will be spent in layout for newly created view subtrees as the user pages back and forth.
You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.
The setOffscreenPageLimit() don't work. You must stop the preload of the ViewPager,it means that the ViewPager need to load data lazyly. Just like this.
public class FragmentSample extends Fragment{
...
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// load your data
}
}
...
}
In your setupViewPager(ViewPager viewPager) method, add this -
viewPager.setOffscreenPageLimit(1);
From the docs,
Set the number of pages that should be retained to either side of the
current page in the view hierarchy in an idle state. Pages beyond this
limit will be recreated from the adapter when needed.

how to make ImageView visible by timer [duplicate]

I have a problem. I have an Activity with ViewPager which have some Fragments.
In my first Fragment I have some elements. Lets say an ImageView, TextView. How to make them visible by timer when you completely open the page of ViewPager?!
I used this code below in my MainActivity.java document to make that ImageView visible by timer but it works not as I expected. When i want to go to next page by scrolling and touch the screen ImageView dissapear. Why its happened?!
final ImageView mImageView = (ImageView) findViewById(R.id.earth);
mImageView.setVisibility(View.INVISIBLE);
mImageView.postDelayed(new Runnable() {
public void run() {
mImageView.setVisibility(View.VISIBLE);
}}, 5000);
Any help is appreciated. Thanks!
My new edits:
// Initialize the ViewPager and set an adapter
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
// Bind the tabs to the ViewPager
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
tabs.setViewPager(pager);
//open concrete page of ViewPager. setCurrentItem(index of page)
pager.setCurrentItem(1);
tabs.setOnPageChangeListener(new OnPageChangeListener() {
//This method will be invoked when the current page is scrolled, either as part of a program initiated smooth scroll or a user initiated touch scroll.
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
//This method will be invoked when a new page becomes selected.
#Override
public void onPageSelected(int position) {
final ImageView mImageView = (ImageView) findViewById(R.id.earth);
mImageView.setVisibility(View.INVISIBLE);
if (position == 0) {
mImageView.postDelayed(new Runnable() {
public void run() {
mImageView.setVisibility(View.VISIBLE);
}
}, 5000);
}
}
//Called when the scroll state changes.
#Override
public void onPageScrollStateChanged(int state) {
}
});
My Problem is conflict with TABS and ViewPager. When I use tabs.setOnPageChangeListener(new OnPageChangeListener() i have conflict with pager.setCurrentItem(1); which shows concrete page when Activity first opened. In my case its shows 2-d page when Activity first opened but Tab shows that opened 1-st page. WHY?! How to solve this problem?!
I would not use a timer. It would either fire too early, or too late during which your UI looks bad. Use the pager's events to know when to update your UI. For example, you can probably use OnPageChangedListener:
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Now displaying page at position
}
#Override
public void onPageScrollStateChanged(int state) {
}
};

How to make a function in an activity that is available in all tab fragments?

I am building an app that uses three tab fragments and I want to create a function in one place that I can call from all three tabs. I would assume that I need to create the new function in the activity that contains the tabs, but I'm not sure how to declare it or how to call it from one of the tab fragments.
This is how i create my tabs in the main activity:
public class MainActivity extends FragmentActivity implements TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Search", "History", "Saved" };
#Override
protected void onCreate(Bundle savedInstanceState) {
//Initialise the Database connection
DBAdapter.init(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Setup tab bar
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Add the tabs to the action bar
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
//Tab Swipe change listener
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
}
Create the function you need to call in the parent Activity and it must be a public method
and you can call that function like this:
((YourActivityClassName)getActivity()).yourPublicMethod();

Tab+swipe Gesture, Custom grid view, Fragments

Well I have this app with swipe gesture functionality between fragments which they contains images which are located in the resources folders .. but when i swipe left and right I noticed that the performance is bad and slow .. Any suggestions to improve it?
And here is the header of the main activity code :
public class MainActivity extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = {"Roman Curtain", "Roller Blinds", "Wooden Blinds" ,"Kitchen Blinds"};
//
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
and here is tab pager adapter :
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new RomanCurtains();
case 1:
return new RollerBlinds();
case 2:
return new WoodenBlinds();
case 3:
return new KitchenBlinds();
// case 4:
// return new KitchenBlinds();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 4;
}
}
There may be a two reason for the bad performance
Your images are too big and takes too much space in the memory
You can put the images in assets folder and then use Picasso library to use them. It will improve the performance.
https://github.com/square/picasso
All the pages in the ViewPager is in the memory if you use PagerAdapter or FragmentPagerAdapter.
If you use FragmentStatePagerAdapter only the visible page and the
pages adjacent to that page are kept in the memory. This will
improve the performance too.
Use ViewPager.setOffscreenPageLimit(int limit)

Categories

Resources