自定义控件省市区:仿苹果级联菜单

JavaBean类 --- DialogCityItem.java

package cn.newcom.domain;

/**
 * JavaBean
 */
public class DialogCityItem {

    private String name;//省市县 名称
    private String pcode;//对应
    private String desc;//描述

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public String getPcode() {
        return pcode;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPcode(String pcode) {
        this.pcode = pcode;
    }

    @Override
    public String toString() {
        return "MyListItem [name=" + name + ", pcode=" + pcode + "]";
    }
}
View Code

 

日志记录类 --- Loger.java

package cn.newcom.loger;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import android.os.Environment;
import android.util.Log;
/**
 * 日志记录
 */
public class Loger{

    private LogerImp instance;
    
    //日志名称
    private String logerName;
    
    //调试时可以设置为true;发布时需要设置为false;
    protected static boolean isOpen = true;
    
    /**
     * 开始输入日志信息<br\>
     * (只作为程序日志开关,在个人设置中开启,其他应用中不得调用)
     */
    public static void openPrint(){
        if (isOpen){
            LogerImp.instance.startRun();
        }
    }
    
    /**
     * 关闭日志打印 <br\>
     * (只作为程序日志开关,在个人设置中开启,其他应用中不得调用)
     */
    public static void closePrint(){
        if (isOpen){
            LogerImp.instance.stopRun();
        }
    }
    
    private static Loger loger = new Loger("[Loger]");
    
    /**
     * 输出日志信息
     * @param msg String 日志
     */
    public synchronized static void print(String msg){
        if (isOpen){
            loger.output(msg);
        }
    }
    
    /**
     * 输出日志信息及异常发生的详细信息
     * @param msg String 日志
     * @param e Exception
     */
    public synchronized static void print(String msg, Exception e){
        if (isOpen){
            loger.output(msg, e);
        }
    }
    
    /**
     * 构造函数
     * @param name String
     */
    public Loger(String name){
        logerName = name;
        instance = LogerImp.getInstance();
    }
    
    /**
     * 输出日志信息
     * @param msg String 日志
     */
    public synchronized void output(String msg){
        if (isOpen){
            Log.i(logerName, msg);
            instance.submitMsg(logerName+" "+msg);
        }
    }

    /**
     * 输出日志信息及异常发生的详细信息
     * @param msg String 日志
     * @param e Exception
     */
    public synchronized void output(String msg, Exception e){
        if (isOpen){
            Log.i(logerName, msg, e);
            StringBuffer buf = new StringBuffer(msg);
            buf.append(logerName).append(" : ").append(msg).append("\n");
            buf.append(e.getClass()).append(" : ");
            buf.append(e.getLocalizedMessage());
            buf.append("\n");
            StackTraceElement[] stack = e.getStackTrace();
            for(StackTraceElement trace : stack){
                buf.append("\t at ").append(trace.toString()).append("\n");
            }
            instance.submitMsg(buf.toString());
        }
    }
    
    /**
     * 打印当前的内存信息
     */
    public void printCurrentMemory(){
        if (isOpen){
            StringBuilder logs = new StringBuilder();
            long freeMemory = Runtime.getRuntime().freeMemory()/1024;
            long totalMemory = Runtime.getRuntime().totalMemory()/1024;
            long maxMemory = Runtime.getRuntime().maxMemory()/1024;
            logs.append("\t[Memory_free]: ").append(freeMemory).append(" kb");
            logs.append("\t[Memory_total]: ").append(totalMemory).append(" kb");
            logs.append("\t[Memory_max]: ").append(maxMemory).append(" kb");
            Log.i(logerName, logs.toString());
            instance.submitMsg(logerName+" "+logs.toString());
        }
    }
}

/**
 * 日志输出的具体实现类
 * @author Administrator
 *
 */
class LogerImp implements Runnable{

    private Loger log = new Loger("[LogerImp]");
    
    static LogerImp instance = new LogerImp();
    
    //日志存放的队列
    private List<String> printOutList = new ArrayList<String>();
    
    //日志文件
    private FileOutputStream fos = null;
    
    //日志输出流
    private PrintStream print = null;
    
    //时间格式
    private DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    //线程轮询标识
    private boolean runFlag = false;
    
    //当前天,每天生成一个日志文件
    private int currDay = -1;
    
    private GcCheck gcRun = new GcCheck();
        
    class GcCheck implements Runnable {
        
        boolean flag = true;
        
        @Override
        public void run() {
            int count = 40;
            StringBuffer logs = new StringBuffer();
            while(flag){
                if (count >= 50){
                    long freeMemory = Runtime.getRuntime().freeMemory()/1024;
                    long totalMemory = Runtime.getRuntime().totalMemory()/1024;
                    long maxMemory = Runtime.getRuntime().maxMemory()/1024;
                    logs.append("\t[Memory_free]:").append(freeMemory).append(" kb");
                    logs.append("\t[Memory_total]:").append(totalMemory).append(" kb");
                    logs.append("\t[Memory_max]:").append(maxMemory).append(" kb");
                    synchronized (printOutList) {
                        printOutList.add(logs.toString());
                    }
                    Log.i("Memory", logs.toString());
                    logs.setLength(0);
                    if (freeMemory < 400){
                        System.gc();
                        count = 40;
                        logs.append("<GC>");
                    }else{
                        count = 0;
                    }
                }
                try {
                    count++;
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    /**
     * 得到单例对象
     * @return LogerImp
     */
    public static LogerImp getInstance(){
        return instance;
    }
    
    /**
     * 私有方法,单例
     */
    private LogerImp(){
    }
    
//    void listenGC(){
//        gcRun.flag = true;
//        new Thread(gcRun).start();
//    }
    
//    void stopLintenGC(){
//        gcRun.flag = false;
//    }
    
    //初始化文件输出流
    private void initPrint(){
        Calendar date = Calendar.getInstance();
        currDay = date.get(Calendar.DAY_OF_YEAR);
        DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd");
        String fileName = new String(dfm.format(date.getTime())+".txt");
        String path = null;
        try {
            if (null != print){
                close();
            }
            path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/weiboShare/";
            File dir = new File(path);
            if (!dir.exists()){
                dir.mkdir();
            }
            fos = new FileOutputStream(path+fileName, true);
            print = new PrintStream(fos, true);
        } catch (Exception e) {
            log.output("[LogerImp] 未能打开文件:"+path+" 文件名:"+fileName+" 异常描述:"+e.getLocalizedMessage());
        }
    }
    
    /**
     * 线程开启
     */
    public void startRun(){
        if (!runFlag){
            runFlag = true;
            new Thread(this).start();
        }else{
            log.output("[LogerImp] < warn > thread already run !");
        }
    }
    
    /**
     * 线程停止
     */
    public void stopRun(){
        if (runFlag){
            gcRun.flag = false;
            runFlag = false;
            Log.i("Thread", "队列大小:"+printOutList.size());
            printToFile("[LogerImp] < info > thread stop !");
            close();
        }
    }
    
    private void close() {
        print.flush();
        print.close();
        print = null;
        try{
            fos.close();
            fos = null;
        }catch(IOException e){
            e.printStackTrace();
        }
    }

    /**
     * 向队列中增加日志数据
     * @param msg String 日志数据
     */
    protected synchronized void submitMsg(String msg) {
        synchronized (printOutList) {
            printOutList.add(msg);
        }
    }
    
    public void run(){
        try{
            initPrint();
            printToFile("[LogerImp] < info > start new thread ... ");
            while(runFlag){
                runMethod();
            }
            runFlag = false;
        }catch(Exception e){
            printToFile("[LogerImp] < warn > thread error : "+e.getLocalizedMessage());
            if (runFlag){
                printToFile("[LogerImp] 线程强制中断 "+e.getLocalizedMessage());
                new Thread(this).start();
            }
        }
    }
    
    //线程需要重复执行的操作
    private void runMethod() throws Exception {
        String line = null;
        synchronized (printOutList) {
            if (!printOutList.isEmpty()){
                line = printOutList.remove(0);
            }
        }
        if (null != line){
            printToFile(line);
        }else{
            Thread.sleep(10);
        }
    }
    
    //把数据持久到文件
    private void printToFile(String line){
        Calendar date = Calendar.getInstance();
        int day = date.get(Calendar.DAY_OF_YEAR);
        if (day != currDay){
            initPrint();
        }
        if (null == print){
            return;
        }
        print.println(">>> "+format.format(date.getTime())+" -- "+line);
        print.flush();
    }
}
View Code

 

 查询省份数据库的工具类 --- DialogCityDB.java

package cn.newcom.db;

import java.util.ArrayList;
import java.util.List;
import cn.newcom.domain.DialogCityItem;
import cn.newcom.loger.Loger;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

/**
 * 查询省份数据库的工具类
 */
public class DialogCityDB {
    
    private static DialogCityDBManager dbm;
    private static SQLiteDatabase db;
    private static Loger log = new Loger(DialogCityDB.class.getSimpleName());

    /**
     * 查询所有的省份信息
     * @param context Context
     * @return List<MyListItem>
     */
    public static List<DialogCityItem> getAllProInfo(Context context) {
        dbm = new DialogCityDBManager(context);
        dbm.openDatabase();
        db = dbm.getDatabase();
        List<DialogCityItem> list = new ArrayList<DialogCityItem>();
        try {
            String sql = "SELECT DISTINCT (province) FROM CityRegion";
            Cursor cursor = db.rawQuery(sql, null);
            log.output("cursor:" + cursor.getCount());
            int i = 0;
            while (cursor.moveToNext()) {
                i++;
                String province = cursor.getString(cursor.getColumnIndex("province"));
                DialogCityItem myListItem = new DialogCityItem();
                myListItem.setName(province);
                list.add(myListItem);
            }
            log.output("i:" + i);
        } catch (Exception e) {
            log.output("提取所有省份信息异常", e);
        }
        dbm.closeDatabase();
        return list;
    }
    /**
     * 返回所有省份的字符串信息
     * @param context
     * @return
     */
    public static List<String> getAllProInfoStr(Context context) {
        dbm = new DialogCityDBManager(context);
        dbm.openDatabase();
        db = dbm.getDatabase();
        List<String> list = new ArrayList<String>();
        try {
            String sql = "SELECT DISTINCT (province) FROM CityRegion";
            Cursor cursor = db.rawQuery(sql, null);
            log.output("cursor:" + cursor.getCount());
            int i = 0;
            while (cursor.moveToNext()) {
                i++;
                String province = cursor.getString(cursor.getColumnIndex("province"));
                list.add(province);
            }
            log.output("i:" + i);
        } catch (Exception e) {
            log.output("提取所有省份信息异常", e);
        }
        dbm.closeDatabase();
        return list;
    }
    /**
     * 获取指定省份的城市信息
     * @param context Context
     * @param pro String
     * @return List<MyListItem>
     */
    public static List<DialogCityItem> getCityInfo(Context context, String pro) {
        dbm = new DialogCityDBManager(context);
        dbm.openDatabase();
        db = dbm.getDatabase();
        List<DialogCityItem> list = new ArrayList<DialogCityItem>();
        try {
            String sql = "select DISTINCT(city) from CityRegion where province = ?";
            Cursor cursor = db.rawQuery(sql, new String[] { pro });
            while (cursor.moveToNext()) {
                String city = cursor.getString(cursor.getColumnIndex("city"));
                DialogCityItem myListItem = new DialogCityItem();
                myListItem.setName(city);
                list.add(myListItem);
            }
        } catch (Exception e) {
            log.output("提取指定省份信息异常,省份:"+pro, e);
        }
        dbm.closeDatabase();
        db.close();
        return list;
    }
    
    public static List<String> getCityInfoStr(Context context, String pro) {
        dbm = new DialogCityDBManager(context);
        dbm.openDatabase();
        db = dbm.getDatabase();
        List<String> list = new ArrayList<String>();
        try {
            String sql = "select DISTINCT(city) from CityRegion where province = ?";
            Cursor cursor = db.rawQuery(sql, new String[] { pro });
            while (cursor.moveToNext()) {
                String city = cursor.getString(cursor.getColumnIndex("city"));
                list.add(city);
            }
        } catch (Exception e) {
            log.output("提取指定省份信息异常,省份:"+pro, e);
        }
        dbm.closeDatabase();
        db.close();
        return list;
    }

    /**
     * 获取指定城市下的县级信息
     * @param context Context
     * @param pro String 省份
     * @param city String 城市
     * @return List<MyListItem>
     */
    public static List<DialogCityItem> getCountyInfo(Context context, String pro, String city) {
        dbm = new DialogCityDBManager(context);
        dbm.openDatabase();
        db = dbm.getDatabase();
        List<DialogCityItem> list = new ArrayList<DialogCityItem>();
        try {
            String sql = "select code,area,desc from CityRegion where province = ? and city = ? ";
            Cursor cursor = db.rawQuery(sql, new String[] { pro, city });
            while (cursor.moveToNext()) {
                String area = cursor.getString(cursor.getColumnIndex("area"));
                String code = cursor.getString(cursor.getColumnIndex("code"));
                String desc = cursor.getString(cursor.getColumnIndex("desc"));
                DialogCityItem myListItem = new DialogCityItem();
                myListItem.setName(area);
                myListItem.setPcode(code);
                myListItem.setDesc(desc);
                list.add(myListItem);
            }
            cursor.close();
        } catch (Exception e) {
            log.output("提取指定的县级信息异常,省份:"+pro+"  城市:"+city, e);
        }
        dbm.closeDatabase();
        db.close();
        return list;
    }
}
View Code

 

操作已有数据库的类(复制到SD卡中) --- DialogCityDBManager.java

package cn.newcom.db;

/**
 * 操作已有数据库的类——复制到SD卡中
 */
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import cn.newcom.loger.Loger;
import cn.newcom.pickdemo.R;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.util.Log;

public class DialogCityDBManager {
    private final int BUFFER_SIZE = 1024;
    public static final String DB_NAME = "xxt.db";
    //其他应用用到时,需要修改包名
    public static final String PACKAGE_NAME = "cn.newcom.pickdemo";
    // 把raw目录下的数据库文件复制到data下
    public static final String DB_PATH = "/data"
            + Environment.getDataDirectory().getAbsolutePath() + "/"
            + PACKAGE_NAME + "/databases";

    private SQLiteDatabase database;
    private Context context;
    private File file = null;
    private Loger log = new Loger("[" + this.getClass().getSimpleName() + "]");
    public DialogCityDBManager(Context context) {
        this.context = context;
    }

    public void openDatabase() {
        this.database = this.openDatabase(DB_PATH + "/" + DB_NAME);
    }

    public SQLiteDatabase getDatabase() {
        return this.database;
    }

    private SQLiteDatabase openDatabase(String dbfile) {
        try {
            log.output("路径:" + DB_PATH);
            Log.e("cc", "open and return");

            File dir = new File(DB_PATH);
            if (!dir.exists())
                dir.mkdir();
            file = new File(dbfile);
            if (!file.exists()) {
                Log.e("cc", "file");
                InputStream is = context.getResources().openRawResource(
                        R.raw.xxt);
                if (is == null) {
                    Log.e("cc", "is null");
                }
                FileOutputStream fos = new FileOutputStream(dbfile);
                if (fos != null) {
                    Log.e("cc", "fos null");
                }
                byte[] buffer = new byte[BUFFER_SIZE];
                int count = 0;
                while ((count = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, count);
                    fos.flush();
                }
                fos.close();
                is.close();
            }
            database = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
            return database;
        } catch (FileNotFoundException e) {
            Log.e("cc", "File not found");
            e.printStackTrace();
        } catch (IOException e) {
            Log.e("cc", "IO exception");
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("cc", "exception " + e.toString());
        }
        return null;
    }

    public void closeDatabase() {
        Log.e("cc", "closeDatabase()");
        if (this.database != null)
            this.database.close();
    }
}
View Code

 

适配list集合的 适配器 --- ArrayWheelAdapter1.java

package cn.newcom.pickdemo;

/**
 * 适配list集合的 适配器
 */
import java.util.List;
import cn.newcom.wheelview.WheelAdapter;

public class ArrayWheelAdapter1 implements WheelAdapter {
    public static final int DEFAULT_LENGTH = -1;
    private List<String> list;
    private int length;
    public ArrayWheelAdapter1(List<String> list, int length) {
        this.list = list;
        this.length = length;
    }
    public ArrayWheelAdapter1(List<String> list) {
        this(list, DEFAULT_LENGTH);
    }

    @Override
    public int getItemsCount() {
        return list.size();
    }

    @Override
    public int getMaximumLength() {
        return length;
    }
    @Override
    public String getItem(int index) {
        return list.get(index);
    }
}
View Code

 

省市联动的主页面,使用自定义控件 --- PickViewDemoActivity.java

package cn.newcom.pickdemo;

/**
 * 省市联动的主页面,使用自定义控件
 */
import java.util.ArrayList;
import java.util.List;
import cn.newcom.db.DialogCityDB;
import cn.newcom.domain.DialogCityItem;
import cn.newcom.pickdemo.R;
import cn.newcom.wheelview.OnWheelChangedListener;
import cn.newcom.wheelview.WheelView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class PickViewDemoActivity extends Activity {
    private WheelView province;//省份控件
    private WheelView city;
    private WheelView town;
    private String pro;
    private String ct;
    private String tw;
    private List<String> pros;//省份名称集合
    private List<String> cities;
    private List<String> towns;
    private List<DialogCityItem> countyInfo;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.cities_layout);
        province = (WheelView) findViewById(R.id.province);
        city = (WheelView) findViewById(R.id.city);
        town = (WheelView) findViewById(R.id.town);
        initPickPro();
    }
    //初始化省份列表
    private void initPickPro() {
        pros = DialogCityDB.getAllProInfoStr(this);
        province.setAdapter(new ArrayWheelAdapter1(pros));
//        province.setCurrentItem(pros.size()/2);
        province.addChangingListener(new ProListener());
    }
    
    //省份列表滑动监听
    private class ProListener implements OnWheelChangedListener{
        @Override
        public void onChanged(WheelView wheel, int oldValue, int newValue) {
            pro = pros.get(newValue);
            initPickCity(pro);
        }
    }
    //初始化城市列表
    public void initPickCity(String pro) {
        cities = DialogCityDB.getCityInfoStr(this, pro);
        city.setAdapter(new ArrayWheelAdapter1(cities));
        city.setCurrentItem(cities.size()/2);
        city.addChangingListener(new CityListener());
    }
    
    
    private class CityListener implements OnWheelChangedListener{
        @Override
        public void onChanged(WheelView wheel, int oldValue, int newValue) {
            ct = cities.get(newValue);
            initPickTown(pro , ct);
        }
    }
    public void initPickTown(String pro, String city) {
        countyInfo = DialogCityDB.getCountyInfo(this, pro, city);
        towns = new ArrayList<String>();
        for (int i = 0; i < countyInfo.size(); i++) {
            towns.add(countyInfo.get(i).getName());
        }
        town.setAdapter(new ArrayWheelAdapter1(towns));
        town.setCurrentItem(towns.size()/2);
        town.addChangingListener(new TownListener());
    }
    private String desc;
    private String pcode;
    private class TownListener implements OnWheelChangedListener{
        @Override
        public void onChanged(WheelView wheel, int oldValue, int newValue) {
            DialogCityItem dc = countyInfo.get(newValue);
            desc = dc.getDesc();
            pcode = dc.getPcode();
        }
    }
    public void done(View v){
        String content = desc + "," + pcode ;
        Toast.makeText(this, content, 0).show();
    }
}
View Code

自定义控件 --- WheelView.java

/*
 *  Android Wheel Control.
 *  https://code.google.com/p/android-wheel/
 *  
 *  Copyright 2010 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package cn.newcom.wheelview;

/**
 * 自定义控件
 */
import java.util.LinkedList;
import java.util.List;

import cn.newcom.pickdemo.R;
import cn.newcom.pickdemo.R.drawable;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.Handler;
import android.os.Message;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.Scroller;

/**
 * Numeric wheel view.
 */
public class WheelView extends View {
    /** Scrolling duration */
    private static final int SCROLLING_DURATION = 400;

    /** Minimum delta for scrolling */
    private static final int MIN_DELTA_FOR_SCROLLING = 1;

    /** Current value & label text color */
    private static final int VALUE_TEXT_COLOR = 0xF0000000;

    /** Items text color */
    private static final int ITEMS_TEXT_COLOR = 0xFF000000;

    /** Top and bottom shadows colors */
    private static final int[] SHADOWS_COLORS = new int[] { 0xFF111111,
            0x00AAAAAA, 0x00AAAAAA };

    /** Additional items height (is added to standard text item height) */
    private static final int ADDITIONAL_ITEM_HEIGHT = 15;

    /** Text size */
    private static final int TEXT_SIZE = 24;

    /** Top and bottom items offset (to hide that) */
    private static final int ITEM_OFFSET = TEXT_SIZE / 5;

    /** Additional width for items layout */
    private static final int ADDITIONAL_ITEMS_SPACE = 10;

    /** Label offset */
    private static final int LABEL_OFFSET = 8;

    /** Left and right padding value */
    private static final int PADDING = 10;

    /** Default count of visible items */
    private static final int DEF_VISIBLE_ITEMS = 5;

    // Wheel Values
    private WheelAdapter adapter = null;
    private int currentItem = 0;
    
    // Widths
    private int itemsWidth = 0;
    private int labelWidth = 0;

    // Count of visible items
    private int visibleItems = DEF_VISIBLE_ITEMS;
    
    // Item height
    private int itemHeight = 0;

    // Text paints
    private TextPaint itemsPaint;
    private TextPaint valuePaint;

    // Layouts
    private StaticLayout itemsLayout;
    private StaticLayout labelLayout;
    private StaticLayout valueLayout;

    // Label & background
    private String label;
    private Drawable centerDrawable;

    // Shadows drawables
    private GradientDrawable topShadow;
    private GradientDrawable bottomShadow;

    // Scrolling
    private boolean isScrollingPerformed; 
    private int scrollingOffset;

    // Scrolling animation
    private GestureDetector gestureDetector;
    private Scroller scroller;
    private int lastScrollY;

    // Cyclic
    boolean isCyclic = false;
    
    // Listeners
    private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();
    private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();

    /**
     * Constructor
     */
    public WheelView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initData(context);
    }

    /**
     * Constructor
     */
    public WheelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initData(context);
    }

    /**
     * Constructor
     */
    public WheelView(Context context) {
        super(context);
        initData(context);
    }
    
    /**
     * Initializes class data
     * @param context the context
     */
    private void initData(Context context) {
        gestureDetector = new GestureDetector(context, gestureListener);
        gestureDetector.setIsLongpressEnabled(false);
        
        scroller = new Scroller(context);
    }
    
    /**
     * Gets wheel adapter
     * @return the adapter
     */
    public WheelAdapter getAdapter() {
        return adapter;
    }
    
    /**
     * Sets wheel adapter
     * @param adapter the new wheel adapter
     */
    public void setAdapter(WheelAdapter adapter) {
        this.adapter = adapter;
        invalidateLayouts();
        invalidate();
    }
    
    /**
     * Set the the specified scrolling interpolator
     * @param interpolator the interpolator
     */
    public void setInterpolator(Interpolator interpolator) {
        scroller.forceFinished(true);
        scroller = new Scroller(getContext(), interpolator);
    }
    
    /**
     * Gets count of visible items
     * 
     * @return the count of visible items
     */
    public int getVisibleItems() {
        return visibleItems;
    }

    /**
     * Sets count of visible items
     * 
     * @param count
     *            the new count
     */
    public void setVisibleItems(int count) {
        visibleItems = count;
        invalidate();
    }

    /**
     * Gets label
     * 
     * @return the label
     */
    public String getLabel() {
        return label;
    }

    /**
     * Sets label
     * 
     * @param newLabel
     *            the label to set
     */
    public void setLabel(String newLabel) {
        if (label == null || !label.equals(newLabel)) {
            label = newLabel;
            labelLayout = null;
            invalidate();
        }
    }
    
    /**
     * Adds wheel changing listener
     * @param listener the listener 
     */
    public void addChangingListener(OnWheelChangedListener listener) {
        changingListeners.add(listener);
    }

    /**
     * Removes wheel changing listener
     * @param listener the listener
     */
    public void removeChangingListener(OnWheelChangedListener listener) {
        changingListeners.remove(listener);
    }
    
    /**
     * Notifies changing listeners
     * @param oldValue the old wheel value
     * @param newValue the new wheel value
     */
    protected void notifyChangingListeners(int oldValue, int newValue) {
        for (OnWheelChangedListener listener : changingListeners) {
            listener.onChanged(this, oldValue, newValue);
        }
    }

    /**
     * Adds wheel scrolling listener
     * @param listener the listener 
     */
    public void addScrollingListener(OnWheelScrollListener listener) {
        scrollingListeners.add(listener);
    }

    /**
     * Removes wheel scrolling listener
     * @param listener the listener
     */
    public void removeScrollingListener(OnWheelScrollListener listener) {
        scrollingListeners.remove(listener);
    }
    
    /**
     * Notifies listeners about starting scrolling
     */
    protected void notifyScrollingListenersAboutStart() {
        for (OnWheelScrollListener listener : scrollingListeners) {
            listener.onScrollingStarted(this);
        }
    }

    /**
     * Notifies listeners about ending scrolling
     */
    protected void notifyScrollingListenersAboutEnd() {
        for (OnWheelScrollListener listener : scrollingListeners) {
            listener.onScrollingFinished(this);
        }
    }

    /**
     * Gets current value
     * 
     * @return the current value
     */
    public int getCurrentItem() {
        return currentItem;
    }

    /**
     * Sets the current item. Does nothing when index is wrong.
     * 
     * @param index the item index
     * @param animated the animation flag
     */
    public void setCurrentItem(int index, boolean animated) {
        if (adapter == null || adapter.getItemsCount() == 0) {
            return; // throw?
        }
        if (index < 0 || index >= adapter.getItemsCount()) {
            if (isCyclic) {
                while (index < 0) {
                    index += adapter.getItemsCount();
                }
                index %= adapter.getItemsCount();
            } else{
                return; // throw?
            }
        }
        if (index != currentItem) {
            if (animated) {
                scroll(index - currentItem, SCROLLING_DURATION);
            } else {
                invalidateLayouts();
            
                int old = currentItem;
                currentItem = index;
            
                notifyChangingListeners(old, currentItem);
            
                invalidate();
            }
        }
    }

    /**
     * Sets the current item w/o animation. Does nothing when index is wrong.
     * 
     * @param index the item index
     */
    public void setCurrentItem(int index) {
        setCurrentItem(index, false);
    }    
    
    /**
     * Tests if wheel is cyclic. That means before the 1st item there is shown the last one
     * @return true if wheel is cyclic
     */
    public boolean isCyclic() {
        return isCyclic;
    }

    /**
     * Set wheel cyclic flag
     * @param isCyclic the flag to set
     */
    public void setCyclic(boolean isCyclic) {
        this.isCyclic = isCyclic;
        
        invalidate();
        invalidateLayouts();
    }

    /**
     * Invalidates layouts
     */
    private void invalidateLayouts() {
        itemsLayout = null;
        valueLayout = null;
        scrollingOffset = 0;
    }

    /**
     * Initializes resources
     */
    private void initResourcesIfNecessary() {
        if (itemsPaint == null) {
            itemsPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG
                    | Paint.FAKE_BOLD_TEXT_FLAG);
            //itemsPaint.density = getResources().getDisplayMetrics().density;
            itemsPaint.setTextSize(TEXT_SIZE);
        }

        if (valuePaint == null) {
            valuePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG
                    | Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG);
            //valuePaint.density = getResources().getDisplayMetrics().density;
            valuePaint.setTextSize(TEXT_SIZE);
            valuePaint.setShadowLayer(0.1f, 0, 0.1f, 0xFFC0C0C0);
        }

        if (centerDrawable == null) {
            centerDrawable = getContext().getResources().getDrawable(R.drawable.wheel_val);
        }

        if (topShadow == null) {
            topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);
        }

        if (bottomShadow == null) {
            bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);
        }

        setBackgroundResource(R.drawable.wheel_bg);
    }

    /**
     * Calculates desired height for layout
     * 
     * @param layout
     *            the source layout
     * @return the desired layout height
     */
    private int getDesiredHeight(Layout layout) {
        if (layout == null) {
            return 0;
        }

        int desired = getItemHeight() * visibleItems - ITEM_OFFSET * 2
                - ADDITIONAL_ITEM_HEIGHT;

        // Check against our minimum height
        desired = Math.max(desired, getSuggestedMinimumHeight());

        return desired;
    }

    /**
     * Returns text item by index
     * @param index the item index
     * @return the item or null
     */
    private String getTextItem(int index) {
        if (adapter == null || adapter.getItemsCount() == 0) {
            return null;
        }
        int count = adapter.getItemsCount();
        if ((index < 0 || index >= count) && !isCyclic) {
            return null;
        } else {
            while (index < 0) {
                index = count + index;
            }
        }
        
        index %= count;
        return adapter.getItem(index);
    }
    
    /**
     * Builds text depending on current value
     * 
     * @param useCurrentValue
     * @return the text
     */
    private String buildText(boolean useCurrentValue) {
        StringBuilder itemsText = new StringBuilder();
        int addItems = visibleItems / 2 + 1;

        for (int i = currentItem - addItems; i <= currentItem + addItems; i++) {
            if (useCurrentValue || i != currentItem) {
                String text = getTextItem(i);
                if (text != null) {
                    itemsText.append(text);
                }
            }
            if (i < currentItem + addItems) {
                itemsText.append("\n");
            }
        }
        
        return itemsText.toString();
    }

    /**
     * Returns the max item length that can be present
     * @return the max length
     */
    private int getMaxTextLength() {
        WheelAdapter adapter = getAdapter();
        if (adapter == null) {
            return 0;
        }
        
        int adapterLength = adapter.getMaximumLength();
        if (adapterLength > 0) {
            return adapterLength;
        }

        String maxText = null;
        int addItems = visibleItems / 2;
        for (int i = Math.max(currentItem - addItems, 0);
                i < Math.min(currentItem + visibleItems, adapter.getItemsCount()); i++) {
            String text = adapter.getItem(i);
            if (text != null && (maxText == null || maxText.length() < text.length())) {
                maxText = text;
            }
        }

        return maxText != null ? maxText.length() : 0;
    }

    /**
     * Returns height of wheel item
     * @return the item height
     */
    private int getItemHeight() {
        if (itemHeight != 0) {
            return itemHeight;
        } else if (itemsLayout != null && itemsLayout.getLineCount() > 2) {
            itemHeight = itemsLayout.getLineTop(2) - itemsLayout.getLineTop(1);
            return itemHeight;
        }
        
        return getHeight() / visibleItems;
    }

    /**
     * Calculates control width and creates text layouts
     * @param widthSize the input layout width
     * @param mode the layout mode
     * @return the calculated control width
     */
    private int calculateLayoutWidth(int widthSize, int mode) {
        initResourcesIfNecessary();

        int width = widthSize;

        int maxLength = getMaxTextLength();
        if (maxLength > 0) {
            float textWidth = FloatMath.ceil(Layout.getDesiredWidth("0", itemsPaint));
            itemsWidth = (int) (maxLength * textWidth);
        } else {
            itemsWidth = 0;
        }
        itemsWidth += ADDITIONAL_ITEMS_SPACE; // make it some more

        labelWidth = 0;
        if (label != null && label.length() > 0) {
            labelWidth = (int) FloatMath.ceil(Layout.getDesiredWidth(label, valuePaint));
        }

        boolean recalculate = false;
        if (mode == MeasureSpec.EXACTLY) {
            width = widthSize;
            recalculate = true;
        } else {
            width = itemsWidth + labelWidth + 2 * PADDING;
            if (labelWidth > 0) {
                width += LABEL_OFFSET;
            }

            // Check against our minimum width
            width = Math.max(width, getSuggestedMinimumWidth());

            if (mode == MeasureSpec.AT_MOST && widthSize < width) {
                width = widthSize;
                recalculate = true;
            }
        }

        if (recalculate) {
            // recalculate width
            int pureWidth = width - LABEL_OFFSET - 2 * PADDING;
            if (pureWidth <= 0) {
                itemsWidth = labelWidth = 0;
            }
            if (labelWidth > 0) {
                double newWidthItems = (double) itemsWidth * pureWidth
                        / (itemsWidth + labelWidth);
                itemsWidth = (int) newWidthItems;
                labelWidth = pureWidth - itemsWidth;
            } else {
                itemsWidth = pureWidth + LABEL_OFFSET; // no label
            }
        }

        if (itemsWidth > 0) {
            createLayouts(itemsWidth, labelWidth);
        }

        return width;
    }

    /**
     * Creates layouts
     * @param widthItems width of items layout
     * @param widthLabel width of label layout
     */
    private void createLayouts(int widthItems, int widthLabel) {
        if (itemsLayout == null || itemsLayout.getWidth() > widthItems) {
            itemsLayout = new StaticLayout(buildText(isScrollingPerformed), itemsPaint, widthItems,
                    widthLabel > 0 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,
                    1, ADDITIONAL_ITEM_HEIGHT, false);
        } else {
            itemsLayout.increaseWidthTo(widthItems);
        }

        if (!isScrollingPerformed && (valueLayout == null || valueLayout.getWidth() > widthItems)) {
            String text = getAdapter() != null ? getAdapter().getItem(currentItem) : null;
            valueLayout = new StaticLayout(text != null ? text : "",
                    valuePaint, widthItems, widthLabel > 0 ?
                            Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,
                            1, ADDITIONAL_ITEM_HEIGHT, false);
        } else if (isScrollingPerformed) {
            valueLayout = null;
        } else {
            valueLayout.increaseWidthTo(widthItems);
        }

        if (widthLabel > 0) {
            if (labelLayout == null || labelLayout.getWidth() > widthLabel) {
                labelLayout = new StaticLayout(label, valuePaint,
                        widthLabel, Layout.Alignment.ALIGN_NORMAL, 1,
                        ADDITIONAL_ITEM_HEIGHT, false);
            } else {
                labelLayout.increaseWidthTo(widthLabel);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width = calculateLayoutWidth(widthSize, widthMode);

        int height;
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = getDesiredHeight(itemsLayout);

            if (heightMode == MeasureSpec.AT_MOST) {
                height = Math.min(height, heightSize);
            }
        }

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        
        if (itemsLayout == null) {
            if (itemsWidth == 0) {
                calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);
            } else {
                createLayouts(itemsWidth, labelWidth);
            }
        }

        if (itemsWidth > 0) {
            canvas.save();
            // Skip padding space and hide a part of top and bottom items
            canvas.translate(PADDING, -ITEM_OFFSET);
            drawItems(canvas);
            drawValue(canvas);
            canvas.restore();
        }

        drawCenterRect(canvas);
        drawShadows(canvas);
    }

    /**
     * Draws shadows on top and bottom of control
     * @param canvas the canvas for drawing
     */
    private void drawShadows(Canvas canvas) {
        topShadow.setBounds(0, 0, getWidth(), getHeight() / visibleItems);
        topShadow.draw(canvas);

        bottomShadow.setBounds(0, getHeight() - getHeight() / visibleItems,
                getWidth(), getHeight());
        bottomShadow.draw(canvas);
    }

    /**
     * Draws value and label layout
     * @param canvas the canvas for drawing
     */
    private void drawValue(Canvas canvas) {
        valuePaint.setColor(VALUE_TEXT_COLOR);
        valuePaint.drawableState = getDrawableState();

        Rect bounds = new Rect();
        itemsLayout.getLineBounds(visibleItems / 2, bounds);

        // draw label
        if (labelLayout != null) {
            canvas.save();
            canvas.translate(itemsLayout.getWidth() + LABEL_OFFSET, bounds.top);
            labelLayout.draw(canvas);
            canvas.restore();
        }

        // draw current value
        if (valueLayout != null) {
            canvas.save();
            canvas.translate(0, bounds.top + scrollingOffset);
            valueLayout.draw(canvas);
            canvas.restore();
        }
    }

    /**
     * Draws items
     * @param canvas the canvas for drawing
     */
    private void drawItems(Canvas canvas) {
        canvas.save();
        
        int top = itemsLayout.getLineTop(1);
        canvas.translate(0, - top + scrollingOffset);
        
        itemsPaint.setColor(ITEMS_TEXT_COLOR);
        itemsPaint.drawableState = getDrawableState();
        itemsLayout.draw(canvas);
        
        canvas.restore();
    }

    /**
     * Draws rect for current value
     * @param canvas the canvas for drawing
     */
    private void drawCenterRect(Canvas canvas) {
        int center = getHeight() / 2;
        int offset = getItemHeight() / 2;
        centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);
        centerDrawable.draw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        WheelAdapter adapter = getAdapter();
        if (adapter == null) {
            return true;
        }
        
            if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {
            justify();
        }
        return true;
    }
    
    /**
     * Scrolls the wheel
     * @param delta the scrolling value
     */
    private void doScroll(int delta) {
        scrollingOffset += delta;
        
        int count = scrollingOffset / getItemHeight();
        int pos = currentItem - count;
        if (isCyclic && adapter.getItemsCount() > 0) {
            // fix position by rotating
            while (pos < 0) {
                pos += adapter.getItemsCount();
            }
            pos %= adapter.getItemsCount();
        } else if (isScrollingPerformed) {
            // 
            if (pos < 0) {
                count = currentItem;
                pos = 0;
            } else if (pos >= adapter.getItemsCount()) {
                count = currentItem - adapter.getItemsCount() + 1;
                pos = adapter.getItemsCount() - 1;
            }
        } else {
            // fix position
            pos = Math.max(pos, 0);
            pos = Math.min(pos, adapter.getItemsCount() - 1);
        }
        
        int offset = scrollingOffset;
        if (pos != currentItem) {
            setCurrentItem(pos, false);
        } else {
            invalidate();
        }
        
        // update offset
        scrollingOffset = offset - count * getItemHeight();
        if (scrollingOffset > getHeight()) {
            scrollingOffset = scrollingOffset % getHeight() + getHeight();
        }
    }
    
    // gesture listener
    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
        public boolean onDown(MotionEvent e) {
            if (isScrollingPerformed) {
                scroller.forceFinished(true);
                clearMessages();
                return true;
            }
            return false;
        }
        
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            startScrolling();
            doScroll((int)-distanceY);
            return true;
        }
        
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            lastScrollY = currentItem * getItemHeight() + scrollingOffset;
            int maxY = isCyclic ? 0x7FFFFFFF : adapter.getItemsCount() * getItemHeight();
            int minY = isCyclic ? -maxY : 0;
            scroller.fling(0, lastScrollY, 0, (int) -velocityY / 2, 0, 0, minY, maxY);
            setNextMessage(MESSAGE_SCROLL);
            return true;
        }
    };

    // Messages
    private final int MESSAGE_SCROLL = 0;
    private final int MESSAGE_JUSTIFY = 1;
    
    /**
     * Set next message to queue. Clears queue before.
     * 
     * @param message the message to set
     */
    private void setNextMessage(int message) {
        clearMessages();
        animationHandler.sendEmptyMessage(message);
    }

    /**
     * Clears messages from queue
     */
    private void clearMessages() {
        animationHandler.removeMessages(MESSAGE_SCROLL);
        animationHandler.removeMessages(MESSAGE_JUSTIFY);
    }
    
    // animation handler
    private Handler animationHandler = new Handler() {
        public void handleMessage(Message msg) {
            scroller.computeScrollOffset();
            int currY = scroller.getCurrY();
            int delta = lastScrollY - currY;
            lastScrollY = currY;
            if (delta != 0) {
                doScroll(delta);
            }
            
            // scrolling is not finished when it comes to final Y
            // so, finish it manually 
            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
                currY = scroller.getFinalY();
                scroller.forceFinished(true);
            }
            if (!scroller.isFinished()) {
                animationHandler.sendEmptyMessage(msg.what);
            } else if (msg.what == MESSAGE_SCROLL) {
                justify();
            } else {
                finishScrolling();
            }
        }
    };
    
    /**
     * Justifies wheel
     */
    private void justify() {
        if (adapter == null) {
            return;
        }
        
        lastScrollY = 0;
        int offset = scrollingOffset;
        int itemHeight = getItemHeight();
        boolean needToIncrease = offset > 0 ? currentItem < adapter.getItemsCount() : currentItem > 0; 
        if ((isCyclic || needToIncrease) && Math.abs((float) offset) > (float) itemHeight / 2) {
            if (offset < 0)
                offset += itemHeight + MIN_DELTA_FOR_SCROLLING;
            else
                offset -= itemHeight + MIN_DELTA_FOR_SCROLLING;
        }
        if (Math.abs(offset) > MIN_DELTA_FOR_SCROLLING) {
            scroller.startScroll(0, 0, 0, offset, SCROLLING_DURATION);
            setNextMessage(MESSAGE_JUSTIFY);
        } else {
            finishScrolling();
        }
    }
    
    /**
     * Starts scrolling
     */
    private void startScrolling() {
        if (!isScrollingPerformed) {
            isScrollingPerformed = true;
            notifyScrollingListenersAboutStart();
        }
    }

    /**
     * Finishes scrolling
     */
    void finishScrolling() {
        if (isScrollingPerformed) {
            notifyScrollingListenersAboutEnd();
            isScrollingPerformed = false;
        }
        invalidateLayouts();
        invalidate();
    }
    
    
    /**
     * Scroll the wheel
     * @param itemsToSkip items to scroll
     * @param time scrolling duration
     */
    public void scroll(int itemsToScroll, int time) {
        scroller.forceFinished(true);

        lastScrollY = scrollingOffset;
        int offset = itemsToScroll * getItemHeight();
        
        scroller.startScroll(0, lastScrollY, 0, offset - lastScrollY, time);
        setNextMessage(MESSAGE_SCROLL);
        
        startScrolling();
    }

}
View Code

 

OnWheelChangedListener.java

/*
 *  Copyright 2010 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package cn.newcom.wheelview;


/**
 * Wheel changed listener interface.
 * <p>The currentItemChanged() method is called whenever current wheel positions is changed:
 * <li> New Wheel position is set
 * <li> Wheel view is scrolled
 */
public interface OnWheelChangedListener {
    /**
     * Callback method to be invoked when current item changed
     * @param wheel the wheel view whose state has changed
     * @param oldValue the old value of current item
     * @param newValue the new value of current item
     */
    void onChanged(WheelView wheel, int oldValue, int newValue);
}
View Code

 

OnWheelScrollListener.java

/*
 *  Copyright 2010 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package cn.newcom.wheelview;


/**
 * Wheel scrolled listener interface.
 */
public interface OnWheelScrollListener {
    /**
     * Callback method to be invoked when scrolling started.
     * @param wheel the wheel view whose state has changed.
     */
    void onScrollingStarted(WheelView wheel);
    
    /**
     * Callback method to be invoked when scrolling ended.
     * @param wheel the wheel view whose state has changed.
     */
    void onScrollingFinished(WheelView wheel);
}
View Code

 

WheelAdapter.java

/*
 *  Copyright 2010 Yuri Kanivets
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package cn.newcom.wheelview;

public interface WheelAdapter {
    /**
     * Gets items count
     * @return the count of wheel items
     */
    public int getItemsCount();
    
    /**
     * Gets a wheel item by index.
     * 
     * @param index the item index
     * @return the wheel item text or null
     */
    public String getItem(int index);
    
    /**
     * Gets maximum item length. It is used to determine the wheel width. 
     * If -1 is returned there will be used the default wheel width.
     * 
     * @return the maximum item length or -1
     */
    public int getMaximumLength();
}
View Code

 

cities_layout.xml

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/layout_bg"
    android:gravity="center"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <cn.newcom.wheelview.WheelView
            android:id="@+id/province"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1" />

        <cn.newcom.wheelview.WheelView
            android:id="@+id/city"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_weight="1" />

        <cn.newcom.wheelview.WheelView
            android:id="@+id/town"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_weight="1" />
    </LinearLayout>
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="确定"
        android:onClick="done"
        />
</LinearLayout>
View Code

 

 

 

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>
View Code

 

DEMO 完整下载路径:http://download.csdn.net/detail/androidsj/5587597

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2013-06-15 17:53  大米稀饭  阅读(652)  评论(0编辑  收藏  举报