Mehdiway
Mehdiway

Reputation: 10656

ViewPagerIndicator and setOnPageChangeListener

I'd like to change the background color as the user changes pages, for that I need to use ViewPager's setOnPageChangeListener. But it seems that this brakes ViewPagerIndicator, as the indicator is stuck in the first page. Here's the code

viewPager.setOnPageChangeListener(new OnPageChangeListener() {
    @Override
    public void onPageSelected(int position) {
        ColorDrawable[] colors = {new ColorDrawable(backgroundColors[previousPosition]), new ColorDrawable(backgroundColors[position])};
        TransitionDrawable trans = new TransitionDrawable(colors);
        viewPager.setBackgroundDrawable(trans);
        trans.startTransition(200);
        previousPosition = position;
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {}

    @Override
    public void onPageScrollStateChanged(int arg0) {}
});

Upvotes: 1

Views: 3272

Answers (3)

m02ph3u5
m02ph3u5

Reputation: 3161

Since timed transitions don't quite fit the usecase and alpha shouldn't be used (in that way) for transitions/animations on android here is what I came up with:

First of all be sure that no child view has a background set where it shouldn't. In your base layout set the background of the layout to your start color.

In your Activity.onCreate() add this:

final ViewPager mPager = (ViewPager) findViewById(R.id.ofYourPager);
// if you have a page indicator
final YourPageIndicator pageIndicator = (YourPageIndicator) findViewById(R.id.ofYourIndicator);

// change background on swipe
final int[] colors = {
    getResources().getColor(R.color.yourFirstColor),
    getResources().getColor(R.color.yourSecondColor),
    getResources().getColor(R.color.yourThirdColor),
    // --- add as many colours as you have pages ---
};
final ArgbEvaluator argbEvaluator = new ArgbEvaluator();
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (position < (mPagerAdapter.getCount() - 1) && position < (colors.length - 1)) {
            Integer color = (Integer) argbEvaluator.evaluate(positionOffset, colors[position], colors[position + 1]);
            mPager.setBackgroundColor(color);
            pageIndicator.setBackgroundColor(color);
        } else {
            mPager.setBackgroundColor(colors[colors.length - 1]);
            pageIndicator.setBackgroundColor(colors[colors.length - 1]);
        }
    }

    @Override
    public void onPageSelected(int position) {}

    @Override
    public void onPageScrollStateChanged(int state) {}
});

I took the idea from this post I found: http://kubaspatny.github.io/2014/09/18/viewpager-background-transition/

Upvotes: 0

Mehdiway
Mehdiway

Reputation: 10656

I ended up using ViewPagerIndicator's setOnPageChangeListener instead of ViewPager's method

mIndicator = (IconPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(viewPager);

The code becomes :

mIndicator.setOnPageChangeListener(new OnPageChangeListener() {
    @Override
    public void onPageSelected(int position) {
        ColorDrawable[] colors = {new ColorDrawable(backgroundColors[previousPosition]), new ColorDrawable(backgroundColors[position])};
        TransitionDrawable trans = new TransitionDrawable(colors);
        viewPager.setBackgroundDrawable(trans);
        trans.startTransition(200);
        previousPosition = position;
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {}

    @Override
    public void onPageScrollStateChanged(int arg0) {}
});

Upvotes: 10

Sotti
Sotti

Reputation: 14409

This way of changing colors between tabs is a first approach but I think that is not that difficult to come up with a better one.

In your approach: I think that in your approach what you are doing is as soon as a new page is selected you trigger a transition in the background color. In that case the transitions are fixed in time (200 milliseconds in your case) but it doesn't feel natural, is even worse when you change pages swiping between them. The problem is that the onPageSelected is a on/off trigger. You are on page 0 or 1 or 2, but there is no such state as "between 0 and 1".

Wouldn't be great if the color would be exactly proportional to the amount of swipe, this is proportional to the real state in the transition between tabs??

How to do it?

In the activity hosting the viewpager, set a layout with as many background layers as tabs you want in the view pager. If you have 3 tabs then set 3 background layers overlapping one to each other.

For example:

<LinearLayout
    android:id="@+id/background_main_fragment_activity_bottom"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background_gradient_radial_blue_vivid"
    android:orientation="vertical"
    tools:visibility="visible">
</LinearLayout>

<LinearLayout
    android:id="@+id/background_main_fragment_activity_middle"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background_gradient_radial_blue_samknows"
    android:orientation="vertical"
    tools:visibility="visible">
</LinearLayout>

<LinearLayout
    android:id="@+id/background_main_fragment_activity_top"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background_gradient_radial_blue_light"
    android:orientation="vertical"
    tools:visibility="visible">
</LinearLayout>

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</android.support.v4.view.ViewPager>

Each LinearLayout is a background for a particular tab.

The idea is modify the alpha value of the linear layouts making them visible, partially visible or invisible.

Instead of using the onPageSelected method we are gonna use the onPageScrolled, take a look:

// Set a listener that will be invoked whenever the page changes or is incrementally scrolled.
// This listener is used for changing smoothly the colour of the background, this is modifying the visibility of the different layers

viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener()
{
        // Called when the scroll state changes

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);

        switch (position)
        {
            case 0:
                layout_ll_background_middle.setAlpha(positionOffset);
                break;

            case 1:                     
                layout_ll_background_top.setAlpha(positionOffset);
                break;

            default:
                break;
        }               
    }

    // This method will be invoked when a new page becomes selected

    @Override
    public void onPageSelected(int position)
    {       // When swiping between pages, select the corresponding tab         
            getActionBar().setSelectedNavigationItem(position);
            // Set the title    
            actionBar.setTitle(adapter_ViewPager.getPageTitle(position));       
    }           
});

Hope it helps to make it better.

Good luck

Upvotes: 1

Related Questions