Showing posts with label viewpagerindicator. Show all posts
Showing posts with label viewpagerindicator. Show all posts

28 December 2012

Styling tab selectors for ActionBarSherlock

This post builds on the previous post for ABS + VPI.

I have gotten a lot of questions on styling the ABS, specifically the tab selected indicators. This task may seem daunting, but in reality it is relatively simple. I am also quite confused why I didn't find any straightforward tutorials when I tried googling this. Anyway, this post will hopefully help developers who aim to style their action bars.

We will need to use Jeff Gilfelt's awesome styling tool. To use it, just input in your app's color scheme for the highlights and what-not then download the generated zip file. If you want to just change the tab underline color, change the value under "Accent color". To make the change obvious from the default settings, I have used a shade of orange for the tab selected indicators. Here are the settings I used for this demo.

Jeff's tool conveniently generates all the XML files and drawables and organizes them into the correct /res/drawable folders. Unzip the file and just drag the generated files into your project, or merge the contents if you already have such existing files.

See how easy it was? Seriously, we should all lie prostrate at Jeff Gilfelt's and Jake Wharton's feet. These guys are AWESOME.

The two photos below show the difference between the old app and the styled app. As you can see, I only changed the tab selected color. You can explore what happens if you use the other styles you can get from Jeff's tool.
DefaultStyled
The hard work is done, let's now try to understand the automagically generated configurations we did.

First, we have to configure the theme to use custom tab indicators. We do this by changing the tab styles in themes.xml. In my sample app, these lines customize the tabs we are using.
<!-- Styling the tabs -->
<style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
   <!-- Tab text -->
   <item name="android:textSize">15dip</item>
   <item name="android:textColor">#FFB33E3E</item>
        
   <!--  Lines under tabs -->
   <item name="background">@drawable/tab_indicator_ab_styling_abs</item>
   <item name="android:background">@drawable/tab_indicator_ab_styling_abs</item>
</style>

The "drawable" tab_indicator_ab_styling_abs is actually a state list drawable that provides different images for each state of a tab -- focused and non-focused, pressed and not pressed.

You can see part of this in action in the image above. Try long pressing on a tab and you can see the tab's background change to use the unselected-pressed drawable.

Again, HUGE thanks to Jeff Gilfelt and Jake Wharton for creating tools that make our lives easier. :)

I have pushed a new branch in github that uses this style. The master branch of that repo still uses the default tab selectors.

14 August 2012

Making ActionBarSherlock and ViewPagerIndicator play nice

EDIT (20121227): I made a new post on changing the tab selector underline.
EDIT (20121014): I received feedback from the comments that rotating the device will cause the tab contents to revert to the default text. In essence, the adapter "loses" the contents of the tabs. I have corrected this in the example below as well as in github.
EDIT (20120905): The full sample source code is now in github.

So ViewPagerIndicator cheerfully claims that it works with ActionBarSherlock. I was trying to test this out today and I can't find a noob-friendly, step-by-step tutorial on how I can do it. I spent almost half a day frantically opening tab after tab in Google Chrome, but nothing seems to straight out say what I should do. So here it is, collated from several StackOverflow answers, blog posts, etc.

Get the ViewPagerIndicator (hereafter referred to as VPI) and ActionBarSherlock (hereafter referred to as ABS) libraries. Create your Android application in Eclipse and add those two projects as dependency library projects. If you do not know how to do that, see here.

First, create a theme. This is required by ABS, and will also help in VPI. What I did was to make the VPI theme inherit from the ABS theme so I don't lose any of the styles I use in other parts of the app. I just add or override items needed by the ViewPagerIndicator. In this example, I just changed the text size and color of the tab labels. You can go one step further and change the selected tab indicator (via state selectors), change how the selectors are drawn, etc.
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is our main ActionBarSherlock theme -->
    <style name="Theme.Styled" parent="Theme.Sherlock.Light.DarkActionBar">
        <item name="actionBarStyle">@style/Widget.Styled.ActionBar</item>
        <item name="android:actionBarStyle">@style/Widget.Styled.ActionBar</item>
    </style><!-- This is our ViewPagerIndicator theme. We inherit from the ABS theme -->
    <style name="Theme.VPI" parent="Theme.Styled">
       <item name="vpiTabPageIndicatorStyle">@style/CustomTabPageIndicator</item>
    </style>    
    <!-- "Implementation" of our ABS custom theme -->
    <style name="Widget.Styled.ActionBar" parent="Widget.Sherlock.Light.ActionBar.Solid.Inverse">
        <item name="titleTextStyle">@style/TitleText</item>
        <item name="android:titleTextStyle">@style/TitleText</item>
    </style>
    
    <!-- "Implementation" of VPI theme. We just set the text size and color. -->
    <style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
        <item name="android:textSize">50dip</item>
        <item name="android:textColor">#FFB33E3E</item>
    </style>
    
    <!-- More customizations for ABS -->
     <style name="TitleText" >
        <item name="android:textColor">@android:color/darker_gray</item>
        <item name="android:textSize">17dip</item>
    </style>
</resources>

Then we create the fragment(s) we need to populate the viewpager. My fragment is a simple layout with just a TextView indicating which tab is being shown.
public class TestFragment extends SherlockFragment {
 private String mContent = "???";
 
     public static TestFragment newInstance(String text) {
        TestFragment fragment = new TestFragment();
        
        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putString(KEY_TAB_NUM, text);
        fragment.setArguments(args);

        return fragment;
    }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_main, null);
        String text = getString(R.string.tab_page_num) + mContent;
        ((TextView)view.findViewById(R.id.text)).setText(text);
        
        return view;
 }

     @Override
     public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContent =  getArguments() != null ? getArguments().getString(KEY_TAB_NUM) : "???";
     }

}

Then we create the activity that will hold everything together.
public class VpiAbsTestActivity extends SherlockFragmentActivity {
 
 private static final String[] TAB_TITLES = new String[] { "This", "Is", "A", "ViewPager" };
 
 TestFragmentAdapter mAdapter;
    ViewPager mPager;
    PageIndicator mIndicator;
    
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.simple_tabs);
        
        mAdapter = new TestFragmentAdapter(getSupportFragmentManager());

        mPager = (ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);

        mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
        mIndicator.setViewPager(mPager);
    }
 
 class TestFragmentAdapter extends FragmentPagerAdapter {     
     private int mCount = TAB_TITLES.length;

     public TestFragmentAdapter(FragmentManager fm) {
         super(fm);
     }

     @Override
     public Fragment getItem(int position) {
         return TestFragment.newInstance(String.valueOf(position));
     }

     @Override
     public int getCount() {
         return mCount;
     }
     
     @Override
     public CharSequence getPageTitle(int position) {
      return TAB_TITLES[position];
     }
 }
}
And lastly, we apply the ViewPagerIndicator theme to our activity in the manifest:
<activity android:name="VpiAbsTestActivity" android:theme="@style/Theme.VPI">
</activity>

As it turns out, it IS pretty straightforward!