Tuesday, September 20, 2011

ViewPager meets Swipey Tabs

Revision 3 of the Android compatibility package brought us the awesome class ViewPager. The new Android Market app has these nice Swipey Tabs of which the bits and pieces are explained by Kirill Grouchnikov.

A sample swipey tabs application based on this ViewPager can be found at http://code.google.com/p/android-playground.


The main elements are the class SwipeyTabs and the interface SwipeyTabsAdapter.

Layout defintions

The first layout definition we need is the one that will host our SwipeyTabs along with the ViewPager.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:swipeytabs="http://schemas.android.com/apk/res/net.peterkuterna.android.apps.swipeytabs"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <net.peterkuterna.android.apps.swipeytabs.SwipeyTabs
        android:id="@+id/swipeytabs"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        swipeytabs:bottomBarColor="#ff96aa39"
        swipeytabs:bottomBarHeight="2dip"
        swipeytabs:tabIndicatorHeight="3dip"
        android:background="#ff3b3b3b"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="0px"
        android:layout_weight="1" />

</LinearLayout>

As you can see, you can customize the layout of the swipey tab with the attributes bottomBarColor, bottomBarHeight and tabIndicatorHeight.

Second we will need a TextView layout definition that we are going to inflate when SwipeyTabs asks us to create a tab for a given position.
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipey_tab"
    android:layout_width="wrap_content"
    android:layout_height="30dip"
    android:paddingLeft="15dip"
    android:paddingRight="15dip"
    android:focusable="true"
    android:singleLine="true"
    android:textSize="14sp"
    android:background="@drawable/swipey_tab_indicator" />

As last we have a layout definition for the fragment we are going to instantiate in the FragmentPagerAdapter.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView 
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
    
</FrameLayout>

Setting up the adapter

The adapter that we inject into the ViewPager and SwipeyTabs simply extends the FragmentPagerAdapter and implements the interface SwipeyTabsAdapter. As soon as you set the adapter on the swipey tabs object, it will ask your adapter to deliver a TextView for a given position. The implementation in the sample application is as follows:
public TextView getTab(final int position, SwipeyTabs root) {
    TextView view = (TextView) LayoutInflater.from(mContext).inflate(
        R.layout.swipey_tab_indicator, root, false);
    view.setText(TITLES[position]);
    view.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            mViewPager.setCurrentItem(position);
        }
    });
   
    return view;
}

Integration with the ViewPager

To integrate SwipeyTabs with the ViewPager you only need to inject the swipey tab object as an OnPageChangeListener in the ViewPager.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_swipeytab);

    mViewPager = (ViewPager) findViewById(R.id.viewpager);
    mTabs = (SwipeyTabs) findViewById(R.id.swipeytabs);

    SwipeyTabsPagerAdapter adapter = new SwipeyTabsPagerAdapter(this, getSupportFragmentManager());
    mViewPager.setAdapter(adapter);
    mTabs.setAdapter(adapter);
    mViewPager.setOnPageChangeListener(mTabs);
    mViewPager.setCurrentItem(0);
}

Wednesday, September 14, 2011

Simple crossfade on an ImageView

In a project I have this ListView where I initially display a list of items that each contain an ImageView with a drawable from the resources. In the background a thread is started to download the actual image and I wanted a crossfade as soon as I could set this downloaded image on the ImageView.

Basically what you need to do is create a new TransitionDrawable where the contents of layer 0 is the current drawable of the image view. And layer 1 will contain the new drawable to which you want to crossfade to. Last thing you need to do is to enable the crossfading, applying this newly created transition drawable on the image and starting the transition.

public static void setImageBitmapWithFade(final ImageView imageView, final Bitmap bitmap) {
 Resources resources = imageView.getResources();
 BitmapDrawable bitmapDrawable = new BitmapDrawable(resources, bitmap);
 setImageDrawableWithFade(imageView, bitmapDrawable);
}
        
public static void setImageDrawableWithFade(final ImageView imageView, final Drawable drawable) {
 Drawable currentDrawable = imageView.getDrawable();
 if (currentDrawable != null) {
  Drawable [] arrayDrawable = new Drawable[2];
  arrayDrawable[0] = currentDrawable;
  arrayDrawable[1] = drawable;
  TransitionDrawable transitionDrawable = new TransitionDrawable(arrayDrawable);
  transitionDrawable.setCrossFadeEnabled(true);
  imageView.setImageDrawable(transitionDrawable);
  transitionDrawable.startTransition(250);
 } else {
  imageView.setImageDrawable(drawable);
 }
}