├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── feealan │ │ └── wheelview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── city.json │ │ └── type.json │ ├── java │ │ └── com │ │ │ └── feealan │ │ │ └── wheelview │ │ │ ├── MainActivity.java │ │ │ ├── bean │ │ │ ├── CityBean.java │ │ │ └── TypeBean.java │ │ │ ├── utils │ │ │ ├── CityUtils.java │ │ │ ├── SizeConvertUtil.java │ │ │ ├── TimeUtils.java │ │ │ └── TypeUtils.java │ │ │ └── widget │ │ │ ├── BaseDialog.java │ │ │ ├── CityPickerDialog.java │ │ │ ├── MoneyPickerDialog.java │ │ │ ├── SexPickerDialog.java │ │ │ ├── TimePickerDialog.java │ │ │ ├── TypePickerDialog.java │ │ │ └── WheelView.java │ └── res │ │ ├── anim │ │ ├── photo_dialog_in_anim.xml │ │ └── photo_dialog_out_anim.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── dialog_city_picker.xml │ │ ├── dialog_money_picker.xml │ │ ├── dialog_sp_type_picker.xml │ │ └── dialog_time_picker.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── feealan │ └── wheelview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── picker.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea 10 | app/build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CustomWheelView 2 | 自定义WheelView, 实现时间选择器,城市选择器 3 | # 效果 4 | ![picker.gif](picker.gif) 5 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.feealan.wheelview" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.4.0' 26 | compile 'com.google.code.gson:gson:2.6.2' 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\AndroidIDE\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/feealan/wheelview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/assets/type.json: -------------------------------------------------------------------------------- 1 | [{"p":"运动与健身","c":[{"content":"爱跑步","num":1},{"content":"马拉松","num":2},{"content":"健康徒步","num":3},{"content":"篮球","num":4},{"content":"足球","num":5},{"content":"羽毛球","num":6},{"content":"网球","num":7}],"n":1},{"p":"会议与展览","c":[{"content":"创业路演","num":1},{"content":"电子商务","num":2},{"content":"峰会沙龙","num":3},{"content":"资源对接","num":4},{"content":"实战风享","num":5},{"content":"投融资","num":6},{"content":"招商会","num":7}],"n":2},{"p":"亲子与幼教","c":[{"content":"手工DIY","num":1},{"content":"绘本阅读","num":2},{"content":"亲子摄影","num":3},{"content":"素质拓展","num":4},{"content":"职业体验","num":5},{"content":"家庭教育","num":6},{"content":"探索自然","num":7}],"n":3}] -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.Toast; 9 | 10 | import com.feealan.wheelview.widget.CityPickerDialog; 11 | import com.feealan.wheelview.widget.MoneyPickerDialog; 12 | import com.feealan.wheelview.widget.SexPickerDialog; 13 | import com.feealan.wheelview.widget.TimePickerDialog; 14 | import com.feealan.wheelview.widget.TypePickerDialog; 15 | 16 | import java.text.SimpleDateFormat; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 21 | 22 | private Button btn_money_picker; 23 | private Button btn_sex_picker; 24 | private Button btn_time_picker; 25 | private MoneyPickerDialog money_dialog; 26 | private SexPickerDialog sex_dialog; 27 | private TimePickerDialog time_Dialog; 28 | private TypePickerDialog typePickerDialog; 29 | private CityPickerDialog cityPickerDialog; 30 | private List city_list = new ArrayList<>(); 31 | private Button btn_aihao_picker; 32 | private Button btn_city_picker; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_main); 38 | initView(); 39 | } 40 | 41 | private void initView() { 42 | btn_money_picker = (Button) findViewById(R.id.btn_money_picker); 43 | 44 | btn_money_picker.setOnClickListener(this); 45 | 46 | btn_sex_picker = (Button) findViewById(R.id.btn_sex_picker); 47 | btn_time_picker = (Button) findViewById(R.id.btn_time_picker); 48 | btn_sex_picker.setOnClickListener(this); 49 | btn_time_picker.setOnClickListener(this); 50 | 51 | 52 | money_dialog = new MoneyPickerDialog(this); 53 | money_dialog.setCallback(new MoneyPickerDialog.OnClickCallback() { 54 | @Override 55 | public void onCancel() { 56 | money_dialog.dismiss(); 57 | } 58 | 59 | @Override 60 | public void onSure(String data) { 61 | Log.d("aa", data); 62 | Toast.makeText(MainActivity.this,data,Toast.LENGTH_SHORT).show(); 63 | money_dialog.dismiss(); 64 | } 65 | }); 66 | sex_dialog = new SexPickerDialog(this); 67 | sex_dialog.setCallback(new SexPickerDialog.OnClickCallback() { 68 | @Override 69 | public void onCancel() { 70 | sex_dialog.dismiss(); 71 | } 72 | 73 | @Override 74 | public void onSure(String data) { 75 | Log.d("aa", data); 76 | Toast.makeText(MainActivity.this,data,Toast.LENGTH_SHORT).show(); 77 | 78 | sex_dialog.dismiss(); 79 | } 80 | }); 81 | 82 | time_Dialog = new TimePickerDialog(this); 83 | time_Dialog.setCallback(new TimePickerDialog.OnClickCallback() { 84 | @Override 85 | public void onCancel() { 86 | time_Dialog.dismiss(); 87 | } 88 | 89 | @Override 90 | public void onSure(int year, int month, int day, int hour, int minter, long time) { 91 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 92 | String date = dateFormat.format(time); 93 | Log.d("aa", date + ">>"); 94 | Toast.makeText(MainActivity.this,date,Toast.LENGTH_SHORT).show(); 95 | time_Dialog.dismiss(); 96 | } 97 | }); 98 | btn_aihao_picker = (Button) findViewById(R.id.btn_aihao_picker); 99 | btn_aihao_picker.setOnClickListener(this); 100 | typePickerDialog = new TypePickerDialog(this); 101 | typePickerDialog.setCallback(new TypePickerDialog.OnClickCallback() { 102 | @Override 103 | public void onCancel() { 104 | 105 | } 106 | 107 | @Override 108 | public void onSure(int f, int s, String fristType, String sencondType) { 109 | Toast.makeText(MainActivity.this,fristType+"--"+sencondType,Toast.LENGTH_SHORT).show(); 110 | Log.d("aa", f + ">>" + s + ">>" + fristType + ">>" + sencondType); 111 | } 112 | }); 113 | btn_city_picker = (Button) findViewById(R.id.btn_city_picker); 114 | btn_city_picker.setOnClickListener(this); 115 | cityPickerDialog = new CityPickerDialog(this); 116 | cityPickerDialog.setCallback(new CityPickerDialog.OnClickCallback() { 117 | @Override 118 | public void onCancel() { 119 | 120 | } 121 | 122 | @Override 123 | public void onSure(String province, String city, String county, String data) { 124 | Toast.makeText(MainActivity.this,province+"--"+city+"--"+county,Toast.LENGTH_SHORT).show(); 125 | Log.d("AA", ">>" + province + ">>" + city + ">>" + county + ">>" + data); 126 | } 127 | }); 128 | } 129 | 130 | @Override 131 | public void onClick(View v) { 132 | switch (v.getId()) { 133 | case R.id.btn_money_picker: 134 | money_dialog.show(); 135 | break; 136 | case R.id.btn_sex_picker: 137 | sex_dialog.show(); 138 | break; 139 | case R.id.btn_time_picker: 140 | time_Dialog.show(); 141 | break; 142 | case R.id.btn_aihao_picker: 143 | typePickerDialog.show(); 144 | break; 145 | case R.id.btn_city_picker: 146 | cityPickerDialog.show(); 147 | break; 148 | 149 | 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/bean/CityBean.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 解析城市数据实体类 7 | * 8 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 9 | * @created 2016/05/16 10 | */ 11 | public class CityBean { 12 | 13 | /** 14 | * area : 010 15 | * code : 110111 16 | * level : 2 17 | * name : 房山区 18 | * prefix : 区 19 | */ 20 | 21 | private String area; 22 | private String code; 23 | private int level; 24 | private String name; 25 | private String prefix; 26 | private List cities; 27 | 28 | public List getCities() { 29 | return cities; 30 | } 31 | 32 | public void setCities(List cities) { 33 | this.cities = cities; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "CityBean{" + 39 | "area='" + area + '\'' + 40 | ", code='" + code + '\'' + 41 | ", level=" + level + 42 | ", name='" + name + '\'' + 43 | ", prefix='" + prefix + '\'' + 44 | ", cities=" + cities + 45 | '}'; 46 | } 47 | 48 | public void setArea(String area) { 49 | this.area = area; 50 | } 51 | 52 | public void setCode(String code) { 53 | this.code = code; 54 | } 55 | 56 | public void setLevel(int level) { 57 | this.level = level; 58 | } 59 | 60 | public void setName(String name) { 61 | this.name = name; 62 | } 63 | 64 | public void setPrefix(String prefix) { 65 | this.prefix = prefix; 66 | } 67 | 68 | public String getArea() { 69 | return area; 70 | } 71 | 72 | public String getCode() { 73 | return code; 74 | } 75 | 76 | public int getLevel() { 77 | return level; 78 | } 79 | 80 | public String getName() { 81 | return name; 82 | } 83 | 84 | public String getPrefix() { 85 | return prefix; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/bean/TypeBean.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 活动类型解析实体类 7 | * 8 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 9 | * @created 2016/05/16 10 | */ 11 | public class TypeBean { 12 | private String p; 13 | private int n; 14 | private List c; 15 | 16 | public TypeBean(String p, int n, List c) { 17 | this.p = p; 18 | this.n = n; 19 | this.c = c; 20 | } 21 | 22 | public String getP() { 23 | return p; 24 | } 25 | 26 | public void setP(String p) { 27 | this.p = p; 28 | } 29 | 30 | public int getN() { 31 | return n; 32 | } 33 | 34 | public void setN(int n) { 35 | this.n = n; 36 | } 37 | 38 | public List getC() { 39 | return c; 40 | } 41 | 42 | public void setC(List c) { 43 | this.c = c; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "TypeBean{" + 49 | "p='" + p + '\'' + 50 | ", n=" + n + 51 | ", c=" + c + 52 | '}'; 53 | } 54 | 55 | public static class Cbean { 56 | private String content; 57 | private int num; 58 | 59 | @Override 60 | public String toString() { 61 | return "Cbean{" + 62 | "content='" + content + '\'' + 63 | ", num=" + num + 64 | '}'; 65 | } 66 | 67 | public Cbean(int num, String content) { 68 | this.num = num; 69 | this.content = content; 70 | } 71 | 72 | public String getContent() { 73 | return content; 74 | } 75 | 76 | public void setContent(String content) { 77 | this.content = content; 78 | } 79 | 80 | public int getNum() { 81 | return num; 82 | } 83 | 84 | public void setNum(int num) { 85 | this.num = num; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/utils/CityUtils.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.utils; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.feealan.wheelview.bean.CityBean; 7 | import com.google.gson.Gson; 8 | import com.google.gson.reflect.TypeToken; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * 城市数据提供公工具类 19 | * 20 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 21 | * @created 2016/05/16 22 | */ 23 | public class CityUtils { 24 | 25 | private Context mContext; 26 | private List mList; 27 | /** 28 | * 默认的城市 29 | */ 30 | private List defCity = new ArrayList<>(); 31 | /** 32 | * 城市集合 33 | */ 34 | private List cityList = new ArrayList<>(); 35 | /** 36 | * 默认的县 区 37 | */ 38 | private List defX = new ArrayList<>(); 39 | /** 40 | * 县 区集合 41 | */ 42 | private List xList = new ArrayList<>(); 43 | 44 | public CityUtils(Context mContext) { 45 | this.mContext = mContext; 46 | String json = init(this.mContext); 47 | mList = parseProvince(json); 48 | defCity.add("东城区"); 49 | defCity.add("西城区"); 50 | defCity.add("朝阳区"); 51 | defX.add(" "); 52 | defX.add(" "); 53 | defX.add(" "); 54 | } 55 | 56 | /** 57 | * 从assets中获取数据 58 | * 59 | * @param context 60 | * @return 61 | */ 62 | private String init(Context context) { 63 | InputStream inputStream; 64 | StringBuffer stringBuffer = new StringBuffer(); 65 | try { 66 | inputStream = context.getResources().getAssets().open("city.json"); 67 | InputStreamReader isr = new InputStreamReader(inputStream, "UTF-8"); 68 | BufferedReader bfr = new BufferedReader(isr); 69 | String in; 70 | while ((in = bfr.readLine()) != null) { 71 | stringBuffer.append(in); 72 | } 73 | inputStream.close(); 74 | isr.close(); 75 | bfr.close(); 76 | return stringBuffer.toString(); 77 | 78 | } catch (IOException e) { 79 | e.printStackTrace(); 80 | } 81 | return null; 82 | } 83 | 84 | private List parseProvince(String json) { 85 | if (!json.equals("") && !"".equals(json)) { 86 | Gson gson = new Gson(); 87 | return gson.fromJson(json, new TypeToken>() { 88 | }.getType()); 89 | } else { 90 | return null; 91 | } 92 | } 93 | 94 | /** 95 | * 创建省份数据 96 | */ 97 | public List createProvince() { 98 | List list = new ArrayList<>(); 99 | for (CityBean bean : mList) { 100 | list.add(bean.getName()); 101 | } 102 | // Log.d("aa", list.toString()); 103 | return list; 104 | } 105 | 106 | public List createCity() { 107 | return defCity; 108 | } 109 | 110 | /** 111 | * 根据省份编号获取城市 112 | * 113 | * @param pIndex 114 | * @return 115 | */ 116 | public List createCity(int pIndex) { 117 | cityList.clear(); 118 | for (int i = 0; i < mList.size(); i++) { 119 | if (i == pIndex) { 120 | for (CityBean bean : mList.get(i).getCities()) { 121 | cityList.add(bean.getName()); 122 | } 123 | } 124 | } 125 | return cityList; 126 | } 127 | 128 | /** 129 | * 根据省份和城市编号获取县 或者区 130 | * 131 | * @param pIndex 132 | * @param cIndex 133 | * @return 134 | */ 135 | public List createdX(int pIndex, int cIndex) { 136 | 137 | List city_list = mList.get(pIndex).getCities(); 138 | Log.d("aa", "pIndex>>>" + pIndex + "cIndex>>" + cIndex + "city_list>>>>" + city_list.size() + ">>>" + city_list.toString()); 139 | for (int i = 0; i < city_list.size(); i++) { 140 | if (i == cIndex && city_list.get(i).getCities().size() != 0) { 141 | xList.clear(); 142 | for (int j = 0; j < city_list.get(i).getCities().size(); j++) { 143 | xList.add(city_list.get(i).getCities().get(j).getName()); 144 | } 145 | Log.d("aa", "xianqu" + xList.toString()); 146 | return xList; 147 | } 148 | } 149 | return defX; 150 | } 151 | 152 | public List createdX() { 153 | return defX; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/utils/SizeConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.utils; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * 尺寸转换工具 7 | * 8 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 9 | * @created 2016/05/16 10 | */ 11 | public class SizeConvertUtil { 12 | 13 | private SizeConvertUtil() { 14 | } 15 | 16 | public static int dpTopx(Context context, float dp) { 17 | final float scale = context.getResources().getDisplayMetrics().density; 18 | return (int) (dp * scale + 0.5f); 19 | } 20 | 21 | public static int pxTodp(Context context, float px) { 22 | final float scale = context.getResources().getDisplayMetrics().density; 23 | return (int) (px / scale + 0.5f); 24 | } 25 | 26 | public static int pxTosp(Context context, float px) { 27 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 28 | return (int) (px / fontScale + 0.5f); 29 | } 30 | 31 | public static int spTopx(Context context, float sp) { 32 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 33 | return (int) (sp * fontScale + 0.5f); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 时间数据提供工具类 8 | * 9 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 10 | * @created 2016/05/16 11 | */ 12 | public class TimeUtils { 13 | public static final int MIN_YEAR = 1970; 14 | public static final int MAX_YEAR = 2099; 15 | 16 | /** 17 | * Wheel TYPE Year 18 | */ 19 | public static final int TYPE_YEAR = 1; 20 | /** 21 | * Wheel TYPE Month 22 | */ 23 | public static final int TYPE_MONTH = 2; 24 | /** 25 | * Wheel TYPE Day 26 | */ 27 | public static final int TYPE_DAY = 3; 28 | /** 29 | * Wheel TYPE Hour 30 | */ 31 | public static final int TYPE_HOUR = 4; 32 | /** 33 | * Wheel TYPE Minute 34 | */ 35 | public static final int TYPE_MINUTE = 5; 36 | 37 | private TimeUtils() { 38 | } 39 | 40 | /** 41 | * 创建年份数据 42 | * 43 | * @return 44 | */ 45 | 46 | public static List getItemList(int type) { 47 | if (type == TYPE_YEAR) { 48 | return createdYear(); 49 | } else if (type == TYPE_MONTH) { 50 | return createdMonth(); 51 | } else if (type == TYPE_DAY) { 52 | return createdDay(); 53 | } else if (type == TYPE_HOUR) { 54 | return createdHour(); 55 | } else if (type == TYPE_MINUTE) { 56 | return createdMniter(); 57 | } else { 58 | throw new IllegalArgumentException("type is illegal"); 59 | } 60 | } 61 | 62 | private static List createdYear() { 63 | List wheelString = new ArrayList<>(); 64 | for (int i = MIN_YEAR; i <= MAX_YEAR; i++) { 65 | wheelString.add(Integer.toString(i)); 66 | } 67 | return wheelString; 68 | } 69 | 70 | /** 71 | * 创建月份数据 72 | * 73 | * @return 74 | */ 75 | private static List createdMonth() { 76 | List wheelString = new ArrayList<>(); 77 | for (int i = 1; i <= 12; i++) { 78 | wheelString.add(String.format("%02d", i)); 79 | } 80 | return wheelString; 81 | } 82 | 83 | 84 | /** 85 | * 创建日期数据 86 | * 87 | * @return 88 | */ 89 | private static List createdDay() { 90 | List wheelString = new ArrayList<>(); 91 | for (int i = 1; i <= 31; i++) { 92 | wheelString.add(String.format("%02d", i)); 93 | } 94 | return wheelString; 95 | } 96 | 97 | /** 98 | * 根据年 月创建日期数据 99 | * 100 | * @return 101 | */ 102 | public static List createdDay(int year, int month) { 103 | List wheelString = new ArrayList<>(); 104 | int size = 0; 105 | if (isLeapMonth(month)) { 106 | size = 31; 107 | } else if (month == 2) { 108 | if (isLeapYear(year)) { 109 | size = 29; 110 | } else { 111 | size = 28; 112 | } 113 | } else { 114 | size = 30; 115 | } 116 | 117 | for (int i = 1; i <= size; i++) { 118 | wheelString.add(String.format("%02d", i)); 119 | } 120 | return wheelString; 121 | } 122 | 123 | 124 | /** 125 | * 创建小时数据 126 | * 127 | * @return 128 | */ 129 | private static List createdHour() { 130 | List wheelString = new ArrayList<>(); 131 | for (int i = 0; i <= 23; i++) { 132 | wheelString.add(String.format("%02d", i)); 133 | } 134 | return wheelString; 135 | } 136 | 137 | /** 138 | * 创建分钟数据 139 | * 140 | * @return 141 | */ 142 | private static List createdMniter() { 143 | List wheelString = new ArrayList<>(); 144 | for (int i = 0; i <= 59; i++) { 145 | wheelString.add(String.format("%02d", i)); 146 | } 147 | return wheelString; 148 | } 149 | 150 | /** 151 | * 计算大小月 152 | * 153 | * @param month 154 | * @return 155 | */ 156 | private static boolean isLeapMonth(int month) { 157 | return month == 1 || month == 3 || month == 5 || month == 7 158 | || month == 8 || month == 10 || month == 12; 159 | } 160 | 161 | /** 162 | * 计算闰年 163 | * 164 | * @param year 165 | * @return 166 | */ 167 | private static boolean isLeapYear(int year) { 168 | return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/utils/TypeUtils.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.utils; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.feealan.wheelview.bean.TypeBean; 7 | import com.google.gson.Gson; 8 | import com.google.gson.reflect.TypeToken; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * 活动类型数据提供工具类 19 | * 20 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 21 | * @created 2016/05/16 22 | */ 23 | public class TypeUtils { 24 | private Context mContext; 25 | private List mList; 26 | 27 | /*存放第二个wheelview值*/ 28 | private List SList = new ArrayList<>(); 29 | private List defaultList = new ArrayList<>(); 30 | 31 | 32 | public TypeUtils(Context context) { 33 | this.mContext = context; 34 | mList = initData(mContext); 35 | defaultList.add("爱跑步"); 36 | defaultList.add("马拉松"); 37 | defaultList.add("健康徒步"); 38 | } 39 | 40 | private List initData(Context context) { 41 | InputStream inputStream; 42 | StringBuffer stringBuffer = new StringBuffer(); 43 | try { 44 | inputStream = context.getResources().getAssets().open("type.json"); 45 | InputStreamReader isr = new InputStreamReader(inputStream, "UTF-8"); 46 | BufferedReader bfr = new BufferedReader(isr); 47 | String in; 48 | while ((in = bfr.readLine()) != null) { 49 | stringBuffer.append(in); 50 | } 51 | inputStream.close(); 52 | isr.close(); 53 | bfr.close(); 54 | return praseP(stringBuffer.toString()); 55 | 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | return null; 60 | } 61 | 62 | private List praseP(String json) { 63 | Gson gson = new Gson(); 64 | List list = gson.fromJson(json, new TypeToken>() { 65 | }.getType()); 66 | List cbean = gson.fromJson(json, new TypeToken>() { 67 | }.getType()); 68 | for (TypeBean bean : list) { 69 | Log.d("aa", bean.toString()); 70 | } 71 | return list; 72 | } 73 | 74 | public List createFrist() { 75 | /*存放第一个wheelview值*/ 76 | List fList = new ArrayList<>(); 77 | for (TypeBean bean : mList) { 78 | fList.add(bean.getP()); 79 | } 80 | Log.d("aa", fList.toString()); 81 | return fList; 82 | 83 | } 84 | 85 | public List createSecond() { 86 | return defaultList; 87 | } 88 | 89 | public List createSecond(int index) { 90 | //防止之前添加到集合的值还存在于集合内 91 | if (mList != null) { 92 | SList.clear(); 93 | for (int i = 0; i < mList.size(); i++) { 94 | if (index == i) { 95 | for (TypeBean.Cbean b : mList.get(i).getC()) { 96 | SList.add(b.getContent()); 97 | } 98 | } 99 | } 100 | Log.d("aa", SList.toString()); 101 | return SList; 102 | } else { 103 | return defaultList; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/BaseDialog.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.view.Window; 8 | import android.view.WindowManager; 9 | 10 | import com.feealan.wheelview.R; 11 | 12 | /** 13 | * 选择器弹窗基类 14 | * 15 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 16 | * @created 2016/05/16 17 | */ 18 | public class BaseDialog implements View.OnClickListener { 19 | protected Dialog dialog; 20 | protected Context mContext; 21 | 22 | protected BaseDialog(Context context) { 23 | this.mContext = context; 24 | this.dialog = new Dialog(mContext, R.style.picker_dialog); 25 | } 26 | 27 | 28 | protected void setDialogLocation(Context context, Dialog dialog) { 29 | Window window = dialog.getWindow(); 30 | window.setWindowAnimations(R.style.main_menu_animstyle); 31 | WindowManager.LayoutParams lp = window.getAttributes(); 32 | WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 33 | lp.x = 0; 34 | lp.y = manager.getDefaultDisplay().getHeight(); 35 | // 以下这两句是为了保证按钮可以水平满屏 36 | lp.width = ViewGroup.LayoutParams.MATCH_PARENT; 37 | lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; 38 | // 设置显示位置 39 | dialog.onWindowAttributesChanged(lp); 40 | // 设置点击外围解散 41 | dialog.setCanceledOnTouchOutside(true); 42 | } 43 | 44 | public void show() { 45 | if (dialog != null) { 46 | dialog.show(); 47 | } 48 | } 49 | 50 | public void dismiss() { 51 | if (dialog != null) { 52 | dialog.dismiss(); 53 | } 54 | } 55 | 56 | @Override 57 | public void onClick(View v) { 58 | dismiss(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/CityPickerDialog.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import com.feealan.wheelview.R; 10 | import com.feealan.wheelview.utils.CityUtils; 11 | 12 | /** 13 | * 城市选择器 14 | * 15 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 16 | * @created 2016/05/16 17 | */ 18 | public class CityPickerDialog extends BaseDialog { 19 | private TextView tv_cancel; 20 | private TextView tv_sure; 21 | private TextView tv_title; 22 | private WheelView province_wheel; 23 | private WheelView city_wheel; 24 | private WheelView county_wheel; 25 | private OnClickCallback callback; 26 | /*省*/ 27 | private int p; 28 | /*市*/ 29 | private int c; 30 | /*县*/ 31 | private int x; 32 | /*省*/ 33 | private String province; 34 | /*市*/ 35 | private String city; 36 | /*县*/ 37 | private String county; 38 | 39 | public CityPickerDialog(Context context) { 40 | super(context); 41 | final CityUtils cityUtils = new CityUtils(mContext); 42 | this.dialog = new Dialog(mContext, R.style.picker_dialog); 43 | dialog.setContentView(R.layout.dialog_city_picker); 44 | tv_cancel = (TextView) dialog.findViewById(R.id.cancel); 45 | tv_sure = (TextView) dialog.findViewById(R.id.ok); 46 | tv_title = (TextView) dialog.findViewById(R.id.title); 47 | tv_title.setText("请选择城市"); 48 | tv_cancel.setOnClickListener(this); 49 | tv_sure.setOnClickListener(this); 50 | tv_title.setOnClickListener(this); 51 | province_wheel = (WheelView) dialog.findViewById(R.id.wheel_p); 52 | city_wheel = (WheelView) dialog.findViewById(R.id.wheel_c); 53 | county_wheel = (WheelView) dialog.findViewById(R.id.wheel_x); 54 | //设置默认值 55 | province = cityUtils.createProvince().get(p); 56 | city = cityUtils.createCity().get(c); 57 | county = cityUtils.createdX().get(x); 58 | 59 | province_wheel.setData(cityUtils.createProvince()); 60 | city_wheel.setData(cityUtils.createCity()); 61 | county_wheel.setData(cityUtils.createdX()); 62 | province_wheel.setOnSelectListener(new WheelView.SelectListener() { 63 | @Override 64 | public void onSelect(int index, String text) { 65 | p = index; 66 | province = text; 67 | city_wheel.setWheelItemList(cityUtils.createCity(p)); 68 | county_wheel.setWheelItemList(cityUtils.createdX(p, c)); 69 | Log.d("aa", p + "<<<<" + c + ">>>>" + cityUtils.createCity(p).size() + ">>>>>>" + cityUtils.createdX(p, c).size()); 70 | city = cityUtils.createCity(p).get(c); 71 | county = cityUtils.createdX(p, c).get(x); 72 | } 73 | }); 74 | city_wheel.setOnSelectListener(new WheelView.SelectListener() { 75 | @Override 76 | public void onSelect(int index, String text) { 77 | c = index; 78 | city = text; 79 | county_wheel.setWheelItemList(cityUtils.createdX(p, c)); 80 | Log.d("aa", "city_wheel>>>>>" + p + "<<<<" + c + ">>>>" + cityUtils.createCity(p).size() + ">>>>>>" + cityUtils.createdX(p, c).size()); 81 | county = cityUtils.createdX(p, c).get(x); 82 | } 83 | }); 84 | county_wheel.setOnSelectListener(new WheelView.SelectListener() { 85 | @Override 86 | public void onSelect(int index, String text) { 87 | x = index; 88 | county = text; 89 | } 90 | }); 91 | 92 | 93 | setDialogLocation(mContext, dialog); 94 | } 95 | 96 | 97 | public void setCallback(OnClickCallback callback) { 98 | this.callback = callback; 99 | } 100 | 101 | @Override 102 | public void onClick(View v) { 103 | super.onClick(v); 104 | 105 | switch (v.getId()) { 106 | case R.id.cancel: 107 | if (callback != null) { 108 | callback.onCancel(); 109 | } 110 | break; 111 | case R.id.ok: 112 | if (callback != null) { 113 | callback.onSure(province, city, county, ">>"); 114 | } 115 | break; 116 | } 117 | } 118 | 119 | public interface OnClickCallback { 120 | void onCancel(); 121 | 122 | /** 123 | * 返回的数据 124 | * 125 | * @param province 省 126 | * @param city 市 127 | * @param county 县 128 | * @param data 包含省市县的数字拼接字符 129 | */ 130 | void onSure(String province, String city, String county, String data); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/MoneyPickerDialog.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.feealan.wheelview.R; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * 收费选择器 15 | * 16 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 17 | * @created 2016/05/16 18 | */ 19 | public class MoneyPickerDialog extends BaseDialog { 20 | 21 | private TextView tv_cancel; 22 | private TextView tv_sure; 23 | private TextView tv_title; 24 | private WheelView wheelView; 25 | private OnClickCallback callback; 26 | private String data; 27 | private List list; 28 | 29 | public MoneyPickerDialog(Context context) { 30 | super(context); 31 | this.mContext = context; 32 | this.list = new ArrayList<>(); 33 | list.add("全部"); 34 | list.add("收费"); 35 | list.add("免费"); 36 | this.dialog = new Dialog(mContext, R.style.picker_dialog); 37 | dialog.setContentView(R.layout.dialog_money_picker); 38 | tv_cancel = (TextView) dialog.findViewById(R.id.cancel); 39 | tv_sure = (TextView) dialog.findViewById(R.id.ok); 40 | tv_title = (TextView) dialog.findViewById(R.id.title); 41 | tv_title.setText("是否收费"); 42 | wheelView = (WheelView) dialog.findViewById(R.id.wheel); 43 | wheelView.setData(list); 44 | data = list.get(0); 45 | wheelView.setOnSelectListener(new WheelView.SelectListener() { 46 | @Override 47 | public void onSelect(int index, String text) { 48 | data = text; 49 | } 50 | }); 51 | tv_cancel.setOnClickListener(this); 52 | tv_sure.setOnClickListener(this); 53 | 54 | setDialogLocation(mContext, dialog); 55 | } 56 | 57 | @Override 58 | public void onClick(View v) { 59 | super.onClick(v); 60 | switch (v.getId()) { 61 | case R.id.ok: 62 | if (callback != null) { 63 | if (!data.equals("") && !"".equals(data)) { 64 | callback.onSure(data); 65 | } 66 | } 67 | break; 68 | case R.id.cancel: 69 | if (callback != null) { 70 | callback.onCancel(); 71 | } 72 | break; 73 | } 74 | } 75 | 76 | public void setCallback(OnClickCallback callback) { 77 | this.callback = callback; 78 | } 79 | 80 | public interface OnClickCallback { 81 | void onCancel(); 82 | 83 | void onSure(String data); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/SexPickerDialog.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.feealan.wheelview.R; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * 性别选择器 15 | * 16 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 17 | * @created 2016/05/16 18 | */ 19 | public class SexPickerDialog extends BaseDialog { 20 | 21 | private TextView tv_title; 22 | private TextView tv_cancel; 23 | private TextView tv_sure; 24 | private WheelView wheelView; 25 | private OnClickCallback callback; 26 | private String data; 27 | private List list; 28 | 29 | @Override 30 | public void onClick(View v) { 31 | super.onClick(v); 32 | switch (v.getId()) { 33 | case R.id.ok: 34 | if (callback != null) { 35 | if (!data.equals("") && !"".equals(data)) { 36 | callback.onSure(data); 37 | } 38 | } 39 | break; 40 | case R.id.cancel: 41 | if (callback != null) { 42 | callback.onCancel(); 43 | } 44 | break; 45 | } 46 | } 47 | 48 | public SexPickerDialog(Context context) { 49 | super(context); 50 | this.mContext = context; 51 | this.list = new ArrayList<>(); 52 | list.add("全部"); 53 | list.add("男"); 54 | list.add("女"); 55 | this.dialog = new Dialog(mContext, R.style.picker_dialog); 56 | dialog.setContentView(R.layout.dialog_money_picker); 57 | tv_cancel = (TextView) dialog.findViewById(R.id.cancel); 58 | tv_sure = (TextView) dialog.findViewById(R.id.ok); 59 | wheelView = (WheelView) dialog.findViewById(R.id.wheel); 60 | tv_title = (TextView) dialog.findViewById(R.id.title); 61 | tv_title.setText("选择性别"); 62 | wheelView.setData(list); 63 | data = list.get(0); 64 | wheelView.setOnSelectListener(new WheelView.SelectListener() { 65 | @Override 66 | public void onSelect(int index, String text) { 67 | data = text; 68 | } 69 | }); 70 | tv_cancel.setOnClickListener(this); 71 | tv_sure.setOnClickListener(this); 72 | setDialogLocation(mContext, dialog); 73 | } 74 | 75 | public void setCallback(OnClickCallback callback) { 76 | this.callback = callback; 77 | } 78 | 79 | public interface OnClickCallback { 80 | void onCancel(); 81 | 82 | void onSure(String data); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/TimePickerDialog.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.feealan.wheelview.R; 9 | import com.feealan.wheelview.utils.TimeUtils; 10 | 11 | import java.util.Calendar; 12 | import java.util.Date; 13 | 14 | /** 15 | * 时间选择器 16 | * 17 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 18 | * @created 2016/05/16 19 | */ 20 | public class TimePickerDialog extends BaseDialog { 21 | private TextView cancel; 22 | private TextView title; 23 | private TextView ok; 24 | private WheelView wheel_y; 25 | private WheelView wheel_m; 26 | private WheelView wheel_d; 27 | private WheelView wheel_h; 28 | private WheelView wheel_mi; 29 | private int year = 0; 30 | private int month = 0; 31 | private int day = 0; 32 | private int hour = 0; 33 | private int minter = 0; 34 | private long time = 0; 35 | private OnClickCallback callback; 36 | 37 | public TimePickerDialog(Context context) { 38 | super(context); 39 | dialog.setContentView(R.layout.dialog_time_picker); 40 | cancel = (TextView) dialog.findViewById(R.id.cancel); 41 | title = (TextView) dialog.findViewById(R.id.title); 42 | ok = (TextView) dialog.findViewById(R.id.ok); 43 | title.setText("请选择时间"); 44 | cancel.setOnClickListener(this); 45 | ok.setOnClickListener(this); 46 | wheel_y = (WheelView) dialog.findViewById(R.id.wheel_y); 47 | wheel_m = (WheelView) dialog.findViewById(R.id.wheel_m); 48 | wheel_d = (WheelView) dialog.findViewById(R.id.wheel_d); 49 | wheel_h = (WheelView) dialog.findViewById(R.id.wheel_h); 50 | wheel_mi = (WheelView) dialog.findViewById(R.id.wheel_mi); 51 | wheel_y.setData(TimeUtils.getItemList(TimeUtils.TYPE_YEAR)); 52 | wheel_y.setOnSelectListener(new WheelView.SelectListener() { 53 | @Override 54 | public void onSelect(int index, String text) { 55 | year = index + TimeUtils.MIN_YEAR; 56 | 57 | } 58 | }); 59 | wheel_m.setData(TimeUtils.getItemList(TimeUtils.TYPE_MONTH)); 60 | wheel_m.setOnSelectListener(new WheelView.SelectListener() { 61 | @Override 62 | public void onSelect(int index, String text) { 63 | month = index + 1; 64 | wheel_d.setData(TimeUtils.createdDay(year, month)); 65 | } 66 | }); 67 | wheel_d.setData(TimeUtils.getItemList(TimeUtils.TYPE_DAY)); 68 | wheel_h.setData(TimeUtils.getItemList(TimeUtils.TYPE_HOUR)); 69 | wheel_mi.setData(TimeUtils.getItemList(TimeUtils.TYPE_MINUTE)); 70 | 71 | Date date = new Date(System.currentTimeMillis()); 72 | Log.d("aa", date.getYear() + ">>" + date.getMonth() + ">>" + date.getDate() + ">>" + date.getHours() + ">>" + date.getMinutes()); 73 | wheel_y.setCurrentItem(date.getYear() - 70); 74 | wheel_m.setCurrentItem(date.getMonth()); 75 | wheel_d.setCurrentItem(date.getDate() - 1); 76 | wheel_h.setCurrentItem(date.getHours()); 77 | wheel_mi.setCurrentItem(date.getMinutes()); 78 | 79 | setDialogLocation(mContext, dialog); 80 | } 81 | 82 | @Override 83 | public void onClick(View v) { 84 | super.onClick(v); 85 | switch (v.getId()) { 86 | case R.id.ok: 87 | if (callback != null) { 88 | int year = wheel_y.getCurrentItem(); 89 | int month = wheel_m.getCurrentItem(); 90 | int day = wheel_d.getCurrentItem(); 91 | int daySize = wheel_d.getItemCount(); 92 | if (day > daySize) { 93 | day = day - daySize; 94 | } 95 | int hour = wheel_h.getCurrentItem() - 12; 96 | int min = wheel_mi.getCurrentItem(); 97 | 98 | Calendar calendar = Calendar.getInstance(); 99 | calendar.set(Calendar.YEAR, year + 1900 + 70); 100 | calendar.set(Calendar.MONTH, month); 101 | calendar.set(Calendar.DATE, day + 1); 102 | calendar.set(Calendar.HOUR, hour); 103 | calendar.set(Calendar.MINUTE, min); 104 | 105 | long setTime = calendar.getTimeInMillis(); 106 | callback.onSure(year, month, day, hour, minter, setTime); 107 | } 108 | break; 109 | case R.id.cancel: 110 | if (callback != null) { 111 | callback.onCancel(); 112 | } 113 | break; 114 | } 115 | } 116 | 117 | public void setCallback(OnClickCallback callback) { 118 | this.callback = callback; 119 | } 120 | 121 | public interface OnClickCallback { 122 | void onCancel(); 123 | 124 | /** 125 | * 126 | * @param year 用于界面显示 下同 127 | * @param month 128 | * @param day 129 | * @param hour 130 | * @param minter 131 | * @param time 用于给服务器传值 132 | */ 133 | void onSure(int year, int month, int day, int hour, int minter, long time); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/TypePickerDialog.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.feealan.wheelview.R; 8 | import com.feealan.wheelview.utils.TypeUtils; 9 | 10 | /** 11 | * 运动类型选择器 12 | * 13 | * @author fee https://github.com/FeeAlan QQ:752115651 费松柏 14 | * @created 2016/05/16 15 | */ 16 | public class TypePickerDialog extends BaseDialog { 17 | 18 | private TextView cancel; 19 | private TextView title; 20 | private TextView ok; 21 | private WheelView wheel_p; 22 | private WheelView wheel_c; 23 | private String data; 24 | private OnClickCallback callback; 25 | private String fristType; 26 | private String sencondType; 27 | private int f; 28 | private int s; 29 | 30 | public TypePickerDialog(Context context) { 31 | super(context); 32 | final TypeUtils typeUtils = new TypeUtils(mContext); 33 | dialog.setContentView(R.layout.dialog_sp_type_picker); 34 | cancel = (TextView) dialog.findViewById(R.id.cancel); 35 | title = (TextView) dialog.findViewById(R.id.title); 36 | ok = (TextView) dialog.findViewById(R.id.ok); 37 | title.setText("选择活动类型"); 38 | cancel.setOnClickListener(this); 39 | ok.setOnClickListener(this); 40 | fristType = typeUtils.createFrist().get(f); 41 | sencondType = typeUtils.createSecond(f).get(s); 42 | 43 | wheel_p = (WheelView) dialog.findViewById(R.id.wheel_p); 44 | wheel_c = (WheelView) dialog.findViewById(R.id.wheel_c); 45 | wheel_p.setData(typeUtils.createFrist()); 46 | wheel_c.setData(typeUtils.createSecond()); 47 | wheel_p.setOnSelectListener(new WheelView.SelectListener() { 48 | @Override 49 | public void onSelect(int index, String text) { 50 | fristType = text; 51 | f = index; 52 | wheel_c.setWheelItemList(typeUtils.createSecond(index)); 53 | sencondType = typeUtils.createSecond(f).get(s); 54 | } 55 | }); 56 | wheel_c.setOnSelectListener(new WheelView.SelectListener() { 57 | @Override 58 | public void onSelect(int index, String text) { 59 | sencondType = text; 60 | s = index; 61 | } 62 | }); 63 | setDialogLocation(mContext, dialog); 64 | 65 | } 66 | 67 | public void setCallback(OnClickCallback callback) { 68 | this.callback = callback; 69 | } 70 | 71 | @Override 72 | public void onClick(View v) { 73 | super.onClick(v); 74 | switch (v.getId()) { 75 | case R.id.cancel: 76 | if (callback != null) { 77 | callback.onCancel(); 78 | } 79 | break; 80 | case R.id.ok: 81 | if (callback != null) { 82 | callback.onSure(f, s, fristType, sencondType); 83 | } 84 | break; 85 | } 86 | } 87 | 88 | public interface OnClickCallback { 89 | void onCancel(); 90 | 91 | /** 92 | *前面连个int 值是用于给服务器传值 后面两个String 用于界面显示 93 | * @param f 94 | * @param s 95 | * @param fristType 96 | * @param sencondType 97 | */ 98 | void onSure(int f, int s, String fristType, String sencondType); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/feealan/wheelview/widget/WheelView.java: -------------------------------------------------------------------------------- 1 | package com.feealan.wheelview.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.ColorFilter; 6 | import android.graphics.Paint; 7 | import android.graphics.Rect; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Handler; 10 | import android.os.Message; 11 | import android.support.v4.content.ContextCompat; 12 | import android.util.AttributeSet; 13 | import android.util.Log; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | 17 | import com.feealan.wheelview.R; 18 | import com.feealan.wheelview.utils.SizeConvertUtil; 19 | 20 | import java.util.List; 21 | import java.util.Timer; 22 | import java.util.TimerTask; 23 | 24 | /** 25 | * 自定义WheelView 26 | */ 27 | public class WheelView extends View { 28 | public static final String TAG = "WheelView"; 29 | private Context mContext; 30 | /*要显示的内容*/ 31 | private List itemLsit; 32 | /*选中的画笔*/ 33 | private Paint selectPaint; 34 | /*未选中的画笔*/ 35 | private Paint unSelectPaint; 36 | /*画背景图中单独的画笔*/ 37 | private Paint centerLinePaint; 38 | /*item的高度*/ 39 | private int itemHeight = 50; 40 | /*除选中item外,上下各需要显示的备选项数目*/ 41 | public static final int SHOW_SIZE = 1; 42 | private float centerY; 43 | private float centerX; 44 | /* 滑动的距离*/ 45 | private float mMoveLen = 0; 46 | private boolean isInit = false; 47 | /* 选中的位置,这个位置是mDataList的中心位置,一直不变*/ 48 | private int currentItem; 49 | private int itemCount; 50 | /* 自动回滚到中间的速度*/ 51 | public static final float SPEED = 2; 52 | private SelectListener mSelectListener; 53 | private Timer timer; 54 | private MyTimerTask mTask; 55 | private float mLastDownY; 56 | Handler updateHandler = new Handler() { 57 | 58 | @Override 59 | public void handleMessage(Message msg) { 60 | if (Math.abs(mMoveLen) < SPEED) { 61 | // 如果偏移量少于最少偏移量 62 | mMoveLen = 0; 63 | if (null != timer) { 64 | timer.cancel(); 65 | timer.purge(); 66 | timer = null; 67 | } 68 | if (mTask != null) { 69 | mTask.cancel(); 70 | mTask = null; 71 | performSelect(); 72 | } 73 | } else { 74 | // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚 75 | mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED; 76 | } 77 | invalidate(); 78 | } 79 | 80 | }; 81 | private void resetCurrentSelect() { 82 | if (currentItem < 0) { 83 | currentItem = 0; 84 | } 85 | while (currentItem >= itemCount) { 86 | currentItem--; 87 | } 88 | if (currentItem >= 0 && currentItem < itemCount) { 89 | invalidate(); 90 | } else { 91 | Log.i(TAG, "current item is invalid"); 92 | } 93 | } 94 | public int getItemCount() { 95 | return itemCount; 96 | } 97 | public int getCurrentItem() { 98 | 99 | return currentItem; 100 | } 101 | 102 | public void setCurrentItem(int selected) { 103 | currentItem = selected; 104 | resetCurrentSelect(); 105 | } 106 | 107 | public void setOnSelectListener(SelectListener listener) { 108 | mSelectListener = listener; 109 | } 110 | public WheelView(Context context) { 111 | this(context, null); 112 | } 113 | 114 | public WheelView(Context context, AttributeSet attrs) { 115 | this(context, attrs, 0); 116 | } 117 | 118 | public WheelView(Context context, AttributeSet attrs, int defStyleAttr) { 119 | super(context, attrs, defStyleAttr); 120 | this.mContext = context; 121 | init(mContext); 122 | } 123 | 124 | /** 125 | * 初始化数据 126 | * @param list 127 | */ 128 | public void setData(List list) { 129 | itemLsit=list; 130 | if (itemLsit != null) { 131 | itemCount = itemLsit.size(); 132 | resetCurrentSelect(); 133 | invalidate(); 134 | } else { 135 | Log.i(TAG, "item is null"); 136 | } 137 | 138 | } 139 | 140 | /** 141 | * 做二级联动是设置二级wheelview的数据 142 | * @param list 143 | */ 144 | public void setWheelItemList(List list) { 145 | this.itemLsit = list; 146 | if (itemLsit != null) { 147 | itemCount = itemLsit.size(); 148 | resetCurrentSelect(); 149 | } else { 150 | Log.i(TAG, "item is null"); 151 | } 152 | } 153 | /** 154 | * 初始化 155 | * @param context 156 | */ 157 | private void init(Context context) { 158 | //初始化选中画笔 设置位图抗锯齿 159 | selectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 160 | //画笔 填充 161 | selectPaint.setStyle(Paint.Style.FILL); 162 | //文字显示位置 居中 163 | selectPaint.setTextAlign(Paint.Align.CENTER); 164 | //设置画笔颜色 165 | selectPaint.setColor(ContextCompat.getColor(mContext, android.R.color.white)); 166 | //设置文字大小 167 | selectPaint.setTextSize(SizeConvertUtil.spTopx(mContext, 18)); 168 | 169 | //初始化未选中画笔 设置位图抗锯齿 170 | unSelectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 171 | //画笔 填充 172 | unSelectPaint.setStyle(Paint.Style.FILL); 173 | //文字显示位置 居中 174 | unSelectPaint.setTextAlign(Paint.Align.CENTER); 175 | //设置画笔颜色 176 | unSelectPaint.setColor(ContextCompat.getColor(mContext, R.color.wheel_unselect_text)); 177 | //设置文字大小 178 | unSelectPaint.setTextSize(SizeConvertUtil.spTopx(mContext, 16)); 179 | 180 | //初始化选中行 设置位图抗锯齿 181 | centerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 182 | //画笔 填充 183 | centerLinePaint.setStyle(Paint.Style.FILL); 184 | //文字显示位置 居中 185 | centerLinePaint.setTextAlign(Paint.Align.CENTER); 186 | //设置画笔颜色 187 | centerLinePaint.setColor(ContextCompat.getColor(mContext, R.color.wheel_select_text_bg)); 188 | 189 | setBackground(null); 190 | } 191 | 192 | 193 | 194 | @Override 195 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 196 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 197 | //view的宽高 198 | int mViewHeight = getMeasuredHeight(); 199 | int mViewWidth = getMeasuredWidth(); 200 | 201 | centerY = (float) (mViewHeight / 2.0); 202 | centerX = (float) (mViewWidth / 2.0); 203 | 204 | isInit = true; 205 | //对View重绘 206 | invalidate(); 207 | } 208 | @Override 209 | protected void onDraw(Canvas canvas) { 210 | super.onDraw(canvas); 211 | if (isInit) { 212 | drawData(canvas); 213 | } 214 | } 215 | 216 | private void drawData(Canvas canvas) { 217 | if (!itemLsit.isEmpty()) { 218 | // 绘制中间data 219 | drawCenterText(canvas); 220 | // 绘制上方data 221 | for (int i = 1; i < SHOW_SIZE + 1; i++) { 222 | drawOtherText(canvas, i, -1); 223 | } 224 | // 绘制下方data 225 | for (int i = 1; i < SHOW_SIZE + 1; i++) { 226 | drawOtherText(canvas, i, 1); 227 | } 228 | } 229 | } 230 | /** 231 | * @param canvas 画布 232 | * @param position 距离mCurrentSelected的差值 233 | * @param type 1表示向下绘制,-1表示向上绘制 234 | */ 235 | private void drawOtherText(Canvas canvas, int position, int type) { 236 | int index = currentItem + type * position; 237 | if (index >= itemCount) { 238 | index = index - itemCount; 239 | } 240 | if (index < 0) { 241 | index = index + itemCount; 242 | } 243 | String text = itemLsit.get(index); 244 | 245 | int itemHeight = getHeight() / (SHOW_SIZE * 2 + 1); 246 | float d = itemHeight * position + type * mMoveLen; 247 | float y = centerY + type * d; 248 | 249 | Paint.FontMetricsInt fmi = unSelectPaint.getFontMetricsInt(); 250 | float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); 251 | canvas.drawText(text, centerX, baseline, unSelectPaint); 252 | } 253 | 254 | /** 255 | * 256 | * 绘制选中的文字 257 | * @param canvas 258 | */ 259 | private void drawCenterText(Canvas canvas) { 260 | // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标 261 | float y = centerY + mMoveLen; 262 | Paint.FontMetricsInt fmi = selectPaint.getFontMetricsInt(); 263 | float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); 264 | canvas.drawText(itemLsit.get(currentItem), centerX, baseline, selectPaint); 265 | } 266 | 267 | 268 | @Override 269 | public void setBackground(Drawable background) { 270 | background = new Drawable() { 271 | @Override 272 | public void draw(Canvas canvas) { 273 | //计算出每个Item的高度 274 | itemHeight = getHeight()/(SHOW_SIZE*2+1); 275 | //显示的宽度 276 | int width = getWidth(); 277 | 278 | Rect centerRect = new Rect(0,itemHeight,width,itemHeight*2); 279 | canvas.drawRect(centerRect,centerLinePaint); 280 | } 281 | 282 | @Override 283 | public void setAlpha(int alpha) { 284 | 285 | } 286 | 287 | @Override 288 | public void setColorFilter(ColorFilter colorFilter) { 289 | 290 | } 291 | 292 | @Override 293 | public int getOpacity() { 294 | return 0; 295 | } 296 | }; 297 | super.setBackground(background); 298 | } 299 | 300 | @Override 301 | public boolean onTouchEvent(MotionEvent event) { 302 | switch (event.getActionMasked()) { 303 | case MotionEvent.ACTION_DOWN: 304 | doDown(event); 305 | break; 306 | case MotionEvent.ACTION_MOVE: 307 | doMove(event); 308 | break; 309 | case MotionEvent.ACTION_UP: 310 | doUp(); 311 | break; 312 | default: 313 | break; 314 | } 315 | return true; 316 | } 317 | private void doDown(MotionEvent event) { 318 | if (mTask != null) { 319 | mTask.cancel(); 320 | mTask = null; 321 | } 322 | mLastDownY = event.getY(); 323 | } 324 | private void doMove(MotionEvent event) { 325 | 326 | mMoveLen += (event.getY() - mLastDownY); 327 | 328 | if (mMoveLen > itemHeight / 2) { 329 | // 往下滑超过离开距离 330 | mMoveLen = mMoveLen - itemHeight; 331 | currentItem--; 332 | if (currentItem < 0) { 333 | currentItem = itemCount - 1; 334 | } 335 | } else if (mMoveLen < -itemHeight / 2) { 336 | // 往上滑超过离开距离 337 | mMoveLen = mMoveLen + itemHeight; 338 | currentItem++; 339 | if (currentItem >= itemCount) { 340 | currentItem = 0; 341 | } 342 | } 343 | 344 | mLastDownY = event.getY(); 345 | invalidate(); 346 | } 347 | private void doUp() { 348 | // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置 349 | if (Math.abs(mMoveLen) < 0.0001) { 350 | mMoveLen = 0; 351 | return; 352 | } 353 | if (mTask != null) { 354 | mTask.cancel(); 355 | mTask = null; 356 | } 357 | if (null == timer) { 358 | timer = new Timer(); 359 | } 360 | mTask = new MyTimerTask(updateHandler); 361 | timer.schedule(mTask, 0, 10); 362 | } 363 | class MyTimerTask extends TimerTask { 364 | Handler handler; 365 | 366 | public MyTimerTask(Handler handler) { 367 | this.handler = handler; 368 | } 369 | 370 | @Override 371 | public void run() { 372 | handler.sendMessage(handler.obtainMessage()); 373 | } 374 | 375 | } 376 | 377 | private void performSelect() { 378 | if (mSelectListener != null) { 379 | mSelectListener.onSelect(currentItem, itemLsit.get(currentItem)); 380 | } else { 381 | Log.i(TAG, "null listener"); 382 | } 383 | } 384 | 385 | public interface SelectListener { 386 | void onSelect(int index, String text); 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /app/src/main/res/anim/photo_dialog_in_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/photo_dialog_out_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 |