domingo, 1 de abril de 2012

How to use Android Wheel Part II


UPDATE 2016: This guide has a new version that is Android Studio / Gradle / Github friendly! Click here for the article.

The first thing we have to do is define how many columns we will need for the wheel and write an Adapter for each one. These adapters will help us to fill with data every column.

To make the things easier, the following Adapters are ready to use:

NumericWheelAdapter. As is name indicates, this adapter is useful when we just want to fill a column with a sequence of numbers. To use it is necessary to pass in the constructor the first and last number of the sequence.

ArrayWheelAdapter. With this adapter we can fill the column with a defined array and indicate the current value. The array must be String type.

AbstractWheelTextAdapter. This adapter is more flexible than the two previous. In order to use it, we have to create our own adapter and inherit from this class. I will use this adapter for the example so I will explain it in detail later on.

AbstractWheel Adapter. This is the most flexible of all adapters; we can use to fill the columns with any kind of object, for example, images.

In this example we are going to make a picker date so we will need four columns: one for the days, one for the hours, other for the minutes, and one more for the am, pm marker.


For the first column we’ll create one class (which I’ve named “DayWheelAdapter.java”) that inherits from AbstractWheelTextAdapter, but first is necessary define an XML to customize the text of the columns. This XML will work for the four columns.

wheel_item_time.xml
<?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/time_item"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textSize="20dp"
             android:lines="1"
             android:textStyle="bold"
             android:textColor="#FF111111"
             android:layout_gravity="right" />

Now that we have the XML that will contain the text of the column we can create the DayWheelAdapter class. Let’s see the code below:

DayWheelAdapter.java
public class DayWheelAdapter extends AbstractWheelTextAdapter {

       ArrayList<Date> dates;

       //An object of this class must be initialized with an array of Date type
       protected DayWheelAdapter(Context context, ArrayList<Date> dates) {
       //Pass the context and the custom layout for the text to the super method
             super(context, R.layout.wheel_item_time);
             this.dates = dates;
       }

       @Override
    public View getItem(int index, View cachedView, ViewGroup parent) {
             View view = super.getItem(index, cachedView, parent);
             TextView weekday = (TextView) view.findViewById(R.id.time_item);

             //Format the date (Name of the day / number of the day)
             SimpleDateFormat dateFormat = new SimpleDateFormat("EEE dd");
             //Assign the text
             weekday.setText(dateFormat.format(dates.get(index)));
            
             if (index == 0) {
                    //If it is the first date of the array, set the color blue
                    weekday.setText("Today");
                    weekday.setTextColor(0xFF0000F0);
        }
             else{
                    //If not set the color to black
                    weekday.setTextColor(0xFF111111);
             }
            
             return view;
       }
      
       @Override
       public int getItemsCount() {
             return dates.size();
       }

       @Override
       protected CharSequence getItemText(int index) {
             return "";
       }

}


For the second and third columns (hours and minutes respectively) we’ll use the NumericWheelAdapter and for the am pm marker column we’ll apply the ArrayWheelAdpter. In the last piece of code we’ll see how to use them, before, let’s create the XML that actually contains the Android Wheel.

In the dialog_date.xml file I’ve used one “Kankan.wheel.widget.WheelView” label for each column; this widget is the one that simulates the fancy wheel.

dialog_date.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="5dp" >

    <LinearLayout android:id="@+id/wheel"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_gravity="center_horizontal"
        android:paddingBottom="30dp">
     
        <kankan.wheel.widget.WheelView android:id="@+id/day"
            android:layout_height="wrap_content"
            android:layout_width="100dp"/>
        <kankan.wheel.widget.WheelView android:id="@+id/hour"
            android:layout_height="wrap_content"
            android:layout_width="40dp"/>
        <kankan.wheel.widget.WheelView android:id="@+id/minute"
            android:layout_height="wrap_content"
            android:layout_width="40dp"/>
        <kankan.wheel.widget.WheelView android:id="@+id/ampm"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"/>           
    </LinearLayout>

    <Button android:id="@+id/set"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/wheel"
        android:text="@string/setButton"/>
    <Button android:id="@+id/cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/wheel"
        android:layout_toRightOf="@id/set"
        android:text="@string/cancelButton"/> 
               
</RelativeLayout>

Finally in the following piece of code, I show how to configure each column using the “WheelView” class and an Adapter for each one.


//Array for the am/pm marker column
String[] ampmArray = new String[]{"am","pm"};

//With a custom method I get the next following 10 days from now
ArrayList<Date> days = DateUtils.getNextNumberOfDays(new Date(), 10);
            
//Create a custom dialog with the dialog_date.xml file
Dialog dialogSearchByDate = new Dialog(this);
dialogSearchByDate.setContentView(R.layout.dialog_date);
dialogSearchByDate.setTitle("Date");

//Configure Days Column
WheelView day = (WheelView) dialogSearchByDate.findViewById(R.id.day);
day.setViewAdapter(new DayWheelAdapter(this,days));

//Configure Hours Column
WheelView hour = (WheelView) dialogSearchByDate.findViewById(R.id.hour);
NumericWheelAdapter hourAdapter = new NumericWheelAdapter(this, 1, 12);
hourAdapter.setItemResource(R.layout.wheel_item_time);
hourAdapter.setItemTextResource(R.id.time_item);
hour.setViewAdapter(hourAdapter);
       
//Configure Minutes Column
WheelView min = (WheelView) dialogSearchByDate.findViewById(R.id.minute);
NumericWheelAdapter minAdapter = new NumericWheelAdapter(this, 00, 59);
minAdapter.setItemResource(R.layout.wheel_item_time);
minAdapter.setItemTextResource(R.id.time_item);
min.setViewAdapter(minAdapter);
       
//Configure am/pm Marker Column
WheelView ampm = (WheelView) dialogSearchByDate.findViewById(R.id.ampm);
ArrayWheelAdapter<String> ampmAdapter = new ArrayWheelAdapter<String>(this, ampmArray);
ampmAdapter.setItemResource(R.layout.wheel_item_time);
ampmAdapter.setItemTextResource(R.id.time_item);
ampm.setViewAdapter(ampmAdapter);
       
dialogSearchByDate.show();



Well that’s it, this is how I implemented Android Wheel. 

Over time I realized that (or at least that's what I think) is better to keep the look and feel for every platform and not try to mix them in order to give consistence to the user, but that’s up to you.