├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── huangzj │ │ └── simplewheelview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── huangzj │ │ │ └── simplewheelview │ │ │ ├── MainActivity.java │ │ │ ├── dialog │ │ │ ├── BaseDialog.java │ │ │ ├── SelectDateDialog.java │ │ │ ├── SelectTimeDialog.java │ │ │ └── SelectWeekDialog.java │ │ │ ├── util │ │ │ └── SizeConvertUtil.java │ │ │ └── view │ │ │ ├── WheelStyle.java │ │ │ └── WheelView.java │ └── res │ │ ├── drawable │ │ └── dialog_button_bg.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── content_main.xml │ │ ├── dialog_wheel_select_date.xml │ │ ├── dialog_wheel_select_time.xml │ │ └── dialog_wheel_select_week.xml │ │ ├── menu │ │ └── menu_main.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-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── huangzj │ └── simplewheelview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WheelView 2 | Android时间、日期滚轮选择控件,继承View,重写onDraw()方法,轻量实现 3 | 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.huangzj.simplewheelview" 9 | minSdkVersion 9 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.1.1' 26 | compile 'com.android.support:design:23.1.1' 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 E:\android-sdk-windows-r23/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/huangzj/simplewheelview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview; 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 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.widget.Button; 12 | import android.widget.Toast; 13 | 14 | import com.huangzj.simplewheelview.dialog.SelectDateDialog; 15 | import com.huangzj.simplewheelview.dialog.SelectTimeDialog; 16 | import com.huangzj.simplewheelview.dialog.SelectWeekDialog; 17 | 18 | import java.text.SimpleDateFormat; 19 | 20 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 21 | 22 | private Button selectDate; 23 | private Button selectTime; 24 | private Button selectLightTime; 25 | 26 | private String[] weekString; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_main); 32 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 33 | setSupportActionBar(toolbar); 34 | 35 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 36 | fab.setOnClickListener(new View.OnClickListener() { 37 | @Override 38 | public void onClick(View view) { 39 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 40 | .setAction("Action", null).show(); 41 | } 42 | }); 43 | 44 | initView(); 45 | initValue(); 46 | } 47 | 48 | private void initValue() { 49 | weekString = getResources().getStringArray(R.array.weeks); 50 | } 51 | 52 | 53 | private void initView() { 54 | selectDate = (Button) findViewById(R.id.show_select_date); 55 | selectTime = (Button) findViewById(R.id.show_select_time); 56 | selectLightTime = (Button) findViewById(R.id.show_select_week); 57 | 58 | selectDate.setOnClickListener(this); 59 | selectTime.setOnClickListener(this); 60 | selectLightTime.setOnClickListener(this); 61 | } 62 | 63 | @Override 64 | public void onClick(View v) { 65 | switch (v.getId()) { 66 | case R.id.show_select_date: 67 | showSelectDateDialog(); 68 | break; 69 | case R.id.show_select_time: 70 | showSelectTimeDialog(); 71 | break; 72 | case R.id.show_select_week: 73 | showSelectWeekDialog(); 74 | break; 75 | default: 76 | break; 77 | } 78 | 79 | } 80 | 81 | private void showSelectWeekDialog() { 82 | SelectWeekDialog mSelectWeekDialog = new SelectWeekDialog(this, new SelectWeekDialog.OnClickListener() { 83 | @Override 84 | public boolean onSure(int item, int setTimeType) { 85 | Toast.makeText(MainActivity.this, weekString[item], Toast.LENGTH_LONG).show(); 86 | return false; 87 | } 88 | 89 | @Override 90 | public boolean onCancel() { 91 | return false; 92 | } 93 | }); 94 | mSelectWeekDialog.show(3); 95 | } 96 | 97 | private void showSelectTimeDialog() { 98 | SelectTimeDialog mSelectTimeDialog = new SelectTimeDialog(this, new SelectTimeDialog.OnClickListener() { 99 | @Override 100 | public boolean onSure(int hour, int minute, int setTimeType) { 101 | String result = String.format("%02d:%02d", hour, minute); 102 | Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show(); 103 | return false; 104 | } 105 | 106 | @Override 107 | public boolean onCancel() { 108 | return false; 109 | } 110 | }); 111 | mSelectTimeDialog.show(12, 30, 1); 112 | } 113 | 114 | private void showSelectDateDialog() { 115 | SelectDateDialog mSelectDateDialog = new SelectDateDialog(this); 116 | mSelectDateDialog.setOnClickListener(new SelectDateDialog.OnClickListener() { 117 | @Override 118 | public boolean onSure(int mYear, int mMonth, int mDay, long time) { 119 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 120 | Toast.makeText(MainActivity.this, dateFormat.format(time), Toast.LENGTH_LONG).show(); 121 | return false; 122 | } 123 | 124 | @Override 125 | public boolean onCancel() { 126 | return false; 127 | } 128 | }); 129 | mSelectDateDialog.show(2013, 11, 15); 130 | } 131 | 132 | @Override 133 | public boolean onCreateOptionsMenu(Menu menu) { 134 | // Inflate the menu; this adds items to the action bar if it is present. 135 | getMenuInflater().inflate(R.menu.menu_main, menu); 136 | return true; 137 | } 138 | 139 | @Override 140 | public boolean onOptionsItemSelected(MenuItem item) { 141 | // Handle action bar item clicks here. The action bar will 142 | // automatically handle clicks on the Home/Up button, so long 143 | // as you specify a parent activity in AndroidManifest.xml. 144 | int id = item.getItemId(); 145 | 146 | //noinspection SimplifiableIfStatement 147 | if (id == R.id.action_settings) { 148 | return true; 149 | } 150 | 151 | return super.onOptionsItemSelected(item); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/dialog/BaseDialog.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | 6 | /** 7 | * Created by huangzj on 2015/10/25. 8 | *

9 | * 对话框基类 10 | */ 11 | public abstract class BaseDialog { 12 | 13 | protected Context context; 14 | protected Dialog dialog; 15 | 16 | public boolean isShow() { 17 | if (dialog != null) { 18 | return dialog.isShowing(); 19 | } 20 | return false; 21 | } 22 | 23 | public void show() { 24 | if (dialog == null || dialog.isShowing()) { 25 | return; 26 | } 27 | dialog.show(); 28 | } 29 | 30 | public void dismiss() { 31 | if (dialog == null || !dialog.isShowing()) { 32 | return; 33 | } 34 | dialog.dismiss(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/dialog/SelectDateDialog.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | 10 | import com.huangzj.simplewheelview.R; 11 | import com.huangzj.simplewheelview.view.WheelStyle; 12 | import com.huangzj.simplewheelview.view.WheelView; 13 | 14 | import java.util.Calendar; 15 | 16 | /** 17 | * 日期选择对话框 18 | *

19 | * Created by huangzj on 2015/10/25. 20 | */ 21 | public class SelectDateDialog extends BaseDialog { 22 | 23 | private View dialogView; 24 | private WheelView yearWheel; 25 | private WheelView monthWheel; 26 | private WheelView dayWheel; 27 | 28 | int selectYear; 29 | int selectMonth; 30 | 31 | private OnClickListener onClickListener; 32 | 33 | /** 34 | * 创建一个日期选择对话框 35 | * 36 | * @param mContext 37 | */ 38 | public SelectDateDialog(Context mContext) { 39 | this.context = mContext; 40 | create(); 41 | } 42 | 43 | /** 44 | * 创建一个日期选择对话框 45 | * 46 | * @param mContext 47 | */ 48 | public SelectDateDialog(Context mContext, OnClickListener listener) { 49 | this.context = mContext; 50 | onClickListener = listener; 51 | create(); 52 | } 53 | 54 | /** 55 | * 创建选择日期对话框 56 | */ 57 | private void create() { 58 | 59 | if (dialog != null) { 60 | return; 61 | } 62 | 63 | LayoutInflater layoutInflater = LayoutInflater.from(context); 64 | dialogView = layoutInflater.inflate(R.layout.dialog_wheel_select_date, null); 65 | yearWheel = (WheelView) dialogView.findViewById(R.id.select_date_wheel_year_wheel); 66 | monthWheel = (WheelView) dialogView.findViewById(R.id.select_date_month_wheel); 67 | dayWheel = (WheelView) dialogView.findViewById(R.id.select_date_day_wheel); 68 | 69 | yearWheel.setWheelStyle(WheelStyle.STYLE_YEAR); 70 | yearWheel.setOnSelectListener(new WheelView.SelectListener() { 71 | @Override 72 | public void onSelect(int index, String text) { 73 | selectYear = index + WheelStyle.minYear; 74 | dayWheel.setWheelItemList(WheelStyle.createDayString(selectYear, selectMonth)); 75 | } 76 | }); 77 | 78 | monthWheel.setWheelStyle(WheelStyle.STYLE_MONTH); 79 | monthWheel.setOnSelectListener(new WheelView.SelectListener() { 80 | @Override 81 | public void onSelect(int index, String text) { 82 | selectMonth = index + 1; 83 | dayWheel.setWheelItemList(WheelStyle.createDayString(selectYear, selectMonth)); 84 | } 85 | }); 86 | 87 | Button cancelBt = (Button) dialogView.findViewById(R.id.select_date_cancel); 88 | cancelBt.setOnClickListener(new View.OnClickListener() { 89 | 90 | @Override 91 | public void onClick(View v) { 92 | if (onClickListener != null) { 93 | if (!onClickListener.onCancel()) { 94 | dialog.dismiss(); 95 | } 96 | } else { 97 | dialog.dismiss(); 98 | } 99 | } 100 | }); 101 | Button sureBt = (Button) dialogView.findViewById(R.id.select_date_sure); 102 | sureBt.setOnClickListener(new View.OnClickListener() { 103 | 104 | @Override 105 | public void onClick(View v) { 106 | int year = yearWheel.getCurrentItem() + WheelStyle.minYear; 107 | int month = monthWheel.getCurrentItem(); 108 | int day = dayWheel.getCurrentItem() + 1; 109 | int daySize = dayWheel.getItemCount(); 110 | if (day > daySize) { 111 | day = day - daySize; 112 | } 113 | Calendar calendar = Calendar.getInstance(); 114 | calendar.set(Calendar.YEAR, year); 115 | calendar.set(Calendar.MONTH, month); 116 | calendar.set(Calendar.DATE, day); 117 | long setTime = calendar.getTimeInMillis(); 118 | 119 | if (onClickListener != null) { 120 | if (!onClickListener.onSure(year, month, day, setTime)) { 121 | dialog.dismiss(); 122 | } 123 | } else { 124 | dialog.dismiss(); 125 | } 126 | } 127 | }); 128 | dialog = new AlertDialog.Builder(context).setView(dialogView).create(); 129 | 130 | 131 | } 132 | 133 | /** 134 | * 显示选择日期对话框 135 | * 136 | * @param year 默认显示的年 137 | * @param month 默认月 138 | * @param day 默认日 139 | */ 140 | public void show(int year, int month, int day) { 141 | if (dialog == null || dialog.isShowing()) { 142 | return; 143 | } 144 | dayWheel.setWheelItemList(WheelStyle.createDayString(year - WheelStyle.minYear, month + 1)); 145 | yearWheel.setCurrentItem(year - WheelStyle.minYear); 146 | monthWheel.setCurrentItem(month); 147 | dayWheel.setCurrentItem(day - 1); 148 | dialog.show(); 149 | } 150 | 151 | 152 | /** 153 | * 选择日期对话框回调 154 | * 155 | * @param listener 156 | */ 157 | public void setOnClickListener(OnClickListener listener) { 158 | onClickListener = listener; 159 | } 160 | 161 | /** 162 | * 选择日期对话框回调接口,调用者实现 163 | * 164 | * @author huangzj 165 | */ 166 | public interface OnClickListener { 167 | boolean onSure(int year, int month, int day, long time); 168 | 169 | boolean onCancel(); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/dialog/SelectTimeDialog.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import com.huangzj.simplewheelview.R; 10 | import com.huangzj.simplewheelview.view.WheelStyle; 11 | import com.huangzj.simplewheelview.view.WheelView; 12 | 13 | 14 | /** 15 | * Created by huangzj on 2015/10/25. 16 | *

17 | * 时间选择对话框 18 | */ 19 | public class SelectTimeDialog extends BaseDialog { 20 | 21 | private View dialogView; 22 | private WheelView leftWheel; 23 | private WheelView rightWheel; 24 | 25 | private int timeType = 0; 26 | private OnClickListener onClickListener; 27 | 28 | boolean cancelable = true; 29 | 30 | /** 31 | * 创建一个时间选择对话框 32 | * 33 | * @param mContext 34 | */ 35 | public SelectTimeDialog(Context mContext, OnClickListener listener) { 36 | this.context = mContext; 37 | onClickListener = listener; 38 | create(); 39 | } 40 | 41 | /** 42 | * 创建选择时间对话框 43 | */ 44 | private void create() { 45 | 46 | if (dialog != null) { 47 | return; 48 | } 49 | 50 | LayoutInflater layoutInflater = LayoutInflater.from(context); 51 | dialogView = layoutInflater.inflate(R.layout.dialog_wheel_select_time, null); 52 | leftWheel = (WheelView) dialogView.findViewById(R.id.select_time_wheel_left); 53 | rightWheel = (WheelView) dialogView.findViewById(R.id.select_time_wheel_right); 54 | leftWheel.setWheelStyle(WheelStyle.STYLE_HOUR); 55 | rightWheel.setWheelStyle(WheelStyle.STYLE_MINUTE); 56 | 57 | dialog = new AlertDialog.Builder(context).setView(dialogView).create(); 58 | 59 | dialog.setCancelable(cancelable); 60 | 61 | Button cancelBtn = (Button) dialogView.findViewById(R.id.select_time_cancel_btn); 62 | cancelBtn.setOnClickListener(new View.OnClickListener() { 63 | 64 | @Override 65 | public void onClick(View v) { 66 | if (onClickListener != null) { 67 | if (!onClickListener.onCancel()) { 68 | dialog.dismiss(); 69 | } 70 | } else { 71 | dialog.dismiss(); 72 | } 73 | } 74 | }); 75 | Button sureBtn = (Button) dialogView.findViewById(R.id.select_time_sure_btn); 76 | sureBtn.setOnClickListener(new View.OnClickListener() { 77 | 78 | @Override 79 | public void onClick(View v) { 80 | if (onClickListener != null) { 81 | if (!onClickListener.onSure(leftWheel.getCurrentItem(), 82 | rightWheel.getCurrentItem(), timeType)) { 83 | dialog.dismiss(); 84 | } 85 | } else { 86 | dialog.dismiss(); 87 | } 88 | 89 | } 90 | }); 91 | 92 | } 93 | 94 | /** 95 | * 显示选择时间对话框 96 | * 97 | * @param mHour 默认显示的小时 98 | * @param mMinute 默认小时的分钟 99 | * @param timeType 设置的时间标签,用于调用者识别回调 100 | */ 101 | public void show(int mHour, int mMinute, int timeType) { 102 | if (dialog == null || dialog.isShowing()) { 103 | return; 104 | } 105 | this.timeType = timeType; 106 | leftWheel.setCurrentItem(mHour); 107 | rightWheel.setCurrentItem(mMinute); 108 | dialog.show(); 109 | } 110 | 111 | /** 112 | * 显示选择时间对话框 113 | * 114 | * @param mHour 默认显示的小时 115 | * @param mMinute 默认小时的分钟 116 | */ 117 | public void show(int mHour, int mMinute) { 118 | if (dialog == null || dialog.isShowing()) { 119 | return; 120 | } 121 | leftWheel.setCurrentItem(mHour); 122 | rightWheel.setCurrentItem(mMinute); 123 | dialog.show(); 124 | } 125 | 126 | /** 127 | * 选择时间对话框回调 128 | * 129 | * @param listener 130 | */ 131 | public void setOnUpdateTimeListener(OnClickListener listener) { 132 | onClickListener = listener; 133 | } 134 | 135 | /** 136 | * 选择时间对话框回调接口,调用者实现 137 | * 138 | * @author huangzj 139 | */ 140 | public interface OnClickListener { 141 | boolean onSure(int hour, int minute, int setTimeType); 142 | 143 | boolean onCancel(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/dialog/SelectWeekDialog.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import com.huangzj.simplewheelview.R; 10 | import com.huangzj.simplewheelview.view.WheelStyle; 11 | import com.huangzj.simplewheelview.view.WheelView; 12 | 13 | 14 | /** 15 | * Created by huangzj on 2015/10/25. 16 | *

17 | * 选择亮屏时间对话框 18 | */ 19 | public class SelectWeekDialog extends BaseDialog { 20 | 21 | private View dialogView; 22 | private WheelView wheel; 23 | 24 | private int timeType = 0; 25 | private OnClickListener onClickListener; 26 | 27 | boolean cancelable = true; 28 | 29 | /** 30 | * 创建一个选择亮屏时间对话框 31 | * 32 | * @param mContext 33 | */ 34 | public SelectWeekDialog(Context mContext, OnClickListener listener) { 35 | this.context = mContext; 36 | onClickListener = listener; 37 | create(); 38 | } 39 | 40 | /** 41 | * 创建选择亮屏时间对话框 42 | */ 43 | private void create() { 44 | 45 | if (dialog != null) { 46 | return; 47 | } 48 | 49 | LayoutInflater layoutInflater = LayoutInflater.from(context); 50 | dialogView = layoutInflater.inflate(R.layout.dialog_wheel_select_week, null); 51 | wheel = (WheelView) dialogView.findViewById(R.id.wheel_week_wheel); 52 | 53 | wheel.setWheelStyle(WheelStyle.STYLE_LIGHT_TIME); 54 | 55 | dialog = new AlertDialog.Builder(context).setView(dialogView).create(); 56 | dialog.setCancelable(cancelable); 57 | 58 | Button cancelBt = (Button) dialogView.findViewById(R.id.wheel_week_cancel_btn); 59 | cancelBt.setOnClickListener(new View.OnClickListener() { 60 | 61 | @Override 62 | public void onClick(View v) { 63 | if (onClickListener != null) { 64 | if (!onClickListener.onCancel()) { 65 | dialog.dismiss(); 66 | } 67 | } else { 68 | dialog.dismiss(); 69 | } 70 | } 71 | }); 72 | Button sureBt = (Button) dialogView.findViewById(R.id.week_wheel_sure_btn); 73 | sureBt.setOnClickListener(new View.OnClickListener() { 74 | 75 | @Override 76 | public void onClick(View v) { 77 | int index = wheel.getCurrentItem(); 78 | 79 | if (onClickListener != null) { 80 | if (onClickListener.onSure(index, timeType)) { 81 | dialog.dismiss(); 82 | } 83 | } else { 84 | dialog.dismiss(); 85 | } 86 | } 87 | }); 88 | } 89 | 90 | /** 91 | * 设置对话框类型 92 | * 93 | * @param style WheelAdapter类型 94 | */ 95 | public void setDialogWheelStyle(int style) { 96 | wheel.setWheelStyle(style); 97 | } 98 | 99 | /** 100 | * 显示亮屏时间对话框 101 | * 102 | * @param selectItem 默认选中项 103 | */ 104 | public void show(int selectItem) { 105 | if (dialog == null || dialog.isShowing()) { 106 | return; 107 | } 108 | wheel.setCurrentItem(selectItem); 109 | dialog.show(); 110 | } 111 | 112 | /** 113 | * 显示选择时间对话框 114 | * 115 | * @param selectItme 默认选中项 116 | * @param timeType 设置的类型标签,用于调用者识别回调 117 | */ 118 | public void show(int selectItme, int timeType) { 119 | if (dialog == null || dialog.isShowing()) { 120 | return; 121 | } 122 | this.timeType = timeType; 123 | wheel.setCurrentItem(selectItme); 124 | dialog.show(); 125 | } 126 | 127 | /** 128 | * 选择时间对话框回调 129 | * 130 | * @param listener 131 | */ 132 | public void setOnClickListener(OnClickListener listener) { 133 | onClickListener = listener; 134 | } 135 | 136 | /** 137 | * 选择时间对话框回调接口,调用者实现 138 | * 139 | * @author huangzj 140 | */ 141 | public interface OnClickListener { 142 | boolean onSure(int item, int setTimeType); 143 | 144 | boolean onCancel(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/util/SizeConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * 尺寸转换工具 7 | * 8 | * Created by huangzj on 2015/12/25. 9 | */ 10 | public class SizeConvertUtil { 11 | 12 | private SizeConvertUtil() {} 13 | 14 | public static int dpTopx(Context context, float dp) { 15 | final float scale = context.getResources().getDisplayMetrics().density; 16 | return (int) (dp * scale + 0.5f); 17 | } 18 | 19 | public static int pxTodp(Context context, float px) { 20 | final float scale = context.getResources().getDisplayMetrics().density; 21 | return (int) (px / scale + 0.5f); 22 | } 23 | 24 | public static int pxTosp(Context context, float px) { 25 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 26 | return (int) (px / fontScale + 0.5f); 27 | } 28 | 29 | public static int spTopx(Context context, float sp) { 30 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 31 | return (int) (sp * fontScale + 0.5f); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/view/WheelStyle.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.view; 2 | 3 | import android.content.Context; 4 | 5 | import com.huangzj.simplewheelview.R; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * 生成wheel的各种选项 12 | *

13 | * Created by huangzj on 2015/12/25. 14 | */ 15 | public class WheelStyle { 16 | 17 | public static final int minYear = 1980; 18 | public static final int maxYear = 2020; 19 | 20 | /** 21 | * Wheel Style Hour 22 | */ 23 | public static final int STYLE_HOUR = 1; 24 | /** 25 | * Wheel Style Minute 26 | */ 27 | public static final int STYLE_MINUTE = 2; 28 | /** 29 | * Wheel Style Year 30 | */ 31 | public static final int STYLE_YEAR = 3; 32 | /** 33 | * Wheel Style Month 34 | */ 35 | public static final int STYLE_MONTH = 4; 36 | /** 37 | * Wheel Style Day 38 | */ 39 | public static final int STYLE_DAY = 5; 40 | /** 41 | * Wheel Style Light Time 42 | */ 43 | public static final int STYLE_LIGHT_TIME = 7; 44 | 45 | private WheelStyle() {} 46 | 47 | public static List getItemList(Context context, int Style) { 48 | if (Style == STYLE_HOUR) { 49 | return createHourString(); 50 | } else if (Style == STYLE_MINUTE) { 51 | return createMinuteString(); 52 | } else if (Style == STYLE_YEAR) { 53 | return createYearString(); 54 | } else if (Style == STYLE_MONTH) { 55 | return createMonthString(); 56 | } else if (Style == STYLE_DAY) { 57 | return createDayString(); 58 | } else if (Style == STYLE_LIGHT_TIME) { 59 | return createWeekString(context); 60 | } else { 61 | throw new IllegalArgumentException("style is illegal"); 62 | } 63 | } 64 | 65 | private static List createHourString() { 66 | List wheelString = new ArrayList<>(); 67 | for (int i = 0; i < 24; i++) { 68 | wheelString.add(String.format("%02d", i)); 69 | } 70 | return wheelString; 71 | } 72 | 73 | private static List createMinuteString() { 74 | List wheelString = new ArrayList<>(); 75 | for (int i = 0; i < 60; i++) { 76 | wheelString.add(String.format("%02d", i)); 77 | } 78 | return wheelString; 79 | } 80 | 81 | private static List createYearString() { 82 | List wheelString = new ArrayList<>(); 83 | for (int i = minYear; i <= maxYear; i++) { 84 | wheelString.add(Integer.toString(i)); 85 | } 86 | return wheelString; 87 | } 88 | 89 | private static List createMonthString() { 90 | List wheelString = new ArrayList<>(); 91 | for (int i = 1; i <= 12; i++) { 92 | wheelString.add(String.format("%02d", i)); 93 | } 94 | return wheelString; 95 | } 96 | 97 | private static List createDayString() { 98 | List wheelString = new ArrayList<>(); 99 | for (int i = 1; i <= 31; i++) { 100 | wheelString.add(String.format("%02d", i)); 101 | } 102 | return wheelString; 103 | } 104 | 105 | private static List createWeekString(Context context) { 106 | List wheelString = new ArrayList<>(); 107 | String[] timeString = context.getResources().getStringArray(R.array.weeks); 108 | for (String week : timeString) { 109 | wheelString.add(week); 110 | } 111 | return wheelString; 112 | } 113 | 114 | public static List createDayString(int year, int month) { 115 | List wheelString = new ArrayList<>(); 116 | int size; 117 | if (isLeapMonth(month)) { 118 | size = 31; 119 | } else if (month == 2) { 120 | if (isLeapYear(year)) { 121 | size = 29; 122 | } else { 123 | size = 28; 124 | } 125 | } else { 126 | size = 30; 127 | } 128 | 129 | for (int i = 1; i <= size; i++) { 130 | wheelString.add(String.format("%02d", i)); 131 | } 132 | return wheelString; 133 | } 134 | 135 | /** 136 | * 计算闰月 137 | * 138 | * @param month 139 | * @return 140 | */ 141 | private static boolean isLeapMonth(int month) { 142 | return month == 1 || month == 3 || month == 5 || month == 7 143 | || month == 8 || month == 10 || month == 12; 144 | } 145 | 146 | /** 147 | * 计算闰年 148 | * 149 | * @param year 150 | * @return 151 | */ 152 | private static boolean isLeapYear(int year) { 153 | return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/java/com/huangzj/simplewheelview/view/WheelView.java: -------------------------------------------------------------------------------- 1 | package com.huangzj.simplewheelview.view; 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.Paint.Align; 8 | import android.graphics.Paint.FontMetricsInt; 9 | import android.graphics.Paint.Style; 10 | import android.graphics.Rect; 11 | import android.graphics.drawable.Drawable; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.util.AttributeSet; 15 | import android.util.Log; 16 | import android.view.MotionEvent; 17 | import android.view.View; 18 | 19 | import com.huangzj.simplewheelview.R; 20 | import com.huangzj.simplewheelview.util.SizeConvertUtil; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.Timer; 25 | import java.util.TimerTask; 26 | 27 | /** 28 | * 滚轮选择器 29 | *

30 | * Created by huangzj on 2015/12/25. 31 | */ 32 | public class WheelView extends View { 33 | 34 | public static final String TAG = "WheelView"; 35 | 36 | /** 37 | * 自动回滚到中间的速度 38 | */ 39 | public static final float SPEED = 2; 40 | 41 | /** 42 | * 除选中item外,上下各需要显示的备选项数目 43 | */ 44 | public static final int SHOW_SIZE = 1; 45 | 46 | private Context context; 47 | 48 | private List itemList; 49 | private int itemCount; 50 | 51 | /** 52 | * item高度 53 | */ 54 | private int itemHeight = 50; 55 | 56 | /** 57 | * 选中的位置,这个位置是mDataList的中心位置,一直不变 58 | */ 59 | private int currentItem; 60 | 61 | private Paint selectPaint; 62 | private Paint mPaint; 63 | // 画背景图中单独的画笔 64 | private Paint centerLinePaint; 65 | 66 | private float centerY; 67 | private float centerX; 68 | 69 | private float mLastDownY; 70 | /** 71 | * 滑动的距离 72 | */ 73 | private float mMoveLen = 0; 74 | private boolean isInit = false; 75 | private SelectListener mSelectListener; 76 | private Timer timer; 77 | private MyTimerTask mTask; 78 | 79 | Handler updateHandler = new Handler() { 80 | 81 | @Override 82 | public void handleMessage(Message msg) { 83 | if (Math.abs(mMoveLen) < SPEED) { 84 | // 如果偏移量少于最少偏移量 85 | mMoveLen = 0; 86 | if (null != timer) { 87 | timer.cancel(); 88 | timer.purge(); 89 | timer = null; 90 | } 91 | if (mTask != null) { 92 | mTask.cancel(); 93 | mTask = null; 94 | performSelect(); 95 | } 96 | } else { 97 | // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚 98 | mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED; 99 | } 100 | invalidate(); 101 | } 102 | 103 | }; 104 | 105 | public WheelView(Context context) { 106 | super(context); 107 | init(context); 108 | } 109 | 110 | public WheelView(Context context, AttributeSet attrs) { 111 | super(context, attrs); 112 | init(context); 113 | } 114 | 115 | public void setOnSelectListener(SelectListener listener) { 116 | mSelectListener = listener; 117 | } 118 | 119 | public void setWheelStyle(int style) { 120 | itemList = WheelStyle.getItemList(context, style); 121 | if (itemList != null) { 122 | itemCount = itemList.size(); 123 | resetCurrentSelect(); 124 | invalidate(); 125 | } else { 126 | Log.i(TAG, "item is null"); 127 | } 128 | } 129 | 130 | public void setWheelItemList(List itemList) { 131 | this.itemList = itemList; 132 | if (itemList != null) { 133 | itemCount = itemList.size(); 134 | resetCurrentSelect(); 135 | } else { 136 | Log.i(TAG, "item is null"); 137 | } 138 | } 139 | 140 | private void resetCurrentSelect() { 141 | if (currentItem < 0) { 142 | currentItem = 0; 143 | } 144 | while (currentItem >= itemCount) { 145 | currentItem--; 146 | } 147 | if (currentItem >= 0 && currentItem < itemCount) { 148 | invalidate(); 149 | } else { 150 | Log.i(TAG, "current item is invalid"); 151 | } 152 | } 153 | 154 | public int getItemCount() { 155 | return itemCount; 156 | } 157 | 158 | /** 159 | * 选择选中的item的index 160 | */ 161 | public void setCurrentItem(int selected) { 162 | currentItem = selected; 163 | resetCurrentSelect(); 164 | } 165 | 166 | public int getCurrentItem() { 167 | return currentItem; 168 | } 169 | 170 | @Override 171 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 172 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 173 | int mViewHeight = getMeasuredHeight(); 174 | int mViewWidth = getMeasuredWidth(); 175 | centerX = (float) (mViewWidth / 2.0); 176 | centerY = (float) (mViewHeight / 2.0); 177 | 178 | isInit = true; 179 | invalidate(); 180 | } 181 | 182 | 183 | private void init(Context context) { 184 | this.context = context; 185 | 186 | timer = new Timer(); 187 | itemList = new ArrayList<>(); 188 | 189 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 190 | mPaint.setStyle(Style.FILL); 191 | mPaint.setTextAlign(Align.CENTER); 192 | mPaint.setColor(getResources().getColor(R.color.wheel_unselect_text)); 193 | mPaint.setTextSize(SizeConvertUtil.spTopx(context, 18)); 194 | 195 | selectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 196 | selectPaint.setStyle(Style.FILL); 197 | selectPaint.setTextAlign(Align.CENTER); 198 | selectPaint.setColor(getResources().getColor(R.color.orange)); 199 | selectPaint.setTextSize(SizeConvertUtil.spTopx(context, 22)); 200 | 201 | centerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 202 | centerLinePaint.setStyle(Style.FILL); 203 | centerLinePaint.setTextAlign(Align.CENTER); 204 | centerLinePaint.setColor(getResources().getColor(R.color.wheel_unselect_text)); 205 | 206 | // 绘制背景 207 | setBackground(null); 208 | } 209 | 210 | @Override 211 | protected void onDraw(Canvas canvas) { 212 | super.onDraw(canvas); 213 | if (isInit) { 214 | drawData(canvas); 215 | } 216 | } 217 | 218 | private void drawData(Canvas canvas) { 219 | // 先绘制选中的text再往上往下绘制其余的text 220 | if (!itemList.isEmpty()) { 221 | // 绘制中间data 222 | drawCenterText(canvas); 223 | // 绘制上方data 224 | for (int i = 1; i < SHOW_SIZE + 1; i++) { 225 | drawOtherText(canvas, i, -1); 226 | } 227 | // 绘制下方data 228 | for (int i = 1; i < SHOW_SIZE + 1; i++) { 229 | drawOtherText(canvas, i, 1); 230 | } 231 | } 232 | } 233 | 234 | private void drawCenterText(Canvas canvas) { 235 | // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标 236 | float y = centerY + mMoveLen; 237 | FontMetricsInt fmi = selectPaint.getFontMetricsInt(); 238 | float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); 239 | canvas.drawText(itemList.get(currentItem), centerX, baseline, selectPaint); 240 | } 241 | 242 | /** 243 | * @param canvas 画布 244 | * @param position 距离mCurrentSelected的差值 245 | * @param type 1表示向下绘制,-1表示向上绘制 246 | */ 247 | private void drawOtherText(Canvas canvas, int position, int type) { 248 | int index = currentItem + type * position; 249 | if (index >= itemCount) { 250 | index = index - itemCount; 251 | } 252 | if (index < 0) { 253 | index = index + itemCount; 254 | } 255 | String text = itemList.get(index); 256 | 257 | int itemHeight = getHeight() / (SHOW_SIZE * 2 + 1); 258 | float d = itemHeight * position + type * mMoveLen; 259 | float y = centerY + type * d; 260 | 261 | FontMetricsInt fmi = mPaint.getFontMetricsInt(); 262 | float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); 263 | canvas.drawText(text, centerX, baseline, mPaint); 264 | } 265 | 266 | @Override 267 | public void setBackground(Drawable background) { 268 | background = new Drawable() { 269 | @Override 270 | public void draw(Canvas canvas) { 271 | itemHeight = getHeight() / (SHOW_SIZE * 2 + 1); 272 | int width = getWidth(); 273 | 274 | canvas.drawLine(0, itemHeight, width, itemHeight, centerLinePaint); 275 | canvas.drawLine(0, itemHeight * 2, width, itemHeight * 2, centerLinePaint); 276 | 277 | centerLinePaint.setColor(getResources().getColor(R.color.wheel_bg)); 278 | Rect topRect = new Rect(0, 0, width, itemHeight); 279 | canvas.drawRect(topRect, centerLinePaint); 280 | Rect bottomRect = new Rect(0, itemHeight * 2, width, itemHeight * 3); 281 | canvas.drawRect(bottomRect, centerLinePaint); 282 | } 283 | 284 | @Override 285 | public void setAlpha(int alpha) { 286 | 287 | } 288 | 289 | @Override 290 | public void setColorFilter(ColorFilter cf) { 291 | 292 | } 293 | 294 | @Override 295 | public int getOpacity() { 296 | return 0; 297 | } 298 | }; 299 | super.setBackground(background); 300 | } 301 | 302 | @Override 303 | public boolean onTouchEvent(MotionEvent event) { 304 | switch (event.getActionMasked()) { 305 | case MotionEvent.ACTION_DOWN: 306 | doDown(event); 307 | break; 308 | case MotionEvent.ACTION_MOVE: 309 | doMove(event); 310 | break; 311 | case MotionEvent.ACTION_UP: 312 | doUp(); 313 | break; 314 | default: 315 | break; 316 | } 317 | return true; 318 | } 319 | 320 | private void doDown(MotionEvent event) { 321 | if (mTask != null) { 322 | mTask.cancel(); 323 | mTask = null; 324 | } 325 | mLastDownY = event.getY(); 326 | } 327 | 328 | private void doMove(MotionEvent event) { 329 | 330 | mMoveLen += (event.getY() - mLastDownY); 331 | 332 | if (mMoveLen > itemHeight / 2) { 333 | // 往下滑超过离开距离 334 | mMoveLen = mMoveLen - itemHeight; 335 | currentItem--; 336 | if (currentItem < 0) { 337 | currentItem = itemCount - 1; 338 | } 339 | } else if (mMoveLen < -itemHeight / 2) { 340 | // 往上滑超过离开距离 341 | mMoveLen = mMoveLen + itemHeight; 342 | currentItem++; 343 | if (currentItem >= itemCount) { 344 | currentItem = 0; 345 | } 346 | } 347 | 348 | mLastDownY = event.getY(); 349 | invalidate(); 350 | } 351 | 352 | private void doUp() { 353 | // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置 354 | if (Math.abs(mMoveLen) < 0.0001) { 355 | mMoveLen = 0; 356 | return; 357 | } 358 | if (mTask != null) { 359 | mTask.cancel(); 360 | mTask = null; 361 | } 362 | if (null == timer) { 363 | timer = new Timer(); 364 | } 365 | mTask = new MyTimerTask(updateHandler); 366 | timer.schedule(mTask, 0, 10); 367 | } 368 | 369 | class MyTimerTask extends TimerTask { 370 | Handler handler; 371 | 372 | public MyTimerTask(Handler handler) { 373 | this.handler = handler; 374 | } 375 | 376 | @Override 377 | public void run() { 378 | handler.sendMessage(handler.obtainMessage()); 379 | } 380 | 381 | } 382 | 383 | private void performSelect() { 384 | if (mSelectListener != null) { 385 | mSelectListener.onSelect(currentItem, itemList.get(currentItem)); 386 | } else { 387 | Log.i(TAG, "null listener"); 388 | } 389 | } 390 | 391 | public interface SelectListener { 392 | void onSelect(int index, String text); 393 | } 394 | 395 | } 396 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 |