zoukankan      html  css  js  c++  java
  • 自定义控件省市区:仿苹果级联菜单

    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

  • 相关阅读:
    微信·小程序开发工具安装指南及注意事项
    测试
    PC上面的蓝牙的通信(C#)
    关于图片在div中居中问题
    JSONP---跨域请求问题
    关于position的用法
    APICloud自学笔记总结1
    前端html5
    关于图片自适应div大小问题
    亲身经历——大体量公司能为程序员的生涯带来什么帮助?
  • 原文地址:https://www.cnblogs.com/androidsj/p/3137833.html
Copyright © 2011-2022 走看看