├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── JiangPing.xml
├── vcs.xml
├── encodings.xml
├── modules.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── strings.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── activity_sample.xml
│ │ │ │ ├── fragment_number.xml
│ │ │ │ ├── fragment_time.xml
│ │ │ │ ├── fragment_city.xml
│ │ │ │ ├── layout_city_picker.xml
│ │ │ │ └── layout_time_picker.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── me
│ │ │ └── jp
│ │ │ └── wheelview
│ │ │ ├── ui
│ │ │ ├── fragment
│ │ │ │ ├── CityFragment.java
│ │ │ │ ├── TimeFragment.java
│ │ │ │ └── OtherFragment.java
│ │ │ └── SampleActivity.java
│ │ │ ├── util
│ │ │ └── AreaDataUtil.java
│ │ │ └── widget
│ │ │ ├── TimePickerLayout.java
│ │ │ └── CityPickerLayout.java
│ └── androidTest
│ │ └── java
│ │ └── me
│ │ └── jp
│ │ └── wheelview
│ │ └── ApplicationTest.java
├── build.gradle
├── proguard-rules.pro
└── app.iml
├── settings.gradle
├── Library
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ ├── strings.xml
│ │ │ │ └── attrs.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── jp
│ │ │ └── wheelview
│ │ │ └── WheelView.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── jp
│ │ └── wheelview
│ │ └── ApplicationTest.java
├── project.properties
├── build.gradle
├── proguard-rules.pro
├── bintrayUpload.gradle
└── Library.iml
├── art
└── wheelView_shot_01.gif
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitattributes
├── .gitignore
├── gradle.properties
├── WheelView.iml
├── gradlew.bat
├── README.md
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | WheelView
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':Library'
2 |
--------------------------------------------------------------------------------
/Library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
3 | local.properties
--------------------------------------------------------------------------------
/art/wheelView_shot_01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloJp/WheelView/HEAD/art/wheelView_shot_01.gif
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WheelView
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloJp/WheelView/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.idea/dictionaries/JiangPing.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloJp/WheelView/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloJp/WheelView/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloJp/WheelView/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloJp/WheelView/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/Library/project.properties:
--------------------------------------------------------------------------------
1 | #project
2 | project.name=WheelView
3 | project.groupId=com.jp
4 | project.artifactId=wheelview
5 | project.packaging=aar
6 | project.siteUrl=https://github.com/helloJp/WheelView
7 | project.gitUrl=https://github.com/helloJp/WheelView.git
8 |
9 | #javadoc
10 | javadoc.name=WheelView
--------------------------------------------------------------------------------
/Library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/me/jp/wheelview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package me.jp.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 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/Library/src/androidTest/java/com/jp/wheelview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.jp.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 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 22
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | apply from: "bintrayUpload.gradle"
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "me.jp.wheelview"
9 | minSdkVersion 14
10 | targetSdkVersion 22
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 | compile 'com.android.support:appcompat-v7:22.2.0'
25 | compile project(':Library')
26 | }
27 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/Library/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:\Program Files\as_sdk\android-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/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:\Program Files\as_sdk\android-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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
10 | *.iml
11 |
12 | # Built application files
13 | *.apk
14 | *.ap_
15 |
16 | # Files for the Dalvik VM
17 | *.dex
18 |
19 | # Java class files
20 | *.class
21 |
22 | # Generated files
23 | bin/
24 | gen/
25 |
26 | # Gradle files
27 | .gradle/
28 | build/
29 |
30 | # Local configuration file (sdk path, etc)
31 | local.properties
32 |
33 | # Proguard folder generated by Eclipse
34 | proguard/
35 |
36 | # Log Files
37 | *.log
38 |
39 | .idea/compiler.xml
40 |
41 |
42 | .idea/dictionaries/JiangPing.xml
43 |
44 | .idea/dictionaries/JiangPing.xml
45 |
46 | app/app.iml
47 |
48 | .idea/misc.xml
49 |
50 | WheelView.iml
51 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/WheelView.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_sample.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
23 |
24 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_number.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_time.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
24 |
25 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_city.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
26 |
27 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_city_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
28 |
29 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/ui/fragment/CityFragment.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.ui.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Button;
10 | import android.widget.TextView;
11 |
12 | import me.jp.wheelview.R;
13 | import me.jp.wheelview.widget.CityPickerLayout;
14 |
15 | /**
16 | * Created by jiangp on 16/4/20.
17 | */
18 | public class CityFragment extends Fragment implements View.OnClickListener{
19 |
20 | private View mRootView;
21 | private CityPickerLayout mCityPickerLayout;
22 | private TextView mSelectedTv;
23 | private Button mShowSelectedBtn;
24 |
25 | @Nullable
26 | @Override
27 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
28 | mRootView = inflater.inflate(R.layout.fragment_city, null);
29 | return mRootView;
30 | }
31 |
32 | @Override
33 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
34 | super.onViewCreated(view, savedInstanceState);
35 | initView();
36 | }
37 |
38 |
39 | private void initView() {
40 | mCityPickerLayout = (CityPickerLayout) mRootView.findViewById(R.id.city_picker);
41 | mSelectedTv = (TextView) mRootView.findViewById(R.id.select_tv);
42 | mShowSelectedBtn = (Button) mRootView.findViewById(R.id.show_select_btn);
43 | mShowSelectedBtn.setOnClickListener(this);
44 | }
45 |
46 |
47 | @Override
48 | public void onClick(View view) {
49 | switch (view.getId()) {
50 | case R.id.show_select_btn:
51 | mSelectedTv.setText(new StringBuffer().append(mCityPickerLayout.getProvince())
52 | .append(" ").append(mCityPickerLayout.getCity()));
53 | break;
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/ui/fragment/TimeFragment.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.ui.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Button;
10 | import android.widget.TextView;
11 |
12 | import me.jp.wheelview.R;
13 | import me.jp.wheelview.widget.CityPickerLayout;
14 | import me.jp.wheelview.widget.TimePickerLayout;
15 |
16 | /**
17 | * Created by jiangp on 16/4/20.
18 | */
19 | public class TimeFragment extends Fragment implements View.OnClickListener {
20 |
21 | private View mRootView;
22 | private TimePickerLayout mTimePickerLayout;
23 | private TextView mSelectedTv;
24 | private Button mShowSelectedBtn;
25 |
26 | @Nullable
27 | @Override
28 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
29 | mRootView = inflater.inflate(R.layout.fragment_time, null);
30 | return mRootView;
31 | }
32 |
33 | @Override
34 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
35 | super.onViewCreated(view, savedInstanceState);
36 | mTimePickerLayout = (TimePickerLayout) mRootView.findViewById(R.id.time_picker);
37 | mSelectedTv = (TextView) mRootView.findViewById(R.id.select_tv);
38 | mShowSelectedBtn = (Button) mRootView.findViewById(R.id.show_select_btn);
39 | mShowSelectedBtn.setOnClickListener(this);
40 | }
41 |
42 |
43 | @Override
44 | public void onClick(View view) {
45 | switch (view.getId()) {
46 | case R.id.show_select_btn:
47 |
48 | mSelectedTv.setText(new StringBuffer().append(mTimePickerLayout.getYear()).append("年 ")
49 | .append(mTimePickerLayout.getMonth()).append("月 ")
50 | .append(mTimePickerLayout.getDay()).append("日"));
51 | break;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WheelView
3 |
4 |
5 | - 城市选择器
6 | - 日期选择器
7 | - 其他
8 |
9 |
10 |
11 | "北京!!东城区!西城区!崇文区!宣武区!朝阳区!丰台区!石景山区!海淀区!门头沟区!房山区!通州区!顺义区!昌平区!大兴区!怀柔区!平谷区!密云县!延庆县!!!天津!!和平区!河东区!河西区!南开区!河北区!红桥区!塘沽区!汉沽区!大港区!东丽区!西青区!津南区!北辰区!武清区!宝坻区!宁河县!静海县!蓟县!!!河北!!石家庄!唐山!秦皇岛!邯郸!邢台!保定!张家口!承德!沧州!廊坊!衡水!!!山西!!太原!大同!阳泉!长治!晋城!朔州!晋中!运城!忻州!临汾!吕梁!!!内蒙古!!呼和浩特!包头!乌海!赤峰!通辽!鄂尔多斯!呼伦贝尔!兴安盟!锡林郭勒盟!乌兰察布盟!巴彦淖尔盟!阿拉善盟!!!辽宁!!沈阳!大连!鞍山!抚顺!本溪!丹东!锦州!营口!阜新!辽阳!盘锦!铁岭!朝阳!葫芦岛!!!吉林!!长春!吉林!四平!辽源!通化!白山!松原!白城!延边朝鲜族自治州!!!黑龙江!!哈尔滨!齐齐哈尔!鸡西!鹤岗!双鸭山!大庆!伊春!佳木斯!七台河!牡丹江!黑河!绥化!大兴安岭!!!上海!!黄浦区!卢湾区!徐汇区!长宁区!静安区!普陀区!闸北区!虹口区!杨浦区!闵行区!宝山区!嘉定区!浦东新区!金山区!松江区!青浦区!南汇区!奉贤区!崇明县!!!江苏!!南京!无锡!徐州!常州!苏州!南通!连云港!淮安!盐城!扬州!镇江!泰州!宿迁!!!浙江!!杭州!宁波!温州!嘉兴!湖州!绍兴!金华!衢州!舟山!台州!丽水!!!安徽!!合肥!芜湖!蚌埠!淮南!马鞍山!淮北!铜陵!安庆!黄山!滁州!阜阳!宿州!巢湖!六安!亳州!池州!宣城!!!福建!!福州!厦门!莆田!三明!泉州!漳州!南平!龙岩!宁德!!!江西!!南昌!景德镇!萍乡!九江!新余!鹰潭!赣州!吉安!宜春!抚州!上饶!!!山东!!济南!青岛!淄博!枣庄!东营!烟台!潍坊!济宁!泰安!威海!日照!莱芜!临沂!德州!聊城!滨州!菏泽!!!河南!!郑州!开封!洛阳!平顶山!安阳!鹤壁!新乡!焦作!濮阳!许昌!漯河!三门峡!南阳!商丘!信阳!周口!驻马店!!!湖北!!武汉!黄石!十堰!宜昌!襄樊!鄂州!荆门!孝感!荆州!黄冈!咸宁!随州!恩施土家族苗族自治州!!!湖南!!长沙!株洲!湘潭!衡阳!邵阳!岳阳!常德!张家界!益阳!郴州!永州!怀化!娄底!湘西土家族苗族自治州!!!广东!!广州!韶关!深圳!珠海!汕头!佛山!江门!湛江!茂名!肇庆!惠州!梅州!汕尾!河源!阳江!清远!东莞!中山!潮州!揭阳!云浮!!!广西!!南宁!柳州!桂林!梧州!北海!防城港!钦州!贵港!玉林!百色!贺州!河池!南宁!柳州!!!海南!!海口!三亚!其他!!!重庆!!万州区!涪陵区!渝中区!大渡口区!江北区!沙坪坝区!九龙坡区!南岸区!北碚区!万盛区!双桥区!渝北区!巴南区!黔江区!长寿区!綦江县!潼南县!铜梁县!大足县!荣昌县!璧山县!梁平县!城口县!丰都县!垫江县!武隆县!忠县!开县!云阳县!奉节县!巫山县!巫溪县!石柱土家族自治县!秀山土家族苗族自治县!酉阳土家族苗族自治县!彭水苗族土家族自治县!江津市!合川市!永川区!南川市!!!四川!!成都!自贡!攀枝花!泸州!德阳!绵阳!广元!遂宁!内江!乐山!南充!眉山!宜宾!广安!达州!雅安!巴中!资阳!阿坝!甘孜!凉山!!!贵州!!贵阳!六盘水!遵义!安顺!铜仁!黔西南!毕节!黔东南!黔南!!!云南!!昆明!曲靖!玉溪!保山!昭通!楚雄!红河!文山!思茅!西双版纳!大理!德宏!丽江!怒江!迪庆!临沧!!!西藏!!拉萨!昌都!山南!日喀则!那曲!阿里!林芝!!!陕西!!西安!铜川!宝鸡!咸阳!渭南!延安!汉中!榆林!安康!商洛!!!甘肃!!兰州!嘉峪关!金昌!白银!天水!武威!张掖!平凉!酒泉!庆阳!定西!陇南!临夏!甘南!!!青海!!西宁!海东!海北!黄南!海南!果洛!玉树!海西!!!宁夏!!银川!石嘴山!吴忠!固原!!!新疆!!乌鲁木齐!克拉玛依!吐鲁番!哈密!昌吉!博尔塔拉!巴音郭楞!阿克苏!克孜勒苏!喀什!和田!伊犁!塔城!阿勒泰!!!台湾!!台北!高雄!其他!!!香港!!香港!!!澳门!!澳门!!!海外!!美国!英国!法国!俄罗斯!加拿大!巴西!澳大利亚!印尼!泰国!马来西亚!新加坡!菲律宾!越南!印度!日本!其他"
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/ui/fragment/OtherFragment.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.ui.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.jp.wheelview.WheelView;
11 |
12 | import java.util.ArrayList;
13 |
14 | import me.jp.wheelview.R;
15 |
16 | /**
17 | * Created by jiangp on 16/4/20.
18 | */
19 | public class OtherFragment extends Fragment {
20 |
21 | private View mRootView;
22 | WheelView mWheelView;
23 |
24 | @Nullable
25 | @Override
26 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
27 | mRootView = inflater.inflate(R.layout.fragment_number, null);
28 | return mRootView;
29 | }
30 |
31 | @Override
32 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
33 | super.onViewCreated(view, savedInstanceState);
34 | initView();
35 | }
36 |
37 | private void initView() {
38 | mWheelView = (WheelView) mRootView.findViewById(R.id.wheelView);
39 | mWheelView.setData(getData1());
40 | }
41 |
42 | private boolean mIsData1 = true;
43 |
44 | /**
45 | * 重置数据
46 | *
47 | * @param view
48 | */
49 | public void resetData(View view) {
50 | if (mIsData1) {
51 | mWheelView.refreshData(getData2());
52 | mWheelView.setDefault(1);
53 | } else {
54 | mWheelView.refreshData(getData1());
55 | }
56 | mIsData1 = !mIsData1;
57 | }
58 |
59 | private ArrayList getData1() {
60 | ArrayList data = new ArrayList<>();
61 | for (int i = 0; i < 26; i++) {
62 | data.add(String.valueOf(((char) (97 + i))));
63 | }
64 | return data;
65 | }
66 |
67 | private ArrayList getData2() {
68 | ArrayList data = new ArrayList<>();
69 | data.add("A");
70 | data.add("B");
71 | data.add("C");
72 | return data;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/util/AreaDataUtil.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.util;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.HashMap;
8 | import java.util.List;
9 |
10 | import me.jp.wheelview.R;
11 |
12 | /**
13 | * 全国省份城市操作类
14 | *
15 | * @author JiangPing
16 | */
17 | public class AreaDataUtil {
18 |
19 | /**
20 | * 所有的省市String
21 | */
22 | public String AREAS_DATA;
23 | /**
24 | * 一个省份对应多个城市
25 | */
26 | private String[] single_province_city;
27 | /**
28 | * 全国省市Map key:省份 |Value:城市集合
29 | */
30 | private HashMap> mCityMap = new HashMap<>();
31 |
32 | public AreaDataUtil(Context context) {
33 | AREAS_DATA = context.getResources().getString(R.string.province_and_city);
34 | splitProvince();
35 | getAllCityMap();
36 | }
37 |
38 | /**
39 | * 将省份和对应城市分割出来
40 | *
41 | * 得到:宁夏!!银川!石嘴山!吴忠!固原
42 | */
43 | private void splitProvince() {
44 | single_province_city = AREAS_DATA.split("!!!");
45 | }
46 |
47 | /**
48 | * 获得全国省份的列表
49 | *
50 | * @return
51 | */
52 | public ArrayList getProvinces() {
53 | ArrayList provinceList = new ArrayList<>();
54 | for (String str : single_province_city) {
55 | String province = str.split("!!")[0];
56 | provinceList.add(province);
57 | }
58 | return provinceList;
59 | }
60 |
61 | /**
62 | * 根据省份获取城市列表
63 | *
64 | * @return
65 | */
66 | private void getAllCityMap() {
67 | for (String str : single_province_city) {
68 | // 得到省份
69 | String province = str.split("!!")[0];
70 | // 得到当前省份对应的城市
71 | String city = str.split("!!")[1];
72 | // 分离城市放入集合
73 | List cityList = Arrays.asList(city.split("!"));
74 | // 省份和城市放入Map中
75 | mCityMap.put(province, cityList);
76 | }
77 | }
78 |
79 | /**
80 | * 根据省份查找对应的城市列表
81 | *
82 | * @return 城市集合
83 | */
84 | public ArrayList getCityByProvince(String provinceStr) {
85 |
86 | List list = mCityMap.get(provinceStr);
87 | ArrayList arrList = new ArrayList<>();
88 | for (String city : list) {
89 | arrList.add(city);
90 | }
91 | return arrList;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Android
15 |
16 |
17 | Android Lint
18 |
19 |
20 | Java
21 |
22 |
23 | Java language level migration aidsJava
24 |
25 |
26 |
27 |
28 | Android
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 1.7
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/widget/TimePickerLayout.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.widget.LinearLayout;
7 |
8 | import com.jp.wheelview.WheelView;
9 |
10 | import java.util.ArrayList;
11 |
12 | import me.jp.wheelview.R;
13 |
14 | /**
15 | * Created by JiangPing on 2015/6/17.
16 | */
17 | public class TimePickerLayout extends LinearLayout {
18 | private WheelView mWheelYear;
19 | private WheelView mWheelMonth;
20 | private WheelView mWheelDay;
21 |
22 | public TimePickerLayout(Context context) {
23 | this(context, null);
24 | }
25 |
26 | public TimePickerLayout(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 | }
29 |
30 |
31 | @Override
32 | protected void onFinishInflate() {
33 | super.onFinishInflate();
34 | LayoutInflater.from(getContext()).inflate(R.layout.layout_time_picker, this);
35 | mWheelYear = (WheelView) findViewById(R.id.year);
36 | mWheelMonth = (WheelView) findViewById(R.id.month);
37 | mWheelDay = (WheelView) findViewById(R.id.day);
38 |
39 | mWheelYear.setData(getYearData());
40 | mWheelMonth.setData(getMonthData());
41 | mWheelDay.setData(getDayData());
42 |
43 | }
44 |
45 |
46 | private ArrayList getYearData() {
47 | ArrayList list = new ArrayList<>();
48 | for (int i = 2015; i > 1990; i--) {
49 | list.add(String.valueOf(i));
50 | }
51 | return list;
52 | }
53 |
54 | private ArrayList getMonthData() {
55 | ArrayList list = new ArrayList<>();
56 | for (int i = 1; i <= 12; i++) {
57 | list.add(String.valueOf(i));
58 | }
59 | return list;
60 | }
61 |
62 | private ArrayList getDayData() {
63 | //ignore condition
64 | ArrayList list = new ArrayList<>();
65 | for (int i = 1; i < 31; i++) {
66 | list.add(String.valueOf(i));
67 | }
68 | return list;
69 | }
70 |
71 | public String getYear() {
72 | if (mWheelDay == null) {
73 | return null;
74 | }
75 | return mWheelYear.getSelectedText();
76 | }
77 |
78 | public String getMonth() {
79 | if (mWheelMonth == null) {
80 | return null;
81 | }
82 | return mWheelMonth.getSelectedText();
83 | }
84 |
85 | public String getDay() {
86 | if (mWheelDay == null) {
87 | return null;
88 | }
89 | return mWheelDay.getSelectedText();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_time_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
26 |
27 |
33 |
34 |
50 |
51 |
57 |
58 |
74 |
75 |
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #WheelView 滚轮控件
2 | **WheelView仿IOS的滑动选择器**
3 |
4 | * 继承自View,绘制所有的显示。
5 | * 监听手势来移动(根据新坐标重新绘制)itemObject。
6 | * 单个控件(一个类实现了滚轮效果),拓展性较强。
7 |
8 | > 这里说明一下的是WheelView只能实现一个滚轮,联动效果 可通过多个WheelView的组合使用(issues里面有人反馈这个问题😂)
9 |
10 | ###效果图:
11 | * CityPicker
12 |
13 | 
14 |
15 | * TimePicker
16 |
17 | 
18 |
19 |
20 | ###坐标图
21 |
22 | 下图为控件中心位置的itemObject居中时的简易坐标图。
23 |
24 | 
25 |
26 |
27 | ### 在布局中放入WheelView控件
28 |
29 | ```
30 |
43 | ```
44 |
45 | # Attributes
46 |
47 | There are several attributes you can set:
48 |
49 | | attr 属性 | description 描述 |
50 | |:--- |:---|
51 | | lineColor | divider line color 分割线颜色 |
52 | | lineHeight | divider line height 分割线高度 |
53 | | itemNumber | wheelview show item count 此wheelView显示item的个数 |
54 | | maskHeight | mask height 蒙版高度(normalText的位置) |
55 | | noEmpty | if set true select area can't be null(empty),or could be empty 设置true则选中不能为空,否则可以是空 |
56 | | normalTextColor | unSelected Text color 未选中文本颜色 |
57 | | normalTextSize | unSelected Text size 未选中文本字体大小 |
58 | | selectedTextColor | selected Text color 选中文本颜色 |
59 | | selectedTextSize | selected Text size 选中文本字体大小 |
60 | | unitHeight | item unit height 每个item单元的高度 |
61 |
62 | #Method
63 | ###1. setData(ArrayList data)
64 | set WheelView data
65 | 设置WheelView的数据
66 |
67 | ###2. refreshData(ArrayList data)
68 | **refresh** WheelView data ,and draw again
69 | **刷新** WheelView的数据,并重绘
70 |
71 | ###3. int getSelected()
72 | get selected item index
73 | 获取选中项的index
74 |
75 | ###4. String getSelectedText()
76 | get selected item text
77 | 获取选中项的文本信息
78 |
79 | ###5. boolean isScrolling
80 | is WheelView is scrolling
81 | 获取WheelView是否在滚动中
82 |
83 | ###6. boolean isEnable()
84 | is WheelView is enable
85 | 获取wheelView是否可用
86 |
87 | ###7. void setEnable(boolean isEnable)
88 | set WheelView enable
89 | 设置WheelView是否可用
90 |
91 | ###8. void setDefault(int index)
92 | set **default selected index**
93 | 设置**默认选中项的index**
94 |
95 | ###9. int getListSize()
96 | get WheelView item count
97 | 获取WheelView的item项个数
98 |
99 | ###10. String getItemText(int index)
100 | get the text by index
101 | 获取index位置上的文本数据
102 |
103 | ###11. void setOnSelectListener(OnSelectListener onSelectListener)
104 | set listener on WheelView that can get info when WheelView is **scrolling** or **stop scroll**.
105 | 对WheelView**设置监听**,在 **滑动过程** 或者 **滑动停止** 返回数据信息。
106 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/ui/SampleActivity.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.ui;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentTransaction;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.view.View;
9 | import android.widget.AdapterView;
10 | import android.widget.Spinner;
11 |
12 | import me.jp.wheelview.R;
13 | import me.jp.wheelview.ui.fragment.CityFragment;
14 | import me.jp.wheelview.ui.fragment.OtherFragment;
15 | import me.jp.wheelview.ui.fragment.TimeFragment;
16 |
17 | /**
18 | * Created by jiangp on 16/4/20.
19 | */
20 | public class SampleActivity extends AppCompatActivity {
21 |
22 | private Fragment mCurrFragment;
23 |
24 | private Fragment mCityFragment;
25 | private Fragment mTimeFragment;
26 | private Fragment mNumberFragment;
27 |
28 | @Override
29 | protected void onCreate(@Nullable Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_sample);
32 |
33 | mCityFragment = new CityFragment();
34 | mTimeFragment = new TimeFragment();
35 | mNumberFragment = new OtherFragment();
36 |
37 | //这里直接设置Fragment进入,不知道为什么延时replace就会页面排版错乱
38 | replaceFragment(R.id.fragment, mNumberFragment);
39 | replaceFragment(R.id.fragment, mTimeFragment);
40 | replaceFragment(R.id.fragment, mCityFragment);
41 |
42 | initView();
43 | }
44 |
45 | private void initView() {
46 | Spinner spinner = (Spinner) findViewById(R.id.spinner);
47 | spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
48 | @Override
49 | public void onItemSelected(AdapterView> parent, View view, int pos, long id) {
50 | switch (pos) {
51 | case 0:
52 | replaceFragment(R.id.fragment, mCityFragment);
53 | break;
54 | case 1:
55 | replaceFragment(R.id.fragment, mTimeFragment);
56 | break;
57 | case 2:
58 | replaceFragment(R.id.fragment, mNumberFragment);
59 | break;
60 | }
61 | }
62 |
63 | @Override
64 | public void onNothingSelected(AdapterView> parent) {
65 | }
66 | });
67 | }
68 |
69 |
70 | private void replaceFragment(int resView, Fragment targetFragment) {
71 | if (targetFragment.equals(mCurrFragment)) {
72 | return;
73 | }
74 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
75 | if (!targetFragment.isAdded()) {
76 | transaction.add(resView, targetFragment, targetFragment.getClass().getName());
77 | }
78 | if (targetFragment.isHidden()) {
79 | transaction.show(targetFragment);
80 | }
81 | if (mCurrFragment != null && mCurrFragment.isVisible()) {
82 | transaction.hide(mCurrFragment);
83 | }
84 | mCurrFragment = targetFragment;
85 | transaction.commit();
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/Library/bintrayUpload.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.dcendents.android-maven'
2 | apply plugin: 'com.jfrog.bintray'
3 |
4 | // load properties
5 | Properties properties = new Properties()
6 | File localPropertiesFile = project.file("local.properties");
7 | if(localPropertiesFile.exists()){
8 | properties.load(localPropertiesFile.newDataInputStream())
9 | }
10 | File projectPropertiesFile = project.file("project.properties");
11 | if(projectPropertiesFile.exists()){
12 | properties.load(projectPropertiesFile.newDataInputStream())
13 | }
14 |
15 | // read properties
16 | def projectName = properties.getProperty("project.name")
17 | def projectGroupId = properties.getProperty("project.groupId")
18 | def projectArtifactId = properties.getProperty("project.artifactId")
19 | def projectVersionName = android.defaultConfig.versionName
20 | def projectPackaging = properties.getProperty("project.packaging")
21 | def projectSiteUrl = properties.getProperty("project.siteUrl")
22 | def projectGitUrl = properties.getProperty("project.gitUrl")
23 |
24 | def developerId = properties.getProperty("developer.id")
25 | def developerName = properties.getProperty("developer.name")
26 | def developerEmail = properties.getProperty("developer.email")
27 |
28 | def bintrayUser = properties.getProperty("bintray.user")
29 | def bintrayApikey = properties.getProperty("bintray.apikey")
30 |
31 | def javadocName = properties.getProperty("javadoc.name")
32 |
33 | group = projectGroupId
34 |
35 | // This generates POM.xml with proper parameters
36 | install {
37 | repositories.mavenInstaller {
38 | pom {
39 | project {
40 | name projectName
41 | groupId projectGroupId
42 | artifactId projectArtifactId
43 | version projectVersionName
44 | packaging projectPackaging
45 | url projectSiteUrl
46 | licenses {
47 | license {
48 | name 'The Apache Software License, Version 2.0'
49 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
50 | }
51 | }
52 | developers {
53 | developer {
54 | id developerId
55 | name developerName
56 | email developerEmail
57 | }
58 | }
59 | scm {
60 | connection projectGitUrl
61 | developerConnection projectGitUrl
62 | url projectSiteUrl
63 | }
64 | }
65 | }
66 | }
67 | }
68 |
69 | // This generates sources.jar
70 | task sourcesJar(type: Jar) {
71 | from android.sourceSets.main.java.srcDirs
72 | classifier = 'sources'
73 | }
74 |
75 | task javadoc(type: Javadoc) {
76 | source = android.sourceSets.main.java.srcDirs
77 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
78 | }
79 |
80 | // This generates javadoc.jar
81 | task javadocJar(type: Jar, dependsOn: javadoc) {
82 | classifier = 'javadoc'
83 | from javadoc.destinationDir
84 | }
85 |
86 | artifacts {
87 | archives javadocJar
88 | archives sourcesJar
89 | }
90 |
91 | // javadoc configuration
92 | javadoc {
93 | options{
94 | encoding "UTF-8"
95 | charSet 'UTF-8'
96 | author true
97 | version projectVersionName
98 | links "http://docs.oracle.com/javase/7/docs/api"
99 | title javadocName
100 | }
101 | }
102 |
103 | // bintray configuration
104 | bintray {
105 | user = bintrayUser
106 | key = bintrayApikey
107 | configurations = ['archives']
108 | pkg {
109 | repo = "maven"
110 | name = projectName
111 | websiteUrl = projectSiteUrl
112 | vcsUrl = projectGitUrl
113 | licenses = ["Apache-2.0"]
114 | publish = true
115 | }
116 | }
--------------------------------------------------------------------------------
/app/src/main/java/me/jp/wheelview/widget/CityPickerLayout.java:
--------------------------------------------------------------------------------
1 | package me.jp.wheelview.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.widget.LinearLayout;
7 |
8 | import com.jp.wheelview.WheelView;
9 |
10 | import java.util.ArrayList;
11 |
12 | import me.jp.wheelview.R;
13 | import me.jp.wheelview.util.AreaDataUtil;
14 |
15 | /**
16 | * CityPickerLayout
17 | * put two WheelView into LinearLayout
18 | *
19 | * @author JiangPing
20 | */
21 | public class CityPickerLayout extends LinearLayout {
22 |
23 | private WheelView mProvincePicker;
24 | private WheelView mCityPicker;
25 |
26 | private int mCurrProvinceIndex = -1;
27 | private int mCurrCityIndex = -1;
28 |
29 | private AreaDataUtil mAreaDataUtil;
30 | private ArrayList mProvinceList = new ArrayList<>();
31 |
32 | public CityPickerLayout(Context context, AttributeSet attrs) {
33 | super(context, attrs);
34 | getAreaInfo();
35 | }
36 |
37 | public CityPickerLayout(Context context) {
38 | this(context, null);
39 | }
40 |
41 | private void getAreaInfo() {
42 | mAreaDataUtil = new AreaDataUtil(getContext());
43 | mProvinceList = mAreaDataUtil.getProvinces();
44 | }
45 |
46 | @Override
47 | protected void onFinishInflate() {
48 | super.onFinishInflate();
49 | LayoutInflater.from(getContext()).inflate(R.layout.layout_city_picker, this);
50 |
51 | mProvincePicker = (WheelView) findViewById(R.id.province_wv);
52 | mCityPicker = (WheelView) findViewById(R.id.city_wv);
53 |
54 | mProvincePicker.setData(mProvinceList);
55 | mProvincePicker.setDefault(0);
56 |
57 | String defaultProvince = mProvinceList.get(0);
58 | mCityPicker.setData(mAreaDataUtil.getCityByProvince(defaultProvince));
59 | mCityPicker.setDefault(1);
60 |
61 | mProvincePicker.setOnSelectListener(new WheelView.OnSelectListener() {
62 | @Override
63 | public void endSelect(int id, String text) {
64 | if (text.equals("") || text == null)
65 | return;
66 | if (mCurrProvinceIndex != id) {
67 | mCurrProvinceIndex = id;
68 | String selectProvince = mProvincePicker.getSelectedText();
69 | if (selectProvince == null || selectProvince.equals(""))
70 | return;
71 |
72 | // get city names by province
73 | ArrayList city = mAreaDataUtil.getCityByProvince(mProvinceList.get(id));
74 | if (city.size() == 0) {
75 | return;
76 | }
77 |
78 | mCityPicker.setData(city);
79 |
80 | if (city.size() > 1) {
81 | //if city is more than one,show start index == 1
82 | mCityPicker.setDefault(1);
83 | } else {
84 | mCityPicker.setDefault(0);
85 | }
86 | }
87 |
88 | }
89 |
90 | @Override
91 | public void selecting(int id, String text) {
92 | }
93 | });
94 |
95 | mCityPicker.setOnSelectListener(new WheelView.OnSelectListener() {
96 |
97 | @Override
98 | public void endSelect(int id, String text) {
99 | if (text.equals("") || text == null)
100 | return;
101 | if (mCurrCityIndex != id) {
102 | mCurrCityIndex = id;
103 | String selectCity = mCityPicker.getSelectedText();
104 | if (selectCity == null || selectCity.equals(""))
105 | return;
106 | int lastIndex = Integer.valueOf(mCityPicker.getListSize());
107 | if (id > lastIndex) {
108 | mCityPicker.setDefault(lastIndex - 1);
109 | }
110 | }
111 | }
112 |
113 | @Override
114 | public void selecting(int id, String text) {
115 |
116 | }
117 | });
118 | }
119 |
120 | public String getProvince() {
121 | if (mProvincePicker == null) {
122 | return null;
123 | }
124 | return mProvincePicker.getSelectedText();
125 | }
126 |
127 | public String getCity() {
128 | if (mCityPicker == null) {
129 | return null;
130 | }
131 | return mCityPicker.getSelectedText();
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/Library/Library.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/Library/src/main/java/com/jp/wheelview/WheelView.java:
--------------------------------------------------------------------------------
1 | package com.jp.wheelview;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.LinearGradient;
8 | import android.graphics.Paint;
9 | import android.graphics.Rect;
10 | import android.graphics.Shader.TileMode;
11 | import android.os.Handler;
12 | import android.os.Message;
13 | import android.text.TextPaint;
14 | import android.text.TextUtils;
15 | import android.util.AttributeSet;
16 | import android.view.MotionEvent;
17 | import android.view.View;
18 |
19 | import java.util.ArrayList;
20 |
21 | /**
22 | * WheelView滚轮
23 | *
24 | * @author JiangPing
25 | */
26 | public class WheelView extends View {
27 | /**
28 | * 控件宽度
29 | */
30 | private float controlWidth;
31 | /**
32 | * 控件高度
33 | */
34 | private float controlHeight;
35 | /**
36 | * 是否滑动中
37 | */
38 | private boolean isScrolling = false;
39 | /**
40 | * 选择的内容
41 | */
42 | private ArrayList itemList = new ArrayList<>();
43 | /**
44 | * 设置数据
45 | */
46 | private ArrayList dataList = new ArrayList<>();
47 | /**
48 | * 按下的坐标
49 | */
50 | private int downY;
51 | /**
52 | * 按下的时间
53 | */
54 | private long downTime = 0;
55 | /**
56 | * 短促移动
57 | */
58 | private long goonTime = 200;
59 | /**
60 | * 短促移动距离
61 | */
62 | private int goonDistance = 100;
63 | /**
64 | * 画线画笔
65 | */
66 | private Paint linePaint;
67 | /**
68 | * 线的默认颜色
69 | */
70 | private int lineColor = 0xff000000;
71 | /**
72 | * 线的默认宽度
73 | */
74 | private float lineHeight = 2f;
75 | /**
76 | * 默认字体
77 | */
78 | private float normalFont = 14.0f;
79 | /**
80 | * 选中的时候字体
81 | */
82 | private float selectedFont = 22.0f;
83 | /**
84 | * 单元格高度
85 | */
86 | private int unitHeight = 50;
87 | /**
88 | * 显示多少个内容
89 | */
90 | private int itemNumber = 7;
91 | /**
92 | * 默认字体颜色
93 | */
94 | private int normalColor = 0xff000000;
95 | /**
96 | * 选中时候的字体颜色
97 | */
98 | private int selectedColor = 0xffff0000;
99 | /**
100 | * 蒙板高度
101 | */
102 | private float maskHeight = 48.0f;
103 | /**
104 | * 选择监听
105 | */
106 | private OnSelectListener onSelectListener;
107 | /**
108 | * 是否可用
109 | */
110 | private boolean isEnable = true;
111 | /**
112 | * 刷新界面
113 | */
114 | private static final int REFRESH_VIEW = 0x001;
115 | /**
116 | * 移动距离
117 | */
118 | private static final int MOVE_NUMBER = 5;
119 | /**
120 | * 是否允许选空
121 | */
122 | private boolean noEmpty = true;
123 |
124 | /**
125 | * 正在修改数据,避免ConcurrentModificationException异常
126 | */
127 | private boolean isClearing = false;
128 |
129 | public WheelView(Context context, AttributeSet attrs, int defStyle) {
130 | super(context, attrs, defStyle);
131 | init(context, attrs);
132 | initData();
133 | }
134 |
135 | public WheelView(Context context, AttributeSet attrs) {
136 | super(context, attrs);
137 | init(context, attrs);
138 | initData();
139 | }
140 |
141 | public WheelView(Context context) {
142 | super(context);
143 | initData();
144 | }
145 |
146 | /**
147 | * 初始化,获取设置的属性
148 | *
149 | * @param context
150 | * @param attrs
151 | */
152 | private void init(Context context, AttributeSet attrs) {
153 |
154 | TypedArray attribute = context.obtainStyledAttributes(attrs, R.styleable.WheelView);
155 | unitHeight = (int) attribute.getDimension(R.styleable.WheelView_unitHeight, unitHeight);
156 | itemNumber = attribute.getInt(R.styleable.WheelView_itemNumber, itemNumber);
157 |
158 | normalFont = attribute.getDimension(R.styleable.WheelView_normalTextSize, normalFont);
159 | selectedFont = attribute.getDimension(R.styleable.WheelView_selectedTextSize, selectedFont);
160 | normalColor = attribute.getColor(R.styleable.WheelView_normalTextColor, normalColor);
161 | selectedColor = attribute.getColor(R.styleable.WheelView_selectedTextColor, selectedColor);
162 |
163 | lineColor = attribute.getColor(R.styleable.WheelView_lineColor, lineColor);
164 | lineHeight = attribute.getDimension(R.styleable.WheelView_lineHeight, lineHeight);
165 |
166 | maskHeight = attribute.getDimension(R.styleable.WheelView_maskHeight, maskHeight);
167 | noEmpty = attribute.getBoolean(R.styleable.WheelView_noEmpty, true);
168 | isEnable = attribute.getBoolean(R.styleable.WheelView_isEnable, true);
169 |
170 | attribute.recycle();
171 |
172 | controlHeight = itemNumber * unitHeight;
173 | }
174 |
175 | /**
176 | * 初始化数据
177 | */
178 | private void initData() {
179 | isClearing = true;
180 | itemList.clear();
181 | for (int i = 0; i < dataList.size(); i++) {
182 | ItemObject itemObject = new ItemObject();
183 | itemObject.id = i;
184 | itemObject.itemText = dataList.get(i);
185 | itemObject.x = 0;
186 | itemObject.y = i * unitHeight;
187 | itemList.add(itemObject);
188 | }
189 | isClearing = false;
190 | }
191 |
192 | @Override
193 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
194 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
195 | controlWidth = getMeasuredWidth();
196 | if (controlWidth != 0) {
197 | setMeasuredDimension(getMeasuredWidth(), itemNumber * unitHeight);
198 | }
199 | }
200 |
201 | @Override
202 | protected void onDraw(Canvas canvas) {
203 | super.onDraw(canvas);
204 |
205 | drawLine(canvas);
206 | drawList(canvas);
207 | drawMask(canvas);
208 | }
209 |
210 | /**
211 | * 绘制线条
212 | *
213 | * @param canvas
214 | */
215 | private void drawLine(Canvas canvas) {
216 |
217 | if (linePaint == null) {
218 | linePaint = new Paint();
219 | linePaint.setColor(lineColor);
220 | linePaint.setAntiAlias(true);
221 | linePaint.setStrokeWidth(lineHeight);
222 | }
223 |
224 | canvas.drawLine(0, controlHeight / 2 - unitHeight / 2 + lineHeight,
225 | controlWidth, controlHeight / 2 - unitHeight / 2 + lineHeight, linePaint);
226 | canvas.drawLine(0, controlHeight / 2 + unitHeight / 2 - lineHeight,
227 | controlWidth, controlHeight / 2 + unitHeight / 2 - lineHeight, linePaint);
228 | }
229 |
230 | private synchronized void drawList(Canvas canvas) {
231 | if (isClearing)
232 | return;
233 | try {
234 | for (ItemObject itemObject : itemList) {
235 | itemObject.drawSelf(canvas, getMeasuredWidth());
236 | }
237 | } catch (Exception e) {
238 | }
239 | }
240 |
241 | /**
242 | * 绘制遮盖板
243 | *
244 | * @param canvas
245 | */
246 | private void drawMask(Canvas canvas) {
247 | LinearGradient lg = new LinearGradient(0, 0, 0, maskHeight, 0x00f2f2f2,
248 | 0x00f2f2f2, TileMode.MIRROR);
249 | Paint paint = new Paint();
250 | paint.setShader(lg);
251 | canvas.drawRect(0, 0, controlWidth, maskHeight, paint);
252 |
253 | LinearGradient lg2 = new LinearGradient(0, controlHeight - maskHeight,
254 | 0, controlHeight, 0x00f2f2f2, 0x00f2f2f2, TileMode.MIRROR);
255 | Paint paint2 = new Paint();
256 | paint2.setShader(lg2);
257 | canvas.drawRect(0, controlHeight - maskHeight, controlWidth,
258 | controlHeight, paint2);
259 | }
260 |
261 | @Override
262 | public boolean onTouchEvent(MotionEvent event) {
263 | if (!isEnable)
264 | return true;
265 | int y = (int) event.getY();
266 | switch (event.getAction()) {
267 | case MotionEvent.ACTION_DOWN:
268 | isScrolling = true;
269 | downY = (int) event.getY();
270 | downTime = System.currentTimeMillis();
271 | break;
272 | case MotionEvent.ACTION_MOVE:
273 | actionMove(y - downY);
274 | onSelectListener();
275 | break;
276 | case MotionEvent.ACTION_UP:
277 | int move = Math.abs(y - downY);
278 | // 判断这段时间移动的距离
279 | if (System.currentTimeMillis() - downTime < goonTime && move > goonDistance) {
280 | goonMove(y - downY);
281 | } else {
282 | actionUp(y - downY);
283 | noEmpty();
284 | isScrolling = false;
285 | }
286 | break;
287 | default:
288 | break;
289 | }
290 | return true;
291 | }
292 |
293 | /**
294 | * 继续移动一定距离
295 | */
296 | private synchronized void goonMove(final int move) {
297 | new Thread(new Runnable() {
298 |
299 | @Override
300 | public void run() {
301 | int distance = 0;
302 | while (distance < unitHeight * MOVE_NUMBER) {
303 | try {
304 | Thread.sleep(5);
305 | } catch (InterruptedException e) {
306 | e.printStackTrace();
307 | }
308 | actionThreadMove(move > 0 ? distance : distance * (-1));
309 | distance += 10;
310 |
311 | }
312 | actionUp(move > 0 ? distance - 10 : distance * (-1) + 10);
313 | noEmpty();
314 | }
315 | }).start();
316 | }
317 |
318 | /**
319 | * 不能为空,必须有选项
320 | */
321 | private void noEmpty() {
322 | if (!noEmpty)
323 | return;
324 | for (ItemObject item : itemList) {
325 | if (item.isSelected())
326 | return;
327 | }
328 | int move = (int) itemList.get(0).moveToSelected();
329 | if (move < 0) {
330 | defaultMove(move);
331 | } else {
332 | defaultMove((int) itemList.get(itemList.size() - 1)
333 | .moveToSelected());
334 | }
335 | for (ItemObject item : itemList) {
336 | if (item.isSelected()) {
337 | if (onSelectListener != null)
338 | onSelectListener.endSelect(item.id, item.itemText);
339 | break;
340 | }
341 | }
342 | }
343 |
344 | /**
345 | * 移动的时候
346 | *
347 | * @param move
348 | */
349 | private void actionMove(int move) {
350 | for (ItemObject item : itemList) {
351 | item.move(move);
352 | }
353 | invalidate();
354 | }
355 |
356 | /**
357 | * 移动,线程中调用
358 | *
359 | * @param move
360 | */
361 | private void actionThreadMove(int move) {
362 | for (ItemObject item : itemList) {
363 | item.move(move);
364 | }
365 | Message rMessage = new Message();
366 | rMessage.what = REFRESH_VIEW;
367 | handler.sendMessage(rMessage);
368 | }
369 |
370 | /**
371 | * 松开的时候
372 | *
373 | * @param move
374 | */
375 | private void actionUp(int move) {
376 | int newMove = 0;
377 | if (move > 0) {
378 | for (int i = 0; i < itemList.size(); i++) {
379 | if (itemList.get(i).isSelected()) {
380 | newMove = (int) itemList.get(i).moveToSelected();
381 | if (onSelectListener != null)
382 | onSelectListener.endSelect(itemList.get(i).id,
383 | itemList.get(i).itemText);
384 | break;
385 | }
386 | }
387 | } else {
388 | for (int i = itemList.size() - 1; i >= 0; i--) {
389 | if (itemList.get(i).isSelected()) {
390 | newMove = (int) itemList.get(i).moveToSelected();
391 | if (onSelectListener != null)
392 | onSelectListener.endSelect(itemList.get(i).id,
393 | itemList.get(i).itemText);
394 | break;
395 | }
396 | }
397 | }
398 | for (ItemObject item : itemList) {
399 | item.newY(move + 0);
400 | }
401 | slowMove(newMove);
402 | Message rMessage = new Message();
403 | rMessage.what = REFRESH_VIEW;
404 | handler.sendMessage(rMessage);
405 |
406 | }
407 |
408 | /**
409 | * 缓慢移动
410 | *
411 | * @param move
412 | */
413 | private synchronized void slowMove(final int move) {
414 | new Thread(new Runnable() {
415 |
416 | @Override
417 | public void run() {
418 | // 判断正负
419 | int m = move > 0 ? move : move * (-1);
420 | int i = move > 0 ? 1 : (-1);
421 | // 移动速度
422 | int speed = 1;
423 | while (true) {
424 | m = m - speed;
425 | if (m <= 0) {
426 | for (ItemObject item : itemList) {
427 | item.newY(m * i);
428 | }
429 | Message rMessage = new Message();
430 | rMessage.what = REFRESH_VIEW;
431 | handler.sendMessage(rMessage);
432 | try {
433 | Thread.sleep(2);
434 | } catch (InterruptedException e) {
435 | e.printStackTrace();
436 | }
437 | break;
438 | }
439 | for (ItemObject item : itemList) {
440 | item.newY(speed * i);
441 | }
442 | Message rMessage = new Message();
443 | rMessage.what = REFRESH_VIEW;
444 | handler.sendMessage(rMessage);
445 | try {
446 | Thread.sleep(2);
447 | } catch (InterruptedException e) {
448 | e.printStackTrace();
449 | }
450 | }
451 | for (ItemObject item : itemList) {
452 | if (item.isSelected()) {
453 | if (onSelectListener != null)
454 | onSelectListener.endSelect(item.id, item.itemText);
455 | break;
456 | }
457 | }
458 |
459 | }
460 | }).start();
461 | }
462 |
463 | /**
464 | * 移动到默认位置
465 | *
466 | * @param move
467 | */
468 | private void defaultMove(int move) {
469 | for (ItemObject item : itemList) {
470 | item.newY(move);
471 | }
472 | Message rMessage = new Message();
473 | rMessage.what = REFRESH_VIEW;
474 | handler.sendMessage(rMessage);
475 | }
476 |
477 | /**
478 | * 滑动监听
479 | */
480 | private void onSelectListener() {
481 | if (onSelectListener == null)
482 | return;
483 | for (ItemObject item : itemList) {
484 | if (item.isSelected()) {
485 | onSelectListener.selecting(item.id, item.itemText);
486 | }
487 | }
488 | }
489 |
490 | /**
491 | * 设置数据 (第一次)
492 | *
493 | * @param data
494 | */
495 | public void setData(ArrayList data) {
496 | this.dataList = data;
497 | initData();
498 | }
499 |
500 | /**
501 | * 重置数据
502 | *
503 | * @param data
504 | */
505 | public void refreshData(ArrayList data) {
506 | setData(data);
507 | invalidate();
508 | }
509 |
510 | /**
511 | * 获取返回项 id
512 | *
513 | * @return
514 | */
515 | public int getSelected() {
516 | for (ItemObject item : itemList) {
517 | if (item.isSelected())
518 | return item.id;
519 | }
520 | return -1;
521 | }
522 |
523 | /**
524 | * 获取返回的内容
525 | *
526 | * @return
527 | */
528 | public String getSelectedText() {
529 | for (ItemObject item : itemList) {
530 | if (item.isSelected())
531 | return item.itemText;
532 | }
533 | return "";
534 | }
535 |
536 | /**
537 | * 是否正在滑动
538 | *
539 | * @return
540 | */
541 | public boolean isScrolling() {
542 | return isScrolling;
543 | }
544 |
545 | /**
546 | * 是否可用
547 | *
548 | * @return
549 | */
550 | public boolean isEnable() {
551 | return isEnable;
552 | }
553 |
554 | /**
555 | * 设置是否可用
556 | *
557 | * @param isEnable
558 | */
559 | public void setEnable(boolean isEnable) {
560 | this.isEnable = isEnable;
561 | }
562 |
563 | /**
564 | * 设置默认选项
565 | *
566 | * @param index
567 | */
568 | public void setDefault(int index) {
569 | if (index > itemList.size() - 1)
570 | return;
571 | float move = itemList.get(index).moveToSelected();
572 | defaultMove((int) move);
573 | }
574 |
575 | /**
576 | * 获取列表大小
577 | *
578 | * @return
579 | */
580 | public int getListSize() {
581 | if (itemList == null)
582 | return 0;
583 | return itemList.size();
584 | }
585 |
586 | /**
587 | * 获取某项的内容
588 | *
589 | * @param index
590 | * @return
591 | */
592 | public String getItemText(int index) {
593 | if (itemList == null)
594 | return "";
595 | return itemList.get(index).itemText;
596 | }
597 |
598 | /**
599 | * 监听
600 | *
601 | * @param onSelectListener
602 | */
603 | public void setOnSelectListener(OnSelectListener onSelectListener) {
604 | this.onSelectListener = onSelectListener;
605 | }
606 |
607 | @SuppressLint("HandlerLeak")
608 | Handler handler = new Handler() {
609 |
610 | @Override
611 | public void handleMessage(Message msg) {
612 | super.handleMessage(msg);
613 | switch (msg.what) {
614 | case REFRESH_VIEW:
615 | invalidate();
616 | break;
617 | default:
618 | break;
619 | }
620 | }
621 |
622 | };
623 |
624 | /**
625 | * 单条内容
626 | *
627 | * @author JiangPing
628 | */
629 | private class ItemObject {
630 | /**
631 | * id
632 | */
633 | public int id = 0;
634 | /**
635 | * 内容
636 | */
637 | public String itemText = "";
638 | /**
639 | * x坐标
640 | */
641 | public int x = 0;
642 | /**
643 | * y坐标
644 | */
645 | public int y = 0;
646 | /**
647 | * 移动距离
648 | */
649 | public int move = 0;
650 | /**
651 | * 字体画笔
652 | */
653 | private TextPaint textPaint;
654 | /**
655 | * 字体范围矩形
656 | */
657 | private Rect textRect;
658 |
659 | public ItemObject() {
660 | super();
661 | }
662 |
663 | /**
664 | * 绘制自身
665 | *
666 | * @param canvas 画板
667 | * @param containerWidth 容器宽度
668 | */
669 | public void drawSelf(Canvas canvas, int containerWidth) {
670 |
671 | if (textPaint == null) {
672 | textPaint = new TextPaint();
673 | textPaint.setAntiAlias(true);
674 | }
675 |
676 | if (textRect == null)
677 | textRect = new Rect();
678 |
679 | // 判断是否被选择
680 | if (isSelected()) {
681 | textPaint.setColor(selectedColor);
682 | // 获取距离标准位置的距离
683 | float moveToSelect = moveToSelected();
684 | moveToSelect = moveToSelect > 0 ? moveToSelect : moveToSelect * (-1);
685 | // 计算当前字体大小
686 | float textSize = normalFont
687 | + ((selectedFont - normalFont) * (1.0f - moveToSelect / (float) unitHeight));
688 | textPaint.setTextSize(textSize);
689 | } else {
690 | textPaint.setColor(normalColor);
691 | textPaint.setTextSize(normalFont);
692 | }
693 |
694 | // 返回包围整个字符串的最小的一个Rect区域
695 | itemText = (String) TextUtils.ellipsize(itemText, textPaint, containerWidth, TextUtils.TruncateAt.END);
696 | textPaint.getTextBounds(itemText, 0, itemText.length(), textRect);
697 | // 判断是否可视
698 | if (!isInView())
699 | return;
700 |
701 | // 绘制内容
702 | canvas.drawText(itemText, x + controlWidth / 2 - textRect.width() / 2,
703 | y + move + unitHeight / 2 + textRect.height() / 2, textPaint);
704 |
705 | }
706 |
707 | /**
708 | * 是否在可视界面内
709 | *
710 | * @return
711 | */
712 | public boolean isInView() {
713 | if (y + move > controlHeight || (y + move + unitHeight / 2 + textRect.height() / 2) < 0)
714 | return false;
715 | return true;
716 | }
717 |
718 | /**
719 | * 移动距离
720 | *
721 | * @param _move
722 | */
723 | public void move(int _move) {
724 | this.move = _move;
725 | }
726 |
727 | /**
728 | * 设置新的坐标
729 | *
730 | * @param _move
731 | */
732 | public void newY(int _move) {
733 | this.move = 0;
734 | this.y = y + _move;
735 | }
736 |
737 | /**
738 | * 判断是否在选择区域内
739 | *
740 | * @return
741 | */
742 | public boolean isSelected() {
743 | if ((y + move) >= controlHeight / 2 - unitHeight / 2 + lineHeight
744 | && (y + move) <= controlHeight / 2 + unitHeight / 2 - lineHeight) {
745 | return true;
746 | }
747 | if ((y + move + unitHeight) >= controlHeight / 2 - unitHeight / 2 + lineHeight
748 | && (y + move + unitHeight) <= controlHeight / 2 + unitHeight / 2 - lineHeight) {
749 | return true;
750 | }
751 | if ((y + move) <= controlHeight / 2 - unitHeight / 2 + lineHeight
752 | && (y + move + unitHeight) >= controlHeight / 2 + unitHeight / 2 - lineHeight) {
753 | return true;
754 | }
755 | return false;
756 | }
757 |
758 | /**
759 | * 获取移动到标准位置需要的距离
760 | */
761 | public float moveToSelected() {
762 | return (controlHeight / 2 - unitHeight / 2) - (y + move);
763 | }
764 | }
765 |
766 | /**
767 | * 选择监听
768 | *
769 | * @author JiangPing
770 | */
771 | public interface OnSelectListener {
772 | /**
773 | * 结束选择
774 | *
775 | * @param id
776 | * @param text
777 | */
778 | void endSelect(int id, String text);
779 |
780 | /**
781 | * 选中的内容
782 | *
783 | * @param id
784 | * @param text
785 | */
786 | void selecting(int id, String text);
787 |
788 | }
789 | }
790 |
--------------------------------------------------------------------------------