I'm starting to write an Android app and want to have a tab navigation interface. It seems there are multiple choices, some of which may be deprecated:
Android TabHost (deprecated? but still available in Android Studio)
Tab Layout with Swipeable Views
Android Tab Activity
Material Design with Tabs
What is the best choice? Material Design with Tabs? How far back as far as APIs is this supported?
I know this isn't a pure coding question but it is probably a questions that others are pondering as well.
Thanks
extend your MainActivity to AppCompatActivity, and it will go till android version 7,
http://developer.android.com/reference/android/support/v7/app/AppCompatActivity.html
Use tabLayout and and View Pagers, To get the Swipe Effect on your Tabs
activity_main.xml
Add the Following to your MainActivity layout file.
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/vp_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:visibility="visible">
</android.support.v4.view.ViewPager>
MainActivity.java
public class MainActivity extends AppCompatActivity{
ViewPager viewPager;
FragmentPagerAdapter ft;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpaggermain);
viewPager = (ViewPager) findViewById(R.id.vp_main);
ft = new FragmentPagerAdapter(getSupportFragmentManager()) {
String [] titles = {"Subscriber","Merchant"};
final int VIEW_COUNT = 2;
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new YourFirstFragment();
case 1:
return new YourSecondFragment();
}
return null;
}
#Override
public int getCount() {
return VIEW_COUNT;
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
};
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
viewPager.setAdapter(ft);
tabLayout.setupWithViewPager(viewPager);
}
}
Related
I am using ViewPager/TabLayout on Android TV, and I have 2 questions.
1) Currently, if I press DPAD_UP, the focus goes to the tabs, but the page does not actually change to the one corresponding to the focused tab until DPAD_CENTER is pressed. So, there is a difference between focused (shown as a grey box around the tab text) and selected (shown as an underline). I am wondering if it is possible to have whatever focused to be selected?
2) I have 3 tabs in my ViewPager where the fragment in tab1 needs to have focus in order to display things properly. When I switch from tab3 to tab1, the focus is not given to the fragment but stays with the tab. This causes my fragment to not display properly. I am wondering if there is a way to take focus away from the tab? I dug into the source code of ViewPager and TabLayout, and I know the focus is with TabView of TabLayout, but no matter what I try, I cannot take away the focus state of TabView (i.e. the grey box surrounding the tab text does not go away until I use DPAD_DOWN to "go down" to the fragment).
Tried
((ViewGroup) tabLayout.getChildAt(0)).getChildAt(desiredPosition).clearFocus() and it doesn't help.
I don't want to use viewPager.setOffscreenPageLimit(2);
// This is my viewpager activity class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
adapterViewPager = new MyPagerAdapter(getFragmentManager());
viewPager.setAdapter(adapterViewPager);
// Give the TabLayout the ViewPager
TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
// Tried to clear focus of tab here, didn't help
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
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 a particular page.
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new OneFragment; // This is the fragment that needs focus
case 1:
return new TwoFragment();
case 2:
return new ThreeFragment();
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
if (position == 0) {
return "Fragment 1";
} else if (position == 1) {
return "Fragment 2";
} else {
return "Fragment 3";
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
android:theme="#style/AppThemeTab" />
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
</RelativeLayout>
Any help is appreciated, thank you!
One liner solution :) . To suppress focus on Tablayout children views use the code fragment below assuming the tab is scrollable - i.e. tabs selection is scrolling by digipad:
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
tabLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
I'm getting a null pointer exception when trying to switch tabs programmatically of a tablayout inside a fragment,
So I have my main activity that has a tab layout (4 tabs) each tab has a view pager holding a fragment, and each of these fragments has a tab layout (x amount of tabs) with a view pager holding a fragment,
i can switch the tabs of my main activity tab layout from any fragment like this
TabLayout tabLayout = MainActivity.tabLayout;
TabLayout.Tab tab = tabLayout.getTabAt(2);
tab.select();
but if i try to change the tabs of one of the fragments in the same way i get a null pointer
TabLayout tabLayout2 = tabFragOne.tabLayout;
TabLayout.Tab tab2 = tabLayout2.getTabAt(2);
tab2.select();
it only happens if I click the button in question when the app first opens, which suggests that the reason for it is that the fragment hasn't been attached or created yet,
for instance if i scroll across to the fragments tab i want to switch to, and then go back to the main activity and press the button in question it will work.
does anyone know the best way to fix this?
Ok ive found half the crux to this question is actually that im using a view pager adapter, a question here sheds a lot of light on my issue
The correct way to set selected Tab, we should set selected index from Pager instead.
final ViewPager pager = (ViewPager) findViewById(R.id.pager);
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(pager);
pager.setCurrentItem(0);//selected position
Here is my layout design in xml
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#ffffff"
android:background="#color/al_white"
android:elevation="0dp" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
app:tabTextColor="#494a43"
app:tabSelectedTextColor="#494a43"
app:tabIndicatorColor="#494a43"
app:tabIndicatorHeight="2dp"
app:tabMode="fixed"
app:tabGravity="fill" />
</android.support.design.widget.AppBarLayout>
TabLayout tabhost = (TabLayout) getActivity().findViewById(R.id.tabLayout);
tabhost.getTabAt(2).select();
I use this inside my fragment's create function... and it works perfectly
R.id.tabLayout is the tablayout id in your main activity layout.
you can use the setCurrentItem(Postion) in viewpager
example :
tabLayout.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
// tabLayout.setupWithViewPager(mViewPager);
mViewPager.setCurrentItem(4);
Simple example to automatically scroll from the last page to the first. Note: I added a dummy fragment at the first and last position.
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if (position == 0) {
viewPager.setCurrentItem(viewPagerAdapter.getCount() - 2);
} else if (position == viewPagerAdapter.getCount() - 1) {
viewPager.setCurrentItem(1);
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Using view pager, Its working simple and fine
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
int NumbOfTabs;
String mode;
AllDeals deals;
MyDeals myDeals; those are my fragments
public ViewPagerAdapter(FragmentManager fm, int mNumbOfTabsumb, String moe) {
super(fm);
this.NumbOfTabs = mNumbOfTabsumb;
mode=moe;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
if(mode.equals("Deals")){
deals=new AllDeals();
return deals;
}
break;
case 1:
if(mode.equals("Deals")){
myDeals=new MyDeals();
return myDeals;
}
break;
default:
break;
}
return null;
}
#Override
public int getCount() {
return NumbOfTabs;
}
}
add this lines into ur activity
containerViewone.setVisibility(View.VISIBLE);
tabLayout.addTab(tabLayout.newTab().setText(getResources().getString(R.string.title_all_deals)));
tabLayout.addTab(tabLayout.newTab().setText(getResources().getString(R.string.title_my_deals)));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabTextColors(getResources().getColor(R.color.tabunselect), getResources().getColor(R.color.black));
viewpagerad = new ViewPagerAdapter(getSupportFragmentManager(), Numboftabs, "Deals");
pager.setAdapter(viewpagerad);
pager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
Try this:
TabLayout tablayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //your activity layout
tabLayout =(TabLayout)findViewById(R.id.tablayout); //your tab layout id
tabLayout.getTabAt(0).select(); //your tab index;
}
In Kotlin:
With TabLayout and ViewPager2 that works for me:
binding.tablayout.getTabAt(1)!!.select()
I want to have two tabs to navigate between Fragments, I did it with the old method but now with API 21 all methods are deprecated. I searched a lot but I didn't found any tutorial or sample. I try the SlidingTabs sample from Google but it's not built for Eclipse so I don't know how to integrate it in my app. Can someone help me? Maybe send me a link to a basic tutorial? Thank you!
Check this out, it may help you , it's a very well done menu for navigate through fragments
Just import those 2 classes : SlidingTabStrip and SlidingTabLayout in your project to have tabs in your application. You can take a look at the sample project to see how it is used.
Very simple to use. First import those 2 classes in your project and in your xml layout(my_layout.xml), add the SlidingTabLayout. I also added a viewPager in case you want to use it with a ViewPager :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingRight="#dimen/activity_horizontal_margin"
tools:context="MyActivity">
<SlidingTabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/my_pager" />
</LinearLayout>
In your activity,
public class MyActivity extends ActionBarActivity {
private SlidingTabLayout slidingTabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
viewPager = (ViewPager) findViewById(R.id.my_pager);
viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
slidingTabLayout = (SlidingTabLayout)findViewById(R.id.sliding_tabs);
slidingTabLayout.setViewPager(viewPager);
}
}
And then you can define your adapter that will added to the SlidingTabLayout. For instance :
public static class MyAdapter extends FragmentPagerAdapter {
private static final int FRAGMENT_1 = 0;
private static final int FRAGMENT_2 = 1;
private static final int FRAGMENT_3 = 2;
public MyAdapter (FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i){
case FRAGMENT_1 : return new Fragment1();
case FRAGMENT_2 : return new Fragment2();
case FRAGMENT_3 : return new Fragment3();
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case FRAGMENT_1 : return "Fragment 1 Title";
case FRAGMENT_2 : return "Fragment 2 title";
case FRAGMENT_3 : return "Fragment 3 Title";
}
return super.getPageTitle(position);
}
#Override
public int getCount() {
return 3;
}
}
If it is a ViewPager you are talking about and not a NavigationDrawer type of thing, it continues to work well on API-21.
Take a look at IOSched application's code for a "Google Play" like ViewPager indicator.
EDIT
Yes setNavigationMode is deprecated as a method and as a UI/UX pattern.
From the official documentation:
This method was deprecated in API level 21.
Action bar navigation modes are deprecated and not supported by inline toolbar action bars.
Consider using other common navigation patterns instead.
Which links to common navigation patterns.
EDIT2
Fixed iosched application code link.
What is the element that is used for Swarm Android app's actionbar?
I think it's neither the native android actionbar nor actionbarsherlock.
After using uiautomatorviewer, it can be seen that the base components were ImageButtons inside of a HorizontalScrollView for the left portion, and a LinearLayout with an ImageButton for the right portion.
However, this doesn't detail how to attain the sliding animation or how to space out the two functioning parts well.
I managed to recreate it using this fantastic library and a little massaging of views. Basically, you feed the Pager Sliding Tab Strip(PSTS) to the actionbar as a custom view.
//I call this in the onCreate()of my activity
void setupActionBar() {
ActionBar actionBar = getActionBar();
View vwActionBar = View.inflate(this, R.layout.action_bar_main, null);
tabs = (PagerSlidingTabStrip) vwActionBar.findViewById(R.id.tabs);
actionBar.setCustomView(vwActionBar);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
}
With the action_bar_main.xml being this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.astuetz.PagerSlidingTabStrip
android:id="#+id/tabs"
android:layout_width="wrap_content"
android:layout_height="?android:attr/actionBarSize"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
You also have to change how the FragmentPagerAdapter sets up the PSTS. The libraries samples hold a good example of how to do this, but here is mine.
public class MyPagerAdapter extends FragmentPagerAdapter
implements PagerSlidingTabStrip.IconTabProvider {
private final int[] ICONS = {
R.drawable.ic_home,
R.drawable.ic_dashboard,
R.drawable.ic_insights,
R.drawable.ic_stream
};
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return ICONS.length;
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return fragments.get(position);
}
#Override public int getPageIconResId(int i) {
return ICONS[i];
}
}
I've integrated PagerSlidingTabStrips in my application which runs as expected on Swipe of tabs.
But selecting tabs on PagerSlidingTabStrips doesn't switch to that fragment which works perfectly on swiping between tabs.
FragmentManager fm = getSupportFragmentManager();
mPager = (ViewPager) findViewById(R.id.pager);
ViewPagerAdapter viewpageradapter = new ViewPagerAdapter(fm);
mPager.setAdapter(viewpageradapter);
pagerSlidingTabStrp = (PagerSlidingTabStrip) findViewById(R.id.pager_sliding_tab_strip);
pagerSlidingTabStrp.setShouldExpand(true);
pagerSlidingTabStrp.setViewPager(mPager);
pagerSlidingTabStrp.setOnPageChangeListener(ViewPagerListener);
// Capture ViewPager page swipes
ViewPager.SimpleOnPageChangeListener ViewPagerListener = new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
switch(position)
{
case 0:
setMotherActionBarTitle(getString(R.string.str_all_contacts_fragment));
break;
case 1:
setMotherActionBarTitle(getString(R.string.str_group_contacts_fragment));
break;
case 2:
setMotherActionBarTitle(getString(R.string.str_call_logs_fragment));
break;
}
}
};
ViewPagerAdapter
public class ViewPagerAdapter extends FragmentPagerAdapter implements IconTabProvider {
final int PAGE_COUNT = 3;
private final int[] ICONS = { R.drawable.tab_icon_zname_contact_selector, R.drawable.tab_icon_zname_friends_selector,
R.drawable.tab_icon_zname_call_log_selector };
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int item) {
switch (item) {
case 0:
ContactsFragment homeFragment = new ContactsFragment();
return homeFragment;
case 1:
GroupsFragment groupsFragment = new GroupsFragment();
return groupsFragment;
case 2:
CallLogsFragment callLogsFragment = new CallLogsFragment();
return callLogsFragment;
}
return null;
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public int getPageIconResId(int position) {
return ICONS[position];
}
}
How to make selecting tabs works with PagerSlidingTabStrips? Morever PagerSlidingTabStrips tabs are not even clickabe.
Did I missed out to implement something? Or to add pagerSlidingTabStrips.setClickable(true)? or something?
Again the selector of PagerSlidingTabStrips tabs not selected proper drawable with selector. What could be possible the reason for that?
Here's a picture of it.
I've found out why clicking tab was not working with PagerSlidingTabStrips after I've looked out for other options with sliding tabs functionality like SlidingTabsLayout which also was not able to click tabs.
Found out problem was with my xml layout which covers whole as ViewPager which doesn't make tabs clickable of eitherPagerSlidingTabStrips or SlidingTabsLayout works.
<com.netdoers.zname.utils.PagerSlidingTabStrip
android:id="#+id/pager_sliding_tab_strip"
android:layout_width="fill_parent"
android:layout_height="45dip"
android:background="#android:color/white"
app:pstsDividerColor="#FFFFA500"
app:pstsIndicatorColor="#FFFFA500"
app:pstsTabPaddingLeftRight="14dip"
app:pstsUnderlineColor="#FFFFA500" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="45dp" />
Leaving same height in Viewpager as of PagerSlidingTabStips from top where PagerSlidingTabStrips rendered solved my issue.
Indeed the issue is in XML. The issue probably due to RelativeLayout is used om the XML. Consider using LinearLayout will ensure there's no overlap between views.