Commit 76ce3631 by 罗翻

增加选择框,把时间间隔改为15分钟

parent ae7936c9
Showing with 5569 additions and 21 deletions
...@@ -18,12 +18,12 @@ android { ...@@ -18,12 +18,12 @@ android {
release { release {
minifyEnabled isReleaseMinify minifyEnabled isReleaseMinify
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String","BASEURL","\"${BASE_URL}\"" buildConfigField "String", "BASEURL", "\"${BASE_URL}\""
} }
debug { debug {
minifyEnabled isDebugMinify minifyEnabled isDebugMinify
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String","BASEURL","\"${BASE_URL}\"" buildConfigField "String", "BASEURL", "\"${BASE_URL}\""
} }
} }
...@@ -61,10 +61,11 @@ dependencies { ...@@ -61,10 +61,11 @@ dependencies {
//greendao数据库 //greendao数据库
compile 'org.greenrobot:greendao:3.2.0' compile 'org.greenrobot:greendao:3.2.0'
//选择器 //选择器
compile 'com.contrarywind:Android-PickerView:3.2.7' // compile 'com.contrarywind:Android-PickerView:3.2.7'
//jsbridge //jsbridge
compile 'com.github.lzyzsd:jsbridge:1.0.4' compile 'com.github.lzyzsd:jsbridge:1.0.4'
compile project(':locationComponent') compile project(':locationComponent')
compile project(':pickerview')
} }
package com.dayu.order.presenter.processorder; package com.dayu.order.presenter.processorder;
import com.bigkoo.pickerview.OptionsPickerView; import com.bigkoo.pickerview.listener.OnOptionsSelectListener;
import com.dayu.base.ui.presenter.BasePresenter; import com.dayu.base.ui.presenter.BasePresenter;
import com.dayu.common.BaseView; import com.dayu.common.BaseView;
import com.dayu.widgets.listener.OnCloseListener; import com.dayu.widgets.listener.OnCloseListener;
...@@ -40,7 +40,7 @@ public interface ProcessOrderContract { ...@@ -40,7 +40,7 @@ public interface ProcessOrderContract {
*/ */
void getData(); void getData();
void showPayerDialog(List<String> cardItem, OptionsPickerView.OnOptionsSelectListener listener); void showPayerDialog(List<String> cardItem, OnOptionsSelectListener listener);
/** /**
* 当订单不是ka派单时,不可修改. * 当订单不是ka派单时,不可修改.
......
package com.dayu.order.presenter.returnpart; package com.dayu.order.presenter.returnpart;
import com.bigkoo.pickerview.OptionsPickerView; import com.bigkoo.pickerview.listener.OnOptionsSelectListener;
import com.dayu.base.ui.presenter.BasePresenter; import com.dayu.base.ui.presenter.BasePresenter;
import com.dayu.common.BaseView; import com.dayu.common.BaseView;
...@@ -19,7 +19,7 @@ public interface ReturnPartContract { ...@@ -19,7 +19,7 @@ public interface ReturnPartContract {
* @param cardItem * @param cardItem
* @param listener * @param listener
*/ */
void showCouriesDialog(List<String> cardItem, OptionsPickerView.OnOptionsSelectListener listener); void showCouriesDialog(List<String> cardItem, OnOptionsSelectListener listener);
/** /**
* 关闭输入框. * 关闭输入框.
......
package com.dayu.order.presenter.subcribeTime; package com.dayu.order.presenter.subcribeTime;
import com.bigkoo.pickerview.TimePickerView; import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.dayu.base.ui.presenter.BasePresenter; import com.dayu.base.ui.presenter.BasePresenter;
import com.dayu.common.BaseView; import com.dayu.common.BaseView;
...@@ -15,7 +15,7 @@ public interface SubcribeContract { ...@@ -15,7 +15,7 @@ public interface SubcribeContract {
/** /**
* 选择时间. * 选择时间.
*/ */
void selectTime(boolean[] type, TimePickerView.OnTimeSelectListener listener); void selectTime(boolean[] type, OnTimeSelectListener listener);
} }
abstract class Presenter extends BasePresenter<View> { abstract class Presenter extends BasePresenter<View> {
......
...@@ -9,7 +9,9 @@ import android.widget.ImageView; ...@@ -9,7 +9,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import com.bigkoo.pickerview.OptionsPickerView; import com.bigkoo.pickerview.builder.OptionsPickerBuilder;
import com.bigkoo.pickerview.listener.OnOptionsSelectListener;
import com.bigkoo.pickerview.view.OptionsPickerView;
import com.dayu.base.ui.activity.BaseActivity; import com.dayu.base.ui.activity.BaseActivity;
import com.dayu.common.Constants; import com.dayu.common.Constants;
import com.dayu.order.R; import com.dayu.order.R;
...@@ -198,9 +200,9 @@ public class ProcessOrderActivity extends BaseActivity<ProcessOrderPresenter, Ac ...@@ -198,9 +200,9 @@ public class ProcessOrderActivity extends BaseActivity<ProcessOrderPresenter, Ac
} }
@Override @Override
public void showPayerDialog(List<String> cardItem, OptionsPickerView.OnOptionsSelectListener listener) { public void showPayerDialog(List<String> cardItem, OnOptionsSelectListener listener) {
//条件选择器 //条件选择器
OptionsPickerView pvOptions = new OptionsPickerView.Builder(this, listener) OptionsPickerView pvOptions = new OptionsPickerBuilder(this, listener)
.setContentTextSize(20) .setContentTextSize(20)
.setLineSpacingMultiplier(2.0f) .setLineSpacingMultiplier(2.0f)
.build(); .build();
......
package com.dayu.order.ui.activity; package com.dayu.order.ui.activity;
import com.bigkoo.pickerview.OptionsPickerView; import com.bigkoo.pickerview.builder.OptionsPickerBuilder;
import com.bigkoo.pickerview.listener.OnOptionsSelectListener;
import com.bigkoo.pickerview.view.OptionsPickerView;
import com.dayu.base.ui.activity.BaseActivity; import com.dayu.base.ui.activity.BaseActivity;
import com.dayu.order.R; import com.dayu.order.R;
import com.dayu.order.databinding.ActivityReturnPartBinding; import com.dayu.order.databinding.ActivityReturnPartBinding;
...@@ -31,9 +33,9 @@ public class ReturnPartActivity extends BaseActivity<ReturnPartPresenter, Activi ...@@ -31,9 +33,9 @@ public class ReturnPartActivity extends BaseActivity<ReturnPartPresenter, Activi
} }
@Override @Override
public void showCouriesDialog(List<String> cardItem, OptionsPickerView.OnOptionsSelectListener listener) { public void showCouriesDialog(List<String> cardItem, OnOptionsSelectListener listener) {
//条件选择器 //条件选择器
OptionsPickerView pvOptions = new OptionsPickerView.Builder(this, listener) OptionsPickerView pvOptions = new OptionsPickerBuilder(this, listener)
.setContentTextSize(18) .setContentTextSize(18)
.setLineSpacingMultiplier(2.0f) .setLineSpacingMultiplier(2.0f)
.build(); .build();
......
...@@ -4,7 +4,9 @@ import android.content.Context; ...@@ -4,7 +4,9 @@ import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import com.bigkoo.pickerview.TimePickerView; import com.bigkoo.pickerview.builder.TimePickerBuilder;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.bigkoo.pickerview.view.TimePickerView;
import com.dayu.base.ui.activity.BaseActivity; import com.dayu.base.ui.activity.BaseActivity;
import com.dayu.order.R; import com.dayu.order.R;
import com.dayu.order.databinding.ActivitySubscribeTimeBinding; import com.dayu.order.databinding.ActivitySubscribeTimeBinding;
...@@ -37,20 +39,20 @@ public class SubcribeTimeActivity extends BaseActivity<SubcribeTimePresenter, Ac ...@@ -37,20 +39,20 @@ public class SubcribeTimeActivity extends BaseActivity<SubcribeTimePresenter, Ac
} }
@Override @Override
public void selectTime(boolean[] type, TimePickerView.OnTimeSelectListener listener) { public void selectTime(boolean[] type, OnTimeSelectListener listener) {
try { try {
InputMethodManager imm = (InputMethodManager) mActivity InputMethodManager imm = (InputMethodManager) mActivity
.getSystemService(Context.INPUT_METHOD_SERVICE); .getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0); imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0);
} catch (NullPointerException e) { } catch (NullPointerException e) {
} }
TimePickerView pvTime = new TimePickerView.Builder(mActivity, listener) TimePickerView pvTime = new TimePickerBuilder(mActivity, listener)
.setType(type)//默认全部显示 .setType(type)//默认全部显示
.setCancelText(getString(R.string.cancle))//取消按钮文字 .setCancelText(getString(R.string.cancle))//取消按钮文字
.setSubmitText(getString(R.string.comfirm))//确认按钮文字 .setSubmitText(getString(R.string.comfirm))//确认按钮文字
.setContentSize(20)//滚轮文字大小 .setContentTextSize(20)//滚轮文字大小
.setOutSideCancelable(true)//点击屏幕,点在控件外部范围时,是否取消显示 .setOutSideCancelable(true)//点击屏幕,点在控件外部范围时,是否取消显示
.isCyclic(true)//是否循环滚动 .isCyclic(false)//是否循环滚动
.setTextColorCenter(Color.BLACK)//设置选中项的颜色 .setTextColorCenter(Color.BLACK)//设置选中项的颜色
.setSubmitColor(Color.BLACK)//确定按钮文字颜色 .setSubmitColor(Color.BLACK)//确定按钮文字颜色
.setCancelColor(Color.BLACK)//取消按钮文字颜色 .setCancelColor(Color.BLACK)//取消按钮文字颜色
......
apply plugin: 'com.android.library'
//apply plugin: 'com.github.dcendents.android-maven'
//apply plugin: 'com.novoda.bintray-release'//添加JCenter插件
android {
compileSdkVersion compile_sdk_version
buildToolsVersion build_tools_version
defaultConfig {
minSdkVersion min_sdk_version
targetSdkVersion target_sdk_version
versionCode version_code
}
buildTypes {
release {
minifyEnabled isReleaseMinify
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
allprojects {
tasks.withType(Javadoc) {//兼容中文字符
options{
encoding "UTF-8"
charSet 'UTF-8'
links "http://docs.oracle.com/javase/7/docs/api"
}
}
}
//publish {
// userOrg = 'contrarywind'//bintray.com 用户名/组织名 user/org name
// groupId = 'com.contrarywind'//JCenter上显示的路径 path
// artifactId = 'Android-PickerView'//项目名称 project name
// publishVersion = '4.1.3'//版本号 version code
// desc = 'this is a pickerview for android'//项目描述 description
// website = 'https://github.com/Bigkoo/Android-PickerView' //项目网址链接 link
//}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile project(path: ':wheelview')
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/Sai/Documents/software/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
package com.bigkoo.pickerview;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.bigkoo.pickerview">
</manifest>
package com.bigkoo.pickerview.adapter;
import com.contrarywind.adapter.WheelAdapter;
import java.util.List;
/**
* The simple Array wheel adapter
* @param <T> the element type
*/
public class ArrayWheelAdapter<T> implements WheelAdapter {
// items
private List<T> items;
/**
* Constructor
* @param items the items
*/
public ArrayWheelAdapter(List<T> items) {
this.items = items;
}
@Override
public Object getItem(int index) {
if (index >= 0 && index < items.size()) {
return items.get(index);
}
return "";
}
@Override
public int getItemsCount() {
return items.size();
}
@Override
public int indexOf(Object o){
return items.indexOf(o);
}
}
package com.bigkoo.pickerview.adapter;
import com.contrarywind.adapter.WheelAdapter;
/**
* Numeric Wheel adapter.
*/
public class NumericWheelAdapter implements WheelAdapter {
private int minValue;
private int maxValue;
/**
* Constructor
* @param minValue the wheel min value
* @param maxValue the wheel max value
*/
public NumericWheelAdapter(int minValue, int maxValue) {
this.minValue = minValue;
this.maxValue = maxValue;
}
@Override
public Object getItem(int index) {
if (index >= 0 && index < getItemsCount()) {
int value = minValue + index;
return value;
}
return 0;
}
@Override
public int getItemsCount() {
return maxValue - minValue + 1;
}
@Override
public int indexOf(Object o){
try {
return (int)o - minValue;
} catch (Exception e) {
return -1;
}
}
}
package com.bigkoo.pickerview.builder;
import android.content.Context;
import android.graphics.Typeface;
import android.view.ViewGroup;
import com.bigkoo.pickerview.configure.PickerOptions;
import com.bigkoo.pickerview.listener.CustomListener;
import com.bigkoo.pickerview.listener.OnOptionsSelectChangeListener;
import com.bigkoo.pickerview.listener.OnOptionsSelectListener;
import com.bigkoo.pickerview.view.OptionsPickerView;
import com.contrarywind.view.WheelView;
/**
* Created by xiaosongzeem on 2018/3/20.
*/
public class OptionsPickerBuilder {
//配置类
private PickerOptions mPickerOptions;
//Required
public OptionsPickerBuilder(Context context, OnOptionsSelectListener listener) {
mPickerOptions = new PickerOptions(PickerOptions.TYPE_PICKER_OPTIONS);
mPickerOptions.context = context;
mPickerOptions.optionsSelectListener = listener;
}
//Option
public OptionsPickerBuilder setSubmitText(String textContentConfirm) {
mPickerOptions.textContentConfirm = textContentConfirm;
return this;
}
public OptionsPickerBuilder setCancelText(String textContentCancel) {
mPickerOptions.textContentCancel = textContentCancel;
return this;
}
public OptionsPickerBuilder setTitleText(String textContentTitle) {
mPickerOptions.textContentTitle = textContentTitle;
return this;
}
public OptionsPickerBuilder isDialog(boolean isDialog) {
mPickerOptions.isDialog = isDialog;
return this;
}
public OptionsPickerBuilder setSubmitColor(int textColorConfirm) {
mPickerOptions.textColorConfirm = textColorConfirm;
return this;
}
public OptionsPickerBuilder setCancelColor(int textColorCancel) {
mPickerOptions.textColorCancel = textColorCancel;
return this;
}
/**
* 显示时的外部背景色颜色,默认是灰色
*
* @param backgroundId color resId.
* @return
*/
public OptionsPickerBuilder setBackgroundId(int backgroundId) {
mPickerOptions.backgroundId = backgroundId;
return this;
}
/**
* ViewGroup 类型
* 设置PickerView的显示容器
*
* @param decorView Parent View.
* @return
*/
public OptionsPickerBuilder setDecorView(ViewGroup decorView) {
mPickerOptions.decorView = decorView;
return this;
}
public OptionsPickerBuilder setLayoutRes(int res, CustomListener listener) {
mPickerOptions.layoutRes = res;
mPickerOptions.customListener = listener;
return this;
}
public OptionsPickerBuilder setBgColor(int bgColorWheel) {
mPickerOptions.bgColorWheel = bgColorWheel;
return this;
}
public OptionsPickerBuilder setTitleBgColor(int bgColorTitle) {
mPickerOptions.bgColorTitle = bgColorTitle;
return this;
}
public OptionsPickerBuilder setTitleColor(int textColorTitle) {
mPickerOptions.textColorTitle = textColorTitle;
return this;
}
public OptionsPickerBuilder setSubCalSize(int textSizeSubmitCancel) {
mPickerOptions.textSizeSubmitCancel = textSizeSubmitCancel;
return this;
}
public OptionsPickerBuilder setTitleSize(int textSizeTitle) {
mPickerOptions.textSizeTitle = textSizeTitle;
return this;
}
public OptionsPickerBuilder setContentTextSize(int textSizeContent) {
mPickerOptions.textSizeContent = textSizeContent;
return this;
}
public OptionsPickerBuilder setOutSideCancelable(boolean cancelable) {
mPickerOptions.cancelable = cancelable;
return this;
}
public OptionsPickerBuilder setLabels(String label1, String label2, String label3) {
mPickerOptions.label1 = label1;
mPickerOptions.label2 = label2;
mPickerOptions.label3 = label3;
return this;
}
/**
* 设置Item 的间距倍数,用于控制 Item 高度间隔
*
* @param lineSpacingMultiplier 浮点型,1.0-4.0f 之间有效,超过则取极值。
*/
public OptionsPickerBuilder setLineSpacingMultiplier(float lineSpacingMultiplier) {
mPickerOptions.lineSpacingMultiplier = lineSpacingMultiplier;
return this;
}
/**
* Set item divider line type color.
*
* @param dividerColor color resId.
*/
public OptionsPickerBuilder setDividerColor(int dividerColor) {
mPickerOptions.dividerColor = dividerColor;
return this;
}
/**
* Set item divider line type.
*
* @param dividerType enum Type {@link WheelView.DividerType}
*/
public OptionsPickerBuilder setDividerType(WheelView.DividerType dividerType) {
mPickerOptions.dividerType = dividerType;
return this;
}
/**
* Set the textColor of selected item.
*
* @param textColorCenter color res.
*/
public OptionsPickerBuilder setTextColorCenter(int textColorCenter) {
mPickerOptions.textColorCenter = textColorCenter;
return this;
}
/**
* Set the textColor of outside item.
*
* @param textColorOut color resId.
*/
public OptionsPickerBuilder setTextColorOut(int textColorOut) {
mPickerOptions.textColorOut = textColorOut;
return this;
}
public OptionsPickerBuilder setTypeface(Typeface font) {
mPickerOptions.font = font;
return this;
}
public OptionsPickerBuilder setCyclic(boolean cyclic1, boolean cyclic2, boolean cyclic3) {
mPickerOptions.cyclic1 = cyclic1;
mPickerOptions.cyclic2 = cyclic2;
mPickerOptions.cyclic3 = cyclic3;
return this;
}
public OptionsPickerBuilder setSelectOptions(int option1) {
mPickerOptions.option1 = option1;
return this;
}
public OptionsPickerBuilder setSelectOptions(int option1, int option2) {
mPickerOptions.option1 = option1;
mPickerOptions.option2 = option2;
return this;
}
public OptionsPickerBuilder setSelectOptions(int option1, int option2, int option3) {
mPickerOptions.option1 = option1;
mPickerOptions.option2 = option2;
mPickerOptions.option3 = option3;
return this;
}
public OptionsPickerBuilder setTextXOffset(int xoffset_one, int xoffset_two, int xoffset_three) {
mPickerOptions.x_offset_one = xoffset_one;
mPickerOptions.x_offset_two = xoffset_two;
mPickerOptions.x_offset_three = xoffset_three;
return this;
}
public OptionsPickerBuilder isCenterLabel(boolean isCenterLabel) {
mPickerOptions.isCenterLabel = isCenterLabel;
return this;
}
/**
* 切换选项时,是否还原第一项
*
* @param isRestoreItem true:还原; false: 保持上一个选项
* @return TimePickerBuilder
*/
public OptionsPickerBuilder isRestoreItem(boolean isRestoreItem) {
mPickerOptions.isRestoreItem = isRestoreItem;
return this;
}
/**
* @param listener 切换item项滚动停止时,实时回调监听。
* @return
*/
public OptionsPickerBuilder setOptionsSelectChangeListener(OnOptionsSelectChangeListener listener) {
mPickerOptions.optionsSelectChangeListener = listener;
return this;
}
public <T> OptionsPickerView<T> build() {
return new OptionsPickerView<>(mPickerOptions);
}
}
package com.bigkoo.pickerview.builder;
import android.content.Context;
import android.view.ViewGroup;
import com.bigkoo.pickerview.configure.PickerOptions;
import com.bigkoo.pickerview.listener.OnTimeSelectChangeListener;
import com.bigkoo.pickerview.view.TimePickerView;
import com.bigkoo.pickerview.listener.CustomListener;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.contrarywind.view.WheelView;
import java.util.Calendar;
/**
* Created by xiaosongzeem on 2018/3/20.
*/
public class TimePickerBuilder {
private PickerOptions mPickerOptions;
//Required
public TimePickerBuilder(Context context, OnTimeSelectListener listener) {
mPickerOptions = new PickerOptions(PickerOptions.TYPE_PICKER_TIME);
mPickerOptions.context = context;
mPickerOptions.timeSelectListener = listener;
}
//Option
public TimePickerBuilder setGravity(int gravity) {
mPickerOptions.textGravity = gravity;
return this;
}
/**
* new boolean[]{true, true, true, false, false, false}
* control the "year","month","day","hours","minutes","seconds " display or hide.
* 分别控制“年”“月”“日”“时”“分”“秒”的显示或隐藏。
*
* @param type 布尔型数组,长度需要设置为6。
* @return TimePickerBuilder
*/
public TimePickerBuilder setType(boolean[] type) {
mPickerOptions.type = type;
return this;
}
public TimePickerBuilder setSubmitText(String textContentConfirm) {
mPickerOptions.textContentConfirm = textContentConfirm;
return this;
}
public TimePickerBuilder isDialog(boolean isDialog) {
mPickerOptions.isDialog = isDialog;
return this;
}
public TimePickerBuilder setCancelText(String textContentCancel) {
mPickerOptions.textContentCancel = textContentCancel;
return this;
}
public TimePickerBuilder setTitleText(String textContentTitle) {
mPickerOptions.textContentTitle = textContentTitle;
return this;
}
public TimePickerBuilder setSubmitColor(int textColorConfirm) {
mPickerOptions.textColorConfirm = textColorConfirm;
return this;
}
public TimePickerBuilder setCancelColor(int textColorCancel) {
mPickerOptions.textColorCancel = textColorCancel;
return this;
}
/**
* ViewGroup 类型的容器
*
* @param decorView 选择器会被添加到此容器中
* @return TimePickerBuilder
*/
public TimePickerBuilder setDecorView(ViewGroup decorView) {
mPickerOptions.decorView = decorView;
return this;
}
public TimePickerBuilder setBgColor(int bgColorWheel) {
mPickerOptions.bgColorWheel = bgColorWheel;
return this;
}
public TimePickerBuilder setTitleBgColor(int bgColorTitle) {
mPickerOptions.bgColorTitle = bgColorTitle;
return this;
}
public TimePickerBuilder setTitleColor(int textColorTitle) {
mPickerOptions.textColorTitle = textColorTitle;
return this;
}
public TimePickerBuilder setSubCalSize(int textSizeSubmitCancel) {
mPickerOptions.textSizeSubmitCancel = textSizeSubmitCancel;
return this;
}
public TimePickerBuilder setTitleSize(int textSizeTitle) {
mPickerOptions.textSizeTitle = textSizeTitle;
return this;
}
public TimePickerBuilder setContentTextSize(int textSizeContent) {
mPickerOptions.textSizeContent = textSizeContent;
return this;
}
/**
* 因为系统Calendar的月份是从0-11的,所以如果是调用Calendar的set方法来设置时间,月份的范围也要是从0-11
*
* @param date
* @return TimePickerBuilder
*/
public TimePickerBuilder setDate(Calendar date) {
mPickerOptions.date = date;
return this;
}
public TimePickerBuilder setLayoutRes(int res, CustomListener customListener) {
mPickerOptions.layoutRes = res;
mPickerOptions.customListener = customListener;
return this;
}
/**
* 设置起始时间
* 因为系统Calendar的月份是从0-11的,所以如果是调用Calendar的set方法来设置时间,月份的范围也要是从0-11
*/
public TimePickerBuilder setRangDate(Calendar startDate, Calendar endDate) {
mPickerOptions.startDate = startDate;
mPickerOptions.endDate = endDate;
return this;
}
/**
* 设置间距倍数,但是只能在1.0-4.0f之间
*
* @param lineSpacingMultiplier
*/
public TimePickerBuilder setLineSpacingMultiplier(float lineSpacingMultiplier) {
mPickerOptions.lineSpacingMultiplier = lineSpacingMultiplier;
return this;
}
/**
* 设置分割线的颜色
*
* @param dividerColor
*/
public TimePickerBuilder setDividerColor(int dividerColor) {
mPickerOptions.dividerColor = dividerColor;
return this;
}
/**
* 设置分割线的类型
*
* @param dividerType
*/
public TimePickerBuilder setDividerType(WheelView.DividerType dividerType) {
mPickerOptions.dividerType = dividerType;
return this;
}
/**
* //显示时的外部背景色颜色,默认是灰色
*
* @param backgroundId
*/
public TimePickerBuilder setBackgroundId(int backgroundId) {
mPickerOptions.backgroundId = backgroundId;
return this;
}
/**
* 设置分割线之间的文字的颜色
*
* @param textColorCenter
*/
public TimePickerBuilder setTextColorCenter(int textColorCenter) {
mPickerOptions.textColorCenter = textColorCenter;
return this;
}
/**
* 设置分割线以外文字的颜色
*
* @param textColorOut
*/
public TimePickerBuilder setTextColorOut(int textColorOut) {
mPickerOptions.textColorOut = textColorOut;
return this;
}
public TimePickerBuilder isCyclic(boolean cyclic) {
mPickerOptions.cyclic = cyclic;
return this;
}
public TimePickerBuilder setOutSideCancelable(boolean cancelable) {
mPickerOptions.cancelable = cancelable;
return this;
}
public TimePickerBuilder setLunarCalendar(boolean lunarCalendar) {
mPickerOptions.isLunarCalendar = lunarCalendar;
return this;
}
public TimePickerBuilder setLabel(String label_year, String label_month, String label_day, String label_hours, String label_mins, String label_seconds) {
mPickerOptions.label_year = label_year;
mPickerOptions.label_month = label_month;
mPickerOptions.label_day = label_day;
mPickerOptions.label_hours = label_hours;
mPickerOptions.label_minutes = label_mins;
mPickerOptions.label_seconds = label_seconds;
return this;
}
/**
* 设置X轴倾斜角度[ -90 , 90°]
*
* @param x_offset_year 年
* @param x_offset_month 月
* @param x_offset_day 日
* @param x_offset_hours 时
* @param x_offset_minutes 分
* @param x_offset_seconds 秒
* @return
*/
public TimePickerBuilder setTextXOffset(int x_offset_year, int x_offset_month, int x_offset_day,
int x_offset_hours, int x_offset_minutes, int x_offset_seconds) {
mPickerOptions.x_offset_year = x_offset_year;
mPickerOptions.x_offset_month = x_offset_month;
mPickerOptions.x_offset_day = x_offset_day;
mPickerOptions.x_offset_hours = x_offset_hours;
mPickerOptions.x_offset_minutes = x_offset_minutes;
mPickerOptions.x_offset_seconds = x_offset_seconds;
return this;
}
public TimePickerBuilder isCenterLabel(boolean isCenterLabel) {
mPickerOptions.isCenterLabel = isCenterLabel;
return this;
}
/**
* @param listener 切换item项滚动停止时,实时回调监听。
* @return
*/
public TimePickerBuilder setTimeSelectChangeListener(OnTimeSelectChangeListener listener) {
mPickerOptions.timeSelectChangeListener = listener;
return this;
}
public TimePickerView build() {
return new TimePickerView(mPickerOptions);
}
}
package com.bigkoo.pickerview.configure;
import android.content.Context;
import android.graphics.Typeface;
import android.view.Gravity;
import android.view.ViewGroup;
import com.bigkoo.pickerview.listener.OnOptionsSelectChangeListener;
import com.bigkoo.pickerview.listener.OnOptionsSelectListener;
import com.bigkoo.pickerview.R;
import com.bigkoo.pickerview.listener.CustomListener;
import com.bigkoo.pickerview.listener.OnTimeSelectChangeListener;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.contrarywind.view.WheelView;
import java.util.Calendar;
/**
* 配置类
* Created by xiaosongzeem on 2018/3/8.
*/
public class PickerOptions {
//常量
private static final int PICKER_VIEW_BTN_COLOR_NORMAL = 0xFF057dff;
private static final int PICKER_VIEW_BG_COLOR_TITLE = 0xFFf5f5f5;
private static final int PICKER_VIEW_COLOR_TITLE = 0xFF000000;
private static final int PICKER_VIEW_BG_COLOR_DEFAULT = 0xFFFFFFFF;
public static final int TYPE_PICKER_OPTIONS = 1;
public static final int TYPE_PICKER_TIME = 2;
public OnOptionsSelectListener optionsSelectListener;
public OnTimeSelectListener timeSelectListener;
public OnTimeSelectChangeListener timeSelectChangeListener;
public OnOptionsSelectChangeListener optionsSelectChangeListener;
public CustomListener customListener;
//options picker
public String label1, label2, label3;//单位字符
public int option1, option2, option3;//默认选中项
public int x_offset_one, x_offset_two, x_offset_three;//x轴偏移量
public boolean cyclic1 = false;//是否循环,默认否
public boolean cyclic2 = false;
public boolean cyclic3 = false;
public boolean isRestoreItem = false; //切换时,还原第一项
//time picker
public boolean[] type = new boolean[]{true, true, true, false, false, false};//显示类型,默认显示: 年月日
public Calendar date;//当前选中时间
public Calendar startDate;//开始时间
public Calendar endDate;//终止时间
public int startYear;//开始年份
public int endYear;//结尾年份
public boolean cyclic = false;//是否循环
public boolean isLunarCalendar = false;//是否显示农历
public String label_year, label_month, label_day, label_hours, label_minutes, label_seconds;//单位
public int x_offset_year, x_offset_month, x_offset_day, x_offset_hours, x_offset_minutes, x_offset_seconds;//单位
public PickerOptions(int buildType) {
if (buildType == TYPE_PICKER_OPTIONS) {
layoutRes = R.layout.pickerview_options;
} else {
layoutRes = R.layout.pickerview_time;
}
}
//******* 公有字段 ******//
public int layoutRes;
public ViewGroup decorView;
public int textGravity = Gravity.CENTER;
public Context context;
public String textContentConfirm;//确定按钮文字
public String textContentCancel;//取消按钮文字
public String textContentTitle;//标题文字
public int textColorConfirm = PICKER_VIEW_BTN_COLOR_NORMAL;//确定按钮颜色
public int textColorCancel = PICKER_VIEW_BTN_COLOR_NORMAL;//取消按钮颜色
public int textColorTitle = PICKER_VIEW_COLOR_TITLE;//标题颜色
public int bgColorWheel = PICKER_VIEW_BG_COLOR_DEFAULT;//滚轮背景颜色
public int bgColorTitle = PICKER_VIEW_BG_COLOR_TITLE;//标题背景颜色
public int textSizeSubmitCancel = 17;//确定取消按钮大小
public int textSizeTitle = 18;//标题文字大小
public int textSizeContent = 18;//内容文字大小
public int textColorOut = 0xFFa8a8a8; //分割线以外的文字颜色
public int textColorCenter = 0xFF2a2a2a; //分割线之间的文字颜色
public int dividerColor = 0xFFd5d5d5; //分割线的颜色
public int backgroundId = -1; //显示时的外部背景色颜色,默认是灰色
public float lineSpacingMultiplier = 1.6f; // 条目间距倍数 默认1.6
public boolean isDialog;//是否是对话框模式
public boolean cancelable = true;//是否能取消
public boolean isCenterLabel = false;//是否只显示中间的label,默认每个item都显示
public Typeface font = Typeface.MONOSPACE;//字体样式
public WheelView.DividerType dividerType = WheelView.DividerType.FILL;//分隔线类型
}
package com.bigkoo.pickerview.listener;
import android.view.View;
/**
* Created by KyuYi on 2017/3/2.
* E-Mail:kyu_yi@sina.com
* 功能:
*/
public interface CustomListener {
void customLayout(View v);
}
package com.bigkoo.pickerview.listener;
/**
* Created by zengsong on 2018/3/21.
*/
public interface ISelectTimeCallback {
public void onTimeSelectChanged();
}
package com.bigkoo.pickerview.listener;
/**
* Created by Sai on 15/8/9.
*/
public interface OnDismissListener {
public void onDismiss(Object o);
}
package com.bigkoo.pickerview.listener;
/**
* Created by xiaosong on 2018/3/20.
*/
public interface OnOptionsSelectChangeListener {
void onOptionsSelectChanged(int options1, int options2, int options3);
}
package com.bigkoo.pickerview.listener;
import android.view.View;
/**
* Created by xiaosong on 2018/3/20.
*/
public interface OnOptionsSelectListener {
void onOptionsSelect(int options1, int options2, int options3, View v);
}
package com.bigkoo.pickerview.listener;
import java.util.Date;
/**
* Created by xiaosong on 2018/3/20.
*/
public interface OnTimeSelectChangeListener {
void onTimeSelectChanged(Date date);
}
package com.bigkoo.pickerview.listener;
import android.view.View;
import java.util.Date;
/**
* Created by xiaosong on 2018/3/20.
*/
public interface OnTimeSelectListener {
void onTimeSelect(Date date, View v);
}
package com.bigkoo.pickerview.utils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
public class ChinaDate {
/**
* <lunarInfo 数组值的计算原理>
*
* 0x代表十六进制,后面的五位数是十六进制数。
* 举个例子: 1980年的数据是 0x095b0
* 二进制: 0000 1001 0101 1011 0000
* 1-4: 表示当年有无闰年,有的话,为闰月的月份,没有的话,为0。
* 5-16: 为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。
* 注意: 从1月到12月对应的是第16位到第5位。
* 17-20: 表示闰月是大月还是小月,仅当存在闰月的情况下有意义。
*/
final private static long[] lunarInfo = new long[]{
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,//1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,//1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,//1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,//1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,//1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0,//1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,//1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6,//1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,//1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,//1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,//2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,//2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,//2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,//2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,//2040-2049
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0,//2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4,//2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0,//2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160,//2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252,//2090-2099
0x0d520};//2100
final private static int[] year20 = new int[]{1, 4, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1};
final private static int[] year19 = new int[]{0, 3, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0};
final private static int[] year2000 = new int[]{0, 3, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1};
public final static String[] nStr1 = new String[]{"", "正", "二", "三", "四",
"五", "六", "七", "八", "九", "十", "冬", "腊"};
private final static String[] Gan = new String[]{"甲", "乙", "丙", "丁", "戊",
"己", "庚", "辛", "壬", "癸"};
private final static String[] Zhi = new String[]{"子", "丑", "寅", "卯", "辰",
"巳", "午", "未", "申", "酉", "戌", "亥"};
private final static String[] Animals = new String[]{"鼠", "牛", "虎", "兔",
"龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};
/**
* 传回农历
*
* @param y 年的总天数
* @return 农历
*/
final private static int lYearDays(int y) {
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
if ((lunarInfo[y - 1900] & i) != 0)
sum += 1;
}
return (sum + leapDays(y));
}
/**
* 传回农历
*
* @param y 年闰月的天数
* @return 农历
*/
final public static int leapDays(int y) {
if (leapMonth(y) != 0) {
if ((lunarInfo[y - 1900] & 0x10000) != 0)
return 30;
else
return 29;
} else
return 0;
}
/**
* 传回农历
*
* @param y 年闰哪个月 1-12 , 没闰传回 0
* @return 农历
*/
final public static int leapMonth(int y) {
return (int) (lunarInfo[y - 1900] & 0xf);
}
/**
* 传回农历 y
*
* @param y y年m月的总天数
* @param m y年m月的总天数
* @return 农历
*/
final public static int monthDays(int y, int m) {
if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)
return 29;
else
return 30;
}
/**
* 传回农历
*
* @param y 年的生肖
* @return
*/
final public static String AnimalsYear(int y) {
return Animals[(y - 4) % 12];
}
/**
* 传入
*
* @param num 月日的offset 传回干支,0是甲子
* @return 干支
*/
final private static String cyclicalm(int num) {
return (Gan[num % 10] + Zhi[num % 12]);
}
/**
* 传入 offset 传回干支
*
* @param y 0是甲子
* @return 干支
*/
final public static String cyclical(int y) {
int num = y - 1900 + 36;
return (cyclicalm(num));
}
/**
* 传出农历.year0 .month1 .day2 .yearCyl3 .monCyl4 .dayCyl5 .isLeap6
*
* @param y 年
* @param m 月
* @return 传出农历
*/
final private long[] Lunar(int y, int m) {
long[] nongDate = new long[7];
int i = 0, temp = 0, leap = 0;
Date baseDate = new GregorianCalendar(1900 + 1900, 1, 31).getTime();
Date objDate = new GregorianCalendar(y + 1900, m, 1).getTime();
long offset = (objDate.getTime() - baseDate.getTime()) / 86400000L;
if (y < 2000)
offset += year19[m - 1];
if (y > 2000)
offset += year20[m - 1];
if (y == 2000)
offset += year2000[m - 1];
nongDate[5] = offset + 40;
nongDate[4] = 14;
for (i = 1900; i < 2050 && offset > 0; i++) {
temp = lYearDays(i);
offset -= temp;
nongDate[4] += 12;
}
if (offset < 0) {
offset += temp;
i--;
nongDate[4] -= 12;
}
nongDate[0] = i;
nongDate[3] = i - 1864;
leap = leapMonth(i); // 闰哪个月
nongDate[6] = 0;
for (i = 1; i < 13 && offset > 0; i++) {
// 闰月
if (leap > 0 && i == (leap + 1) && nongDate[6] == 0) {
--i;
nongDate[6] = 1;
temp = leapDays((int) nongDate[0]);
} else {
temp = monthDays((int) nongDate[0], i);
}
// 解除闰月
if (nongDate[6] == 1 && i == (leap + 1))
nongDate[6] = 0;
offset -= temp;
if (nongDate[6] == 0)
nongDate[4]++;
}
if (offset == 0 && leap > 0 && i == leap + 1) {
if (nongDate[6] == 1) {
nongDate[6] = 0;
} else {
nongDate[6] = 1;
--i;
--nongDate[4];
}
}
if (offset < 0) {
offset += temp;
--i;
--nongDate[4];
}
nongDate[1] = i;
nongDate[2] = offset + 1;
return nongDate;
}
/**
* 传出y年m月d日对应的农历.year0 .month1 .day2 .yearCyl3 .monCyl4 .dayCyl5 .isLeap6
*
* @param y 年
* @param m 月
* @param d 日
* @return y年m月d日对应的农历
*/
final public static long[] calElement(int y, int m, int d) {
long[] nongDate = new long[7];
int i = 0, temp = 0, leap = 0;
Date baseDate = new GregorianCalendar(0 + 1900, 0, 31).getTime();
Date objDate = new GregorianCalendar(y, m - 1, d).getTime();
long offset = (objDate.getTime() - baseDate.getTime()) / 86400000L;
nongDate[5] = offset + 40;
nongDate[4] = 14;
for (i = 1900; i < 2050 && offset > 0; i++) {
temp = lYearDays(i);
offset -= temp;
nongDate[4] += 12;
}
if (offset < 0) {
offset += temp;
i--;
nongDate[4] -= 12;
}
nongDate[0] = i;
nongDate[3] = i - 1864;
leap = leapMonth(i); // 闰哪个月
nongDate[6] = 0;
for (i = 1; i < 13 && offset > 0; i++) {
// 闰月
if (leap > 0 && i == (leap + 1) && nongDate[6] == 0) {
--i;
nongDate[6] = 1;
temp = leapDays((int) nongDate[0]);
} else {
temp = monthDays((int) nongDate[0], i);
}
// 解除闰月
if (nongDate[6] == 1 && i == (leap + 1))
nongDate[6] = 0;
offset -= temp;
if (nongDate[6] == 0)
nongDate[4]++;
}
if (offset == 0 && leap > 0 && i == leap + 1) {
if (nongDate[6] == 1) {
nongDate[6] = 0;
} else {
nongDate[6] = 1;
--i;
--nongDate[4];
}
}
if (offset < 0) {
offset += temp;
--i;
--nongDate[4];
}
nongDate[1] = i;
nongDate[2] = offset + 1;
return nongDate;
}
public final static String getChinaDate(int day) {
String a = "";
if (day == 10)
return "初十";
if (day == 20)
return "二十";
if (day == 30)
return "三十";
int two = (int) ((day) / 10);
if (two == 0)
a = "初";
if (two == 1)
a = "十";
if (two == 2)
a = "廿";
if (two == 3)
a = "三";
int one = (int) (day % 10);
switch (one) {
case 1:
a += "一";
break;
case 2:
a += "二";
break;
case 3:
a += "三";
break;
case 4:
a += "四";
break;
case 5:
a += "五";
break;
case 6:
a += "六";
break;
case 7:
a += "七";
break;
case 8:
a += "八";
break;
case 9:
a += "九";
break;
}
return a;
}
public static String today() {
Calendar today = Calendar.getInstance(Locale.SIMPLIFIED_CHINESE);
int year = today.get(Calendar.YEAR);
int month = today.get(Calendar.MONTH) + 1;
int date = today.get(Calendar.DATE);
long[] l = calElement(year, month, date);
StringBuffer sToday = new StringBuffer();
try {
sToday.append(sdf.format(today.getTime()));
sToday.append(" 农历");
sToday.append(cyclical(year));
sToday.append('(');
sToday.append(AnimalsYear(year));
sToday.append(")年");
sToday.append(nStr1[(int) l[1]]);
sToday.append("月");
sToday.append(getChinaDate((int) (l[2])));
return sToday.toString();
} finally {
sToday = null;
}
}
public static String oneDay(int year, int month, int day) {
// Calendar today = Calendar.getInstance(Locale.SIMPLIFIED_CHINESE);
long[] l = calElement(year, month, day);
StringBuffer sToday = new StringBuffer();
try {
// sToday.append(sdf.format(today.getTime()));
sToday.append(" 农历");
sToday.append(cyclical(year));
sToday.append('(');
sToday.append(AnimalsYear(year));
sToday.append(")年");
sToday.append(nStr1[(int) l[1]]);
sToday.append("月");
sToday.append(getChinaDate((int) (l[2])));
return sToday.toString();
} finally {
sToday = null;
}
}
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 EEEEE");
/**
* @param lunarYear 农历年份
* @return String of Ganzhi: 甲子年
* 甲乙丙丁戊己庚辛壬癸
* 子丑寅卯辰巳无为申酉戌亥
*/
public static String getLunarYearText(int lunarYear) {
return Gan[(lunarYear - 4) % 10] + Zhi[(lunarYear - 4) % 12] + "年";
}
public static ArrayList<String> getYears(int startYear, int endYear) {
ArrayList<String> years = new ArrayList<>();
for (int i = startYear; i < endYear; i++) {
years.add(String.format("%s(%d)", getLunarYearText(i), i));
}
return years;
}
/**
* 获取year年的所有月份
*
* @param year 年
* @return 月份列表
*/
public static ArrayList<String> getMonths(int year) {
ArrayList<String> baseMonths = new ArrayList<>();
for (int i = 1; i < nStr1.length; i++) {
baseMonths.add(nStr1[i] + "月");
}
if (leapMonth(year) != 0) {
baseMonths.add(leapMonth(year), "闰" + nStr1[leapMonth(year)] + "月");
}
return baseMonths;
}
/**
* 获取每月农历显示名称
*
* @param maxDay 天
* @return 名称列表
*/
public static ArrayList<String> getLunarDays(int maxDay) {
ArrayList<String> days = new ArrayList<>();
for (int i = 1; i <= maxDay; i++) {
days.add(getChinaDate(i));
}
return days;
}
}
\ No newline at end of file
package com.bigkoo.pickerview.utils;
import android.util.Log;
import java.util.Date;
import java.util.GregorianCalendar;
/**
* author: Jerry on 2016/7/11 11:29.
* description:工具类,实现公农历互转
*/
public class LunarCalendar {
/**
* 支持转换的最小农历年份
*/
public static final int MIN_YEAR = 1900;
/**
* 支持转换的最大农历年份
*/
public static final int MAX_YEAR = 2099;
/**
* 公历每月前的天数
*/
private static final int DAYS_BEFORE_MONTH[] = {0, 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334, 365};
/**
* 用来表示1900年到2099年间农历年份的相关信息,共24位bit的16进制表示,其中:
* 1. 前4位表示该年闰哪个月;
* 2. 5-17位表示农历年份13个月的大小月分布,0表示小,1表示大;
* 3. 最后7位表示农历年首(正月初一)对应的公历日期。
* <p>
* 以2014年的数据0x955ABF为例说明:
* 1001 0101 0101 1010 1011 1111
* 闰九月 农历正月初一对应公历1月31号
*/
private static final int LUNAR_INFO[] = {
0x84B6BF,/*1900*/
0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6, 0x04AE4A,/*1901-1910*/
0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1, 0x049754,/*1911-1920*/
0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A, 0x664B3E,/*1921-1930*/
0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553, 0x0D4A48,/*1931-1940*/
0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD, 0x06CA51,/*1941-1950*/
0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48, 0x6AD53C,/*1951-1960*/
0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51, 0x096D46,/*1961-1970*/
0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C, 0x095B50,/*1971-1980*/
0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x095746, 0x5497BB,/*1981-1990*/
0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50, 0x0C9645,/*1991-2000*/
0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, 0x0A954E,/*2001-2010*/
0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, 0x474AB9,/*2011-2020*/
0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x6a573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, 0x05AA43,/*2021-2030*/
0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, 0x0B5A4C,/*2031-2040*/
0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, 0x355B37,/*2041-2050*/
0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06AA44, 0x4AB638, 0x0AAE4C, 0x092E42,/*2051-2060*/
0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, 0x052D4B,/*2061-2070*/
0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, 0x3A93B6,/*2071-2080*/
0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, 0x8E933E,/*2081-2090*/
0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5 /*2091-2099*/
};
private static int[] solar_1_1 = {1887, 0xec04c, 0xec23f, 0xec435, 0xec649,
0xec83e, 0xeca51, 0xecc46, 0xece3a, 0xed04d, 0xed242, 0xed436,
0xed64a, 0xed83f, 0xeda53, 0xedc48, 0xede3d, 0xee050, 0xee244,
0xee439, 0xee64d, 0xee842, 0xeea36, 0xeec4a, 0xeee3e, 0xef052,
0xef246, 0xef43a, 0xef64e, 0xef843, 0xefa37, 0xefc4b, 0xefe41,
0xf0054, 0xf0248, 0xf043c, 0xf0650, 0xf0845, 0xf0a38, 0xf0c4d,
0xf0e42, 0xf1037, 0xf124a, 0xf143e, 0xf1651, 0xf1846, 0xf1a3a,
0xf1c4e, 0xf1e44, 0xf2038, 0xf224b, 0xf243f, 0xf2653, 0xf2848,
0xf2a3b, 0xf2c4f, 0xf2e45, 0xf3039, 0xf324d, 0xf3442, 0xf3636,
0xf384a, 0xf3a3d, 0xf3c51, 0xf3e46, 0xf403b, 0xf424e, 0xf4443,
0xf4638, 0xf484c, 0xf4a3f, 0xf4c52, 0xf4e48, 0xf503c, 0xf524f,
0xf5445, 0xf5639, 0xf584d, 0xf5a42, 0xf5c35, 0xf5e49, 0xf603e,
0xf6251, 0xf6446, 0xf663b, 0xf684f, 0xf6a43, 0xf6c37, 0xf6e4b,
0xf703f, 0xf7252, 0xf7447, 0xf763c, 0xf7850, 0xf7a45, 0xf7c39,
0xf7e4d, 0xf8042, 0xf8254, 0xf8449, 0xf863d, 0xf8851, 0xf8a46,
0xf8c3b, 0xf8e4f, 0xf9044, 0xf9237, 0xf944a, 0xf963f, 0xf9853,
0xf9a47, 0xf9c3c, 0xf9e50, 0xfa045, 0xfa238, 0xfa44c, 0xfa641,
0xfa836, 0xfaa49, 0xfac3d, 0xfae52, 0xfb047, 0xfb23a, 0xfb44e,
0xfb643, 0xfb837, 0xfba4a, 0xfbc3f, 0xfbe53, 0xfc048, 0xfc23c,
0xfc450, 0xfc645, 0xfc839, 0xfca4c, 0xfcc41, 0xfce36, 0xfd04a,
0xfd23d, 0xfd451, 0xfd646, 0xfd83a, 0xfda4d, 0xfdc43, 0xfde37,
0xfe04b, 0xfe23f, 0xfe453, 0xfe648, 0xfe83c, 0xfea4f, 0xfec44,
0xfee38, 0xff04c, 0xff241, 0xff436, 0xff64a, 0xff83e, 0xffa51,
0xffc46, 0xffe3a, 0x10004e, 0x100242, 0x100437, 0x10064b, 0x100841,
0x100a53, 0x100c48, 0x100e3c, 0x10104f, 0x101244, 0x101438,
0x10164c, 0x101842, 0x101a35, 0x101c49, 0x101e3d, 0x102051,
0x102245, 0x10243a, 0x10264e, 0x102843, 0x102a37, 0x102c4b,
0x102e3f, 0x103053, 0x103247, 0x10343b, 0x10364f, 0x103845,
0x103a38, 0x103c4c, 0x103e42, 0x104036, 0x104249, 0x10443d,
0x104651, 0x104846, 0x104a3a, 0x104c4e, 0x104e43, 0x105038,
0x10524a, 0x10543e, 0x105652, 0x105847, 0x105a3b, 0x105c4f,
0x105e45, 0x106039, 0x10624c, 0x106441, 0x106635, 0x106849,
0x106a3d, 0x106c51, 0x106e47, 0x10703c, 0x10724f, 0x107444,
0x107638, 0x10784c, 0x107a3f, 0x107c53, 0x107e48};
private static int[] lunar_month_days = {1887, 0x1694, 0x16aa, 0x4ad5,
0xab6, 0xc4b7, 0x4ae, 0xa56, 0xb52a, 0x1d2a, 0xd54, 0x75aa, 0x156a,
0x1096d, 0x95c, 0x14ae, 0xaa4d, 0x1a4c, 0x1b2a, 0x8d55, 0xad4,
0x135a, 0x495d, 0x95c, 0xd49b, 0x149a, 0x1a4a, 0xbaa5, 0x16a8,
0x1ad4, 0x52da, 0x12b6, 0xe937, 0x92e, 0x1496, 0xb64b, 0xd4a,
0xda8, 0x95b5, 0x56c, 0x12ae, 0x492f, 0x92e, 0xcc96, 0x1a94,
0x1d4a, 0xada9, 0xb5a, 0x56c, 0x726e, 0x125c, 0xf92d, 0x192a,
0x1a94, 0xdb4a, 0x16aa, 0xad4, 0x955b, 0x4ba, 0x125a, 0x592b,
0x152a, 0xf695, 0xd94, 0x16aa, 0xaab5, 0x9b4, 0x14b6, 0x6a57,
0xa56, 0x1152a, 0x1d2a, 0xd54, 0xd5aa, 0x156a, 0x96c, 0x94ae,
0x14ae, 0xa4c, 0x7d26, 0x1b2a, 0xeb55, 0xad4, 0x12da, 0xa95d,
0x95a, 0x149a, 0x9a4d, 0x1a4a, 0x11aa5, 0x16a8, 0x16d4, 0xd2da,
0x12b6, 0x936, 0x9497, 0x1496, 0x1564b, 0xd4a, 0xda8, 0xd5b4,
0x156c, 0x12ae, 0xa92f, 0x92e, 0xc96, 0x6d4a, 0x1d4a, 0x10d65,
0xb58, 0x156c, 0xb26d, 0x125c, 0x192c, 0x9a95, 0x1a94, 0x1b4a,
0x4b55, 0xad4, 0xf55b, 0x4ba, 0x125a, 0xb92b, 0x152a, 0x1694,
0x96aa, 0x15aa, 0x12ab5, 0x974, 0x14b6, 0xca57, 0xa56, 0x1526,
0x8e95, 0xd54, 0x15aa, 0x49b5, 0x96c, 0xd4ae, 0x149c, 0x1a4c,
0xbd26, 0x1aa6, 0xb54, 0x6d6a, 0x12da, 0x1695d, 0x95a, 0x149a,
0xda4b, 0x1a4a, 0x1aa4, 0xbb54, 0x16b4, 0xada, 0x495b, 0x936,
0xf497, 0x1496, 0x154a, 0xb6a5, 0xda4, 0x15b4, 0x6ab6, 0x126e,
0x1092f, 0x92e, 0xc96, 0xcd4a, 0x1d4a, 0xd64, 0x956c, 0x155c,
0x125c, 0x792e, 0x192c, 0xfa95, 0x1a94, 0x1b4a, 0xab55, 0xad4,
0x14da, 0x8a5d, 0xa5a, 0x1152b, 0x152a, 0x1694, 0xd6aa, 0x15aa,
0xab4, 0x94ba, 0x14b6, 0xa56, 0x7527, 0xd26, 0xee53, 0xd54, 0x15aa,
0xa9b5, 0x96c, 0x14ae, 0x8a4e, 0x1a4c, 0x11d26, 0x1aa4, 0x1b54,
0xcd6a, 0xada, 0x95c, 0x949d, 0x149a, 0x1a2a, 0x5b25, 0x1aa4,
0xfb52, 0x16b4, 0xaba, 0xa95b, 0x936, 0x1496, 0x9a4b, 0x154a,
0x136a5, 0xda4, 0x15ac};
/**
* 将农历日期转换为公历日期
*
* @param year 农历年份
* @param month 农历月
* @param monthDay 农历日
* @param isLeapMonth 该月是否是闰月
* @return 返回农历日期对应的公历日期,year0, month1, day2.
*/
public static final int[] lunarToSolar(int year, int month, int monthDay,
boolean isLeapMonth) {
int dayOffset;
int leapMonth;
int i;
if (year < MIN_YEAR || year > MAX_YEAR || month < 1 || month > 12
|| monthDay < 1 || monthDay > 30) {
throw new IllegalArgumentException(
"Illegal lunar date, must be like that:\n\t" +
"year : 1900~2099\n\t" +
"month : 1~12\n\t" +
"day : 1~30");
}
dayOffset = (LUNAR_INFO[year - MIN_YEAR] & 0x001F) - 1;
if (((LUNAR_INFO[year - MIN_YEAR] & 0x0060) >> 5) == 2)
dayOffset += 31;
for (i = 1; i < month; i++) {
if ((LUNAR_INFO[year - MIN_YEAR] & (0x80000 >> (i - 1))) == 0)
dayOffset += 29;
else
dayOffset += 30;
}
dayOffset += monthDay;
leapMonth = (LUNAR_INFO[year - MIN_YEAR] & 0xf00000) >> 20;
// 这一年有闰月
if (leapMonth != 0) {
if (month > leapMonth || (month == leapMonth && isLeapMonth)) {
if ((LUNAR_INFO[year - MIN_YEAR] & (0x80000 >> (month - 1))) == 0)
dayOffset += 29;
else
dayOffset += 30;
}
}
if (dayOffset > 366 || (year % 4 != 0 && dayOffset > 365)) {
year += 1;
if (year % 4 == 1)
dayOffset -= 366;
else
dayOffset -= 365;
}
int[] solarInfo = new int[3];
for (i = 1; i < 13; i++) {
int iPos = DAYS_BEFORE_MONTH[i];
if (year % 4 == 0 && i > 2) {
iPos += 1;
}
if (year % 4 == 0 && i == 2 && iPos + 1 == dayOffset) {
solarInfo[1] = i;
solarInfo[2] = dayOffset - 31;
break;
}
if (iPos >= dayOffset) {
solarInfo[1] = i;
iPos = DAYS_BEFORE_MONTH[i - 1];
if (year % 4 == 0 && i > 2) {
iPos += 1;
}
if (dayOffset > iPos)
solarInfo[2] = dayOffset - iPos;
else if (dayOffset == iPos) {
if (year % 4 == 0 && i == 2)
solarInfo[2] = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1] + 1;
else
solarInfo[2] = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1];
} else
solarInfo[2] = dayOffset;
break;
}
}
solarInfo[0] = year;
return solarInfo;
}
public static final int[] solarToLunar(int year, int month, int monthDay) {
int[] lunarDate = new int[4];
int index = year - solar_1_1[0];
int data = (year << 9) | (month << 5)
| (monthDay);
int solar11 = 0;
if (solar_1_1[index] > data) {
index--;
}
solar11 = solar_1_1[index];
int y = getBitInt(solar11, 12, 9);
int m = getBitInt(solar11, 4, 5);
int d = getBitInt(solar11, 5, 0);
long offset = solarToInt(year, month,
monthDay) - solarToInt(y, m, d);
int days = lunar_month_days[index];
int leap = getBitInt(days, 4, 13);
int lunarY = index + solar_1_1[0];
int lunarM = 1;
int lunarD = 1;
offset += 1;
for (int i = 0; i < 13; i++) {
int dm = getBitInt(days, 1, 12 - i) == 1 ? 30 : 29;
if (offset > dm) {
lunarM++;
offset -= dm;
} else {
break;
}
}
lunarD = (int) (offset);
lunarDate[0] = lunarY;
lunarDate[1] = lunarM;
boolean isLeap = false;
if (leap != 0 && lunarM > leap) {
lunarDate[1] = lunarM - 1;
if (lunarM == leap + 1) {
isLeap = true;
}
}
lunarDate[2] = lunarD;
lunarDate[3] = isLeap ? 1 : 0;
//Log.i("----------->",year+"-"+month+"-"+monthDay+"====>"+lunarDate[0]+"-"+lunarDate[1]+"-"+lunarDate[2]+"-"+lunarDate[3]);
return lunarDate;
}
/**
* 将公历日期转换为农历日期,且标识是否是闰月
*
* @param year
* @param month
* @param monthDay
* @return 返回公历日期对应的农历日期,year0,month1,day2,leap3
* @deprecated 不准确
*/
@Deprecated
public static final int[] solarToLunarDeprecated(int year, int month, int monthDay) {
int[] lunarDate = new int[4];
Date baseDate = new GregorianCalendar(1900, 0, 31).getTime();
Date objDate = new GregorianCalendar(year, month - 1, monthDay).getTime();
int offset = (int) ((objDate.getTime() - baseDate.getTime()) / 86400000L);
// 用offset减去每农历年的天数计算当天是农历第几天
// iYear最终结果是农历的年份, offset是当年的第几天
int iYear, daysOfYear = 0;
for (iYear = MIN_YEAR; iYear <= MAX_YEAR && offset > 0; iYear++) {
daysOfYear = daysInLunarYear(iYear);
offset -= daysOfYear;
}
if (offset < 0) {
offset += daysOfYear;
iYear--;
}
// 农历年份
lunarDate[0] = iYear;
int leapMonth = leapMonth(iYear); // 闰哪个月,1-12
boolean isLeap = false;
// 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
int iMonth, daysOfMonth = 0;
for (iMonth = 1; iMonth <= 13 && offset > 0; iMonth++) {
daysOfMonth = daysInLunarMonth(iYear, iMonth);
offset -= daysOfMonth;
}
// 当前月超过闰月,要校正
if (leapMonth != 0 && iMonth > leapMonth) {
--iMonth;
Log.i("----------->", year + "-" + month + "-" + monthDay + "====>" + iMonth + "-" + leapMonth);
if (iMonth == leapMonth) {
isLeap = true;
}
}
// offset小于0时,也要校正
if (offset < 0) {
offset += daysOfMonth;
--iMonth;
}
lunarDate[1] = iMonth;
lunarDate[2] = offset + 1;
lunarDate[3] = isLeap ? 1 : 0;
//Log.i("----------->",year+"-"+month+"-"+monthDay+"====>"+lunarDate[0]+"-"+lunarDate[1]+"-"+lunarDate[2]+"-"+lunarDate[3]);
return lunarDate;
}
/**
* 传回农历year年month月的总天数
*
* @param year 要计算的年份
* @param month 要计算的月
* @return 传回天数
*/
final public static int daysInMonth(int year, int month) {
return daysInMonth(year, month, false);
}
/**
* 传回农历year年month月的总天数
*
* @param year 要计算的年份
* @param month 要计算的月
* @param leap 当月是否是闰月
* @return 传回天数,如果闰月是错误的,返回0.
*/
public static final int daysInMonth(int year, int month, boolean leap) {
int leapMonth = leapMonth(year);
int offset = 0;
// 如果本年有闰月且month大于闰月时,需要校正
if (leapMonth != 0 && month > leapMonth) {
offset = 1;
}
// 不考虑闰月
if (!leap) {
return daysInLunarMonth(year, month + offset);
} else {
// 传入的闰月是正确的月份
if (leapMonth != 0 && leapMonth == month) {
return daysInLunarMonth(year, month + 1);
}
}
return 0;
}
/**
* 传回农历 year年的总天数
*
* @param year 将要计算的年份
* @return 返回传入年份的总天数
*/
private static int daysInLunarYear(int year) {
int i, sum = 348;
if (leapMonth(year) != 0) {
sum = 377;
}
int monthInfo = LUNAR_INFO[year - MIN_YEAR] & 0x0FFF80;
for (i = 0x80000; i > 0x7; i >>= 1) {
if ((monthInfo & i) != 0)
sum += 1;
}
return sum;
}
/**
* 传回农历 year年month月的总天数,总共有13个月包括闰月
*
* @param year 将要计算的年份
* @param month 将要计算的月份
* @return 传回农历 year年month月的总天数
*/
private static int daysInLunarMonth(int year, int month) {
if ((LUNAR_INFO[year - MIN_YEAR] & (0x100000 >> month)) == 0)
return 29;
else
return 30;
}
/**
* 传回农历 year年闰哪个月 1-12 , 没闰传回 0
*
* @param year 将要计算的年份
* @return 传回农历 year年闰哪个月1-12, 没闰传回 0
*/
public static int leapMonth(int year) {
return (int) ((LUNAR_INFO[year - MIN_YEAR] & 0xF00000)) >> 20;
}
private static int getBitInt(int data, int length, int shift) {
return (data & (((1 << length) - 1) << shift)) >> shift;
}
private static long solarToInt(int y, int m, int d) {
m = (m + 9) % 12;
y = y - m / 10;
return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10
+ (d - 1);
}
}
package com.bigkoo.pickerview.utils;
import android.view.Gravity;
import com.bigkoo.pickerview.R;
/**
* Created by Sai on 15/8/9.
*/
public class PickerViewAnimateUtil {
private static final int INVALID = -1;
/**
* Get default animation resource when not defined by the user
*
* @param gravity the animGravity of the dialog
* @param isInAnimation determine if is in or out animation. true when is is
* @return the id of the animation resource
*/
public static int getAnimationResource(int gravity, boolean isInAnimation) {
switch (gravity) {
case Gravity.BOTTOM:
return isInAnimation ? R.anim.pickerview_slide_in_bottom : R.anim.pickerview_slide_out_bottom;
}
return INVALID;
}
}
package com.bigkoo.pickerview.view;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.bigkoo.pickerview.R;
import com.bigkoo.pickerview.configure.PickerOptions;
import com.bigkoo.pickerview.listener.OnDismissListener;
import com.bigkoo.pickerview.utils.PickerViewAnimateUtil;
/**
* Created by Sai on 15/11/22.
* 精仿iOSPickerViewController控件
*/
public class BasePickerView {
private Context context;
protected ViewGroup contentContainer;
private ViewGroup rootView;//附加View 的 根View
private ViewGroup dialogView;//附加Dialog 的 根View
protected PickerOptions mPickerOptions;
private OnDismissListener onDismissListener;
private boolean dismissing;
private Animation outAnim;
private Animation inAnim;
private boolean isShowing;
protected int animGravity = Gravity.BOTTOM;
private Dialog mDialog;
protected View clickView;//是通过哪个View弹出的
private boolean isAnim = true;
public BasePickerView(Context context) {
this.context = context;
}
protected void initViews() {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM);
LayoutInflater layoutInflater = LayoutInflater.from(context);
if (isDialog()) {
//如果是对话框模式
dialogView = (ViewGroup) layoutInflater.inflate(R.layout.layout_basepickerview, null, false);
//设置界面的背景为透明
dialogView.setBackgroundColor(Color.TRANSPARENT);
//这个是真正要加载选择器的父布局
contentContainer = (ViewGroup) dialogView.findViewById(R.id.content_container);
//设置对话框 默认左右间距屏幕30
params.leftMargin = 30;
params.rightMargin = 30;
contentContainer.setLayoutParams(params);
//创建对话框
createDialog();
//给背景设置点击事件,这样当点击内容以外的地方会关闭界面
dialogView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
} else {
//如果只是要显示在屏幕的下方
//decorView是activity的根View,包含 contentView 和 titleView
if (mPickerOptions.decorView == null) {
mPickerOptions.decorView = (ViewGroup) ((Activity) context).getWindow().getDecorView();
}
//将控件添加到decorView中
rootView = (ViewGroup) layoutInflater.inflate(R.layout.layout_basepickerview, mPickerOptions.decorView, false);
rootView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if (mPickerOptions.backgroundId != -1) {
rootView.setBackgroundColor(mPickerOptions.backgroundId);
}
//这个是真正要加载时间选取器的父布局
contentContainer = (ViewGroup) rootView.findViewById(R.id.content_container);
contentContainer.setLayoutParams(params);
}
setKeyBackCancelable(true);
}
protected void initAnim() {
inAnim = getInAnimation();
outAnim = getOutAnimation();
}
protected void initEvents() {
}
/**
* @param v (是通过哪个View弹出的)
* @param isAnim 是否显示动画效果
*/
public void show(View v, boolean isAnim) {
this.clickView = v;
this.isAnim = isAnim;
show();
}
public void show(boolean isAnim) {
this.isAnim = isAnim;
show();
}
public void show(View v) {
this.clickView = v;
show();
}
/**
* 添加View到根视图
*/
public void show() {
if (isDialog()) {
showDialog();
} else {
if (isShowing()) {
return;
}
isShowing = true;
onAttached(rootView);
rootView.requestFocus();
}
}
/**
* show的时候调用
*
* @param view 这个View
*/
private void onAttached(View view) {
mPickerOptions.decorView.addView(view);
if (isAnim) {
contentContainer.startAnimation(inAnim);
}
}
/**
* 检测该View是不是已经添加到根视图
*
* @return 如果视图已经存在该View返回true
*/
public boolean isShowing() {
if (isDialog()) {
return false;
} else {
return rootView.getParent() != null || isShowing;
}
}
public void dismiss() {
if (isDialog()) {
dismissDialog();
} else {
if (dismissing) {
return;
}
if (isAnim) {
//消失动画
outAnim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
dismissImmediately();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
contentContainer.startAnimation(outAnim);
} else {
dismissImmediately();
}
dismissing = true;
}
}
public void dismissImmediately() {
mPickerOptions.decorView.post(new Runnable() {
@Override
public void run() {
//从根视图移除
mPickerOptions.decorView.removeView(rootView);
isShowing = false;
dismissing = false;
if (onDismissListener != null) {
onDismissListener.onDismiss(BasePickerView.this);
}
}
});
}
private Animation getInAnimation() {
int res = PickerViewAnimateUtil.getAnimationResource(this.animGravity, true);
return AnimationUtils.loadAnimation(context, res);
}
private Animation getOutAnimation() {
int res = PickerViewAnimateUtil.getAnimationResource(this.animGravity, false);
return AnimationUtils.loadAnimation(context, res);
}
public BasePickerView setOnDismissListener(OnDismissListener onDismissListener) {
this.onDismissListener = onDismissListener;
return this;
}
public void setKeyBackCancelable(boolean isCancelable) {
ViewGroup View;
if (isDialog()) {
View = dialogView;
} else {
View = rootView;
}
View.setFocusable(isCancelable);
View.setFocusableInTouchMode(isCancelable);
if (isCancelable) {
View.setOnKeyListener(onKeyBackListener);
} else {
View.setOnKeyListener(null);
}
}
private View.OnKeyListener onKeyBackListener = new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == MotionEvent.ACTION_DOWN && isShowing()) {
dismiss();
return true;
}
return false;
}
};
protected BasePickerView setOutSideCancelable(boolean isCancelable) {
if (rootView != null) {
View view = rootView.findViewById(R.id.outmost_container);
if (isCancelable) {
view.setOnTouchListener(onCancelableTouchListener);
} else {
view.setOnTouchListener(null);
}
}
return this;
}
/**
* 设置对话框模式是否可以点击外部取消
*/
public void setDialogOutSideCancelable() {
if (mDialog != null) {
mDialog.setCancelable(mPickerOptions.cancelable);
}
}
/**
* Called when the user touch on black overlay, in order to dismiss the dialog.
*/
private final View.OnTouchListener onCancelableTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
dismiss();
}
return false;
}
};
public View findViewById(int id) {
return contentContainer.findViewById(id);
}
public void createDialog() {
if (dialogView != null) {
mDialog = new Dialog(context, R.style.custom_dialog2);
mDialog.setCancelable(mPickerOptions.cancelable);//不能点外面取消,也不能点back取消
mDialog.setContentView(dialogView);
Window dialogWindow = mDialog.getWindow();
if (dialogWindow != null) {
dialogWindow.setWindowAnimations(R.style.picker_view_scale_anim);
dialogWindow.setGravity(Gravity.CENTER);//可以改成Bottom
}
mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (onDismissListener != null) {
onDismissListener.onDismiss(BasePickerView.this);
}
}
});
}
}
private void showDialog() {
if (mDialog != null) {
mDialog.show();
}
}
private void dismissDialog() {
if (mDialog != null) {
mDialog.dismiss();
}
}
public ViewGroup getDialogContainerLayout() {
return contentContainer;
}
public Dialog getDialog() {
return mDialog;
}
public boolean isDialog() {
return false;
}
}
package com.bigkoo.pickerview.view;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bigkoo.pickerview.R;
import com.bigkoo.pickerview.configure.PickerOptions;
import java.util.List;
/**
* 条件选择器
* Created by Sai on 15/11/22.
*/
public class OptionsPickerView<T> extends BasePickerView implements View.OnClickListener {
private WheelOptions wheelOptions;
private static final String TAG_SUBMIT = "submit";
private static final String TAG_CANCEL = "cancel";
public OptionsPickerView(PickerOptions pickerOptions) {
super(pickerOptions.context);
mPickerOptions = pickerOptions;
initView(pickerOptions.context);
}
private void initView(Context context) {
setDialogOutSideCancelable();
initViews();
initAnim();
initEvents();
if (mPickerOptions.customListener == null) {
LayoutInflater.from(context).inflate(mPickerOptions.layoutRes, contentContainer);
//顶部标题
TextView tvTitle = (TextView) findViewById(R.id.tvTitle);
RelativeLayout rv_top_bar = (RelativeLayout) findViewById(R.id.rv_topbar);
//确定和取消按钮
Button btnSubmit = (Button) findViewById(R.id.btnSubmit);
Button btnCancel = (Button) findViewById(R.id.btnCancel);
btnSubmit.setTag(TAG_SUBMIT);
btnCancel.setTag(TAG_CANCEL);
btnSubmit.setOnClickListener(this);
btnCancel.setOnClickListener(this);
//设置文字
btnSubmit.setText(TextUtils.isEmpty(mPickerOptions.textContentConfirm) ? context.getResources().getString(R.string.pickerview_submit) : mPickerOptions.textContentConfirm);
btnCancel.setText(TextUtils.isEmpty(mPickerOptions.textContentCancel) ? context.getResources().getString(R.string.pickerview_cancel) : mPickerOptions.textContentCancel);
tvTitle.setText(TextUtils.isEmpty(mPickerOptions.textContentTitle) ? "" : mPickerOptions.textContentTitle);//默认为空
//设置color
btnSubmit.setTextColor(mPickerOptions.textColorConfirm);
btnCancel.setTextColor(mPickerOptions.textColorCancel);
tvTitle.setTextColor(mPickerOptions.textColorTitle);
rv_top_bar.setBackgroundColor(mPickerOptions.bgColorTitle);
//设置文字大小
btnSubmit.setTextSize(mPickerOptions.textSizeSubmitCancel);
btnCancel.setTextSize(mPickerOptions.textSizeSubmitCancel);
tvTitle.setTextSize(mPickerOptions.textSizeTitle);
} else {
mPickerOptions.customListener.customLayout(LayoutInflater.from(context).inflate(mPickerOptions.layoutRes, contentContainer));
}
// ----滚轮布局
final LinearLayout optionsPicker = (LinearLayout) findViewById(R.id.optionspicker);
optionsPicker.setBackgroundColor(mPickerOptions.bgColorWheel);
wheelOptions = new WheelOptions(optionsPicker, mPickerOptions.isRestoreItem);
if (mPickerOptions.optionsSelectChangeListener != null) {
wheelOptions.setOptionsSelectChangeListener(mPickerOptions.optionsSelectChangeListener);
}
wheelOptions.setTextContentSize(mPickerOptions.textSizeContent);
wheelOptions.setLabels(mPickerOptions.label1, mPickerOptions.label2, mPickerOptions.label3);
wheelOptions.setTextXOffset(mPickerOptions.x_offset_one, mPickerOptions.x_offset_two, mPickerOptions.x_offset_three);
wheelOptions.setCyclic(mPickerOptions.cyclic1, mPickerOptions.cyclic2, mPickerOptions.cyclic3);
wheelOptions.setTypeface(mPickerOptions.font);
setOutSideCancelable(mPickerOptions.cancelable);
wheelOptions.setDividerColor(mPickerOptions.dividerColor);
wheelOptions.setDividerType(mPickerOptions.dividerType);
wheelOptions.setLineSpacingMultiplier(mPickerOptions.lineSpacingMultiplier);
wheelOptions.setTextColorOut(mPickerOptions.textColorOut);
wheelOptions.setTextColorCenter(mPickerOptions.textColorCenter);
wheelOptions.isCenterLabel(mPickerOptions.isCenterLabel);
}
/**
* 动态设置标题
*
* @param text 标题文本内容
*/
public void setTitleText(String text) {
TextView tvTitle = (TextView) findViewById(R.id.tvTitle);
if (tvTitle != null) {
tvTitle.setText(text);
}
}
/**
* 设置默认选中项
*
* @param option1
*/
public void setSelectOptions(int option1) {
mPickerOptions.option1 = option1;
reSetCurrentItems();
}
public void setSelectOptions(int option1, int option2) {
mPickerOptions.option1 = option1;
mPickerOptions.option2 = option2;
reSetCurrentItems();
}
public void setSelectOptions(int option1, int option2, int option3) {
mPickerOptions.option1 = option1;
mPickerOptions.option2 = option2;
mPickerOptions.option3 = option3;
reSetCurrentItems();
}
private void reSetCurrentItems() {
if (wheelOptions != null) {
wheelOptions.setCurrentItems(mPickerOptions.option1, mPickerOptions.option2, mPickerOptions.option3);
}
}
public void setPicker(List<T> optionsItems) {
this.setPicker(optionsItems, null, null);
}
public void setPicker(List<T> options1Items, List<List<T>> options2Items) {
this.setPicker(options1Items, options2Items, null);
}
public void setPicker(List<T> options1Items,
List<List<T>> options2Items,
List<List<List<T>>> options3Items) {
wheelOptions.setPicker(options1Items, options2Items, options3Items);
reSetCurrentItems();
}
//不联动情况下调用
public void setNPicker(List<T> options1Items,
List<T> options2Items,
List<T> options3Items) {
wheelOptions.setLinkage(false);
wheelOptions.setNPicker(options1Items, options2Items, options3Items);
reSetCurrentItems();
}
@Override
public void onClick(View v) {
String tag = (String) v.getTag();
if (tag.equals(TAG_SUBMIT)) {
returnData();
}
dismiss();
}
//抽离接口回调的方法
public void returnData() {
if (mPickerOptions.optionsSelectListener != null) {
int[] optionsCurrentItems = wheelOptions.getCurrentItems();
mPickerOptions.optionsSelectListener.onOptionsSelect(optionsCurrentItems[0], optionsCurrentItems[1], optionsCurrentItems[2], clickView);
}
}
@Override
public boolean isDialog() {
return mPickerOptions.isDialog;
}
}
package com.bigkoo.pickerview.view;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bigkoo.pickerview.R;
import com.bigkoo.pickerview.configure.PickerOptions;
import com.bigkoo.pickerview.listener.ISelectTimeCallback;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
/**
* 时间选择器
* Created by Sai on 15/11/22.
* Updated by XiaoSong on 2017-2-22.
*/
public class TimePickerView extends BasePickerView implements View.OnClickListener {
private WheelTime wheelTime; //自定义控件
private static final String TAG_SUBMIT = "submit";
private static final String TAG_CANCEL = "cancel";
public TimePickerView(PickerOptions pickerOptions) {
super(pickerOptions.context);
mPickerOptions = pickerOptions;
initView(pickerOptions.context);
}
private void initView(Context context) {
setDialogOutSideCancelable();
initViews();
initAnim();
if (mPickerOptions.customListener == null) {
LayoutInflater.from(context).inflate(R.layout.pickerview_time, contentContainer);
//顶部标题
TextView tvTitle = (TextView) findViewById(R.id.tvTitle);
RelativeLayout rv_top_bar = (RelativeLayout) findViewById(R.id.rv_topbar);
//确定和取消按钮
Button btnSubmit = (Button) findViewById(R.id.btnSubmit);
Button btnCancel = (Button) findViewById(R.id.btnCancel);
btnSubmit.setTag(TAG_SUBMIT);
btnCancel.setTag(TAG_CANCEL);
btnSubmit.setOnClickListener(this);
btnCancel.setOnClickListener(this);
//设置文字
btnSubmit.setText(TextUtils.isEmpty(mPickerOptions.textContentConfirm) ? context.getResources().getString(R.string.pickerview_submit) : mPickerOptions.textContentConfirm);
btnCancel.setText(TextUtils.isEmpty(mPickerOptions.textContentCancel) ? context.getResources().getString(R.string.pickerview_cancel) : mPickerOptions.textContentCancel);
tvTitle.setText(TextUtils.isEmpty(mPickerOptions.textContentTitle) ? "" : mPickerOptions.textContentTitle);//默认为空
//设置color
btnSubmit.setTextColor(mPickerOptions.textColorConfirm);
btnCancel.setTextColor(mPickerOptions.textColorCancel);
tvTitle.setTextColor(mPickerOptions.textColorTitle);
rv_top_bar.setBackgroundColor(mPickerOptions.bgColorTitle);
//设置文字大小
btnSubmit.setTextSize(mPickerOptions.textSizeSubmitCancel);
btnCancel.setTextSize(mPickerOptions.textSizeSubmitCancel);
tvTitle.setTextSize(mPickerOptions.textSizeTitle);
} else {
mPickerOptions.customListener.customLayout(LayoutInflater.from(context).inflate(mPickerOptions.layoutRes, contentContainer));
}
// 时间转轮 自定义控件
LinearLayout timePickerView = (LinearLayout) findViewById(R.id.timepicker);
timePickerView.setBackgroundColor(mPickerOptions.bgColorWheel);
initWheelTime(timePickerView);
}
private void initWheelTime(LinearLayout timePickerView) {
wheelTime = new WheelTime(timePickerView, mPickerOptions.type, mPickerOptions.textGravity, mPickerOptions.textSizeContent);
if (mPickerOptions.timeSelectChangeListener != null) {
wheelTime.setSelectChangeCallback(new ISelectTimeCallback() {
@Override
public void onTimeSelectChanged() {
try {
Date date = WheelTime.dateFormat.parse(wheelTime.getTime());
mPickerOptions.timeSelectChangeListener.onTimeSelectChanged(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
});
}
wheelTime.setLunarMode(mPickerOptions.isLunarCalendar);
if (mPickerOptions.startYear != 0 && mPickerOptions.endYear != 0
&& mPickerOptions.startYear <= mPickerOptions.endYear) {
setRange();
}
//若手动设置了时间范围限制
if (mPickerOptions.startDate != null && mPickerOptions.endDate != null) {
if (mPickerOptions.startDate.getTimeInMillis() > mPickerOptions.endDate.getTimeInMillis()) {
throw new IllegalArgumentException("startDate can't be later than endDate");
} else {
setRangDate();
}
} else if (mPickerOptions.startDate != null) {
if (mPickerOptions.startDate.get(Calendar.YEAR) < 1900) {
throw new IllegalArgumentException("The startDate can not as early as 1900");
} else {
setRangDate();
}
} else if (mPickerOptions.endDate != null) {
if (mPickerOptions.endDate.get(Calendar.YEAR) > 2100) {
throw new IllegalArgumentException("The endDate should not be later than 2100");
} else {
setRangDate();
}
} else {//没有设置时间范围限制,则会使用默认范围。
setRangDate();
}
setTime();
wheelTime.setLabels(mPickerOptions.label_year, mPickerOptions.label_month, mPickerOptions.label_day
, mPickerOptions.label_hours, mPickerOptions.label_minutes, mPickerOptions.label_seconds);
wheelTime.setTextXOffset(mPickerOptions.x_offset_year, mPickerOptions.x_offset_month, mPickerOptions.x_offset_day,
mPickerOptions.x_offset_hours, mPickerOptions.x_offset_minutes, mPickerOptions.x_offset_seconds);
setOutSideCancelable(mPickerOptions.cancelable);
wheelTime.setCyclic(mPickerOptions.cyclic);
wheelTime.setDividerColor(mPickerOptions.dividerColor);
wheelTime.setDividerType(mPickerOptions.dividerType);
wheelTime.setLineSpacingMultiplier(mPickerOptions.lineSpacingMultiplier);
wheelTime.setTextColorOut(mPickerOptions.textColorOut);
wheelTime.setTextColorCenter(mPickerOptions.textColorCenter);
wheelTime.isCenterLabel(mPickerOptions.isCenterLabel);
}
/**
* 设置默认时间
*/
public void setDate(Calendar date) {
mPickerOptions.date = date;
setTime();
}
/**
* 设置可以选择的时间范围, 要在setTime之前调用才有效果
*/
private void setRange() {
wheelTime.setStartYear(mPickerOptions.startYear);
wheelTime.setEndYear(mPickerOptions.endYear);
}
/**
* 设置可以选择的时间范围, 要在setTime之前调用才有效果
*/
private void setRangDate() {
wheelTime.setRangDate(mPickerOptions.startDate, mPickerOptions.endDate);
initDefaultSelectedDate();
}
private void initDefaultSelectedDate() {
//如果手动设置了时间范围
if (mPickerOptions.startDate != null && mPickerOptions.endDate != null) {
//若默认时间未设置,或者设置的默认时间越界了,则设置默认选中时间为开始时间。
if (mPickerOptions.date == null || mPickerOptions.date.getTimeInMillis() < mPickerOptions.startDate.getTimeInMillis()
|| mPickerOptions.date.getTimeInMillis() > mPickerOptions.endDate.getTimeInMillis()) {
mPickerOptions.date = mPickerOptions.startDate;
}
} else if (mPickerOptions.startDate != null) {
//没有设置默认选中时间,那就拿开始时间当默认时间
mPickerOptions.date = mPickerOptions.startDate;
} else if (mPickerOptions.endDate != null) {
mPickerOptions.date = mPickerOptions.endDate;
}
}
/**
* 设置选中时间,默认选中当前时间
*/
private void setTime() {
int year, month, day, hours, minute, seconds;
Calendar calendar = Calendar.getInstance();
if (mPickerOptions.date == null) {
calendar.setTimeInMillis(System.currentTimeMillis());
year = calendar.get(Calendar.YEAR);
month = calendar.get(Calendar.MONTH);
day = calendar.get(Calendar.DAY_OF_MONTH);
hours = calendar.get(Calendar.HOUR_OF_DAY);
minute = calendar.get(Calendar.MINUTE);
seconds = calendar.get(Calendar.SECOND);
} else {
year = mPickerOptions.date.get(Calendar.YEAR);
month = mPickerOptions.date.get(Calendar.MONTH);
day = mPickerOptions.date.get(Calendar.DAY_OF_MONTH);
hours = mPickerOptions.date.get(Calendar.HOUR_OF_DAY);
minute = mPickerOptions.date.get(Calendar.MINUTE);
seconds = mPickerOptions.date.get(Calendar.SECOND);
}
wheelTime.setPicker(year, month, day, hours, minute, seconds);
}
@Override
public void onClick(View v) {
String tag = (String) v.getTag();
if (tag.equals(TAG_SUBMIT)) {
returnData();
}
dismiss();
}
public void returnData() {
if (mPickerOptions.timeSelectListener != null) {
try {
Date date = WheelTime.dateFormat.parse(wheelTime.getTime());
mPickerOptions.timeSelectListener.onTimeSelect(date, clickView);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
/**
* 动态设置标题
*
* @param text 标题文本内容
*/
public void setTitleText(String text) {
TextView tvTitle = (TextView) findViewById(R.id.tvTitle);
if (tvTitle != null) {
tvTitle.setText(text);
}
}
/**
* 目前暂时只支持设置1900 - 2100年
*
* @param lunar 农历的开关
*/
public void setLunarCalendar(boolean lunar) {
try {
int year, month, day, hours, minute, seconds;
Calendar calendar = Calendar.getInstance();
calendar.setTime(WheelTime.dateFormat.parse(wheelTime.getTime()));
year = calendar.get(Calendar.YEAR);
month = calendar.get(Calendar.MONTH);
day = calendar.get(Calendar.DAY_OF_MONTH);
hours = calendar.get(Calendar.HOUR_OF_DAY);
minute = calendar.get(Calendar.MINUTE);
seconds = calendar.get(Calendar.SECOND);
wheelTime.setLunarMode(lunar);
wheelTime.setLabels(mPickerOptions.label_year, mPickerOptions.label_month, mPickerOptions.label_day,
mPickerOptions.label_hours, mPickerOptions.label_minutes, mPickerOptions.label_seconds);
wheelTime.setPicker(year, month, day, hours, minute, seconds);
} catch (ParseException e) {
e.printStackTrace();
}
}
public boolean isLunarCalendar() {
return wheelTime.isLunarMode();
}
@Override
public boolean isDialog() {
return mPickerOptions.isDialog;
}
}
package com.bigkoo.pickerview.view;
import android.graphics.Typeface;
import android.view.View;
import com.bigkoo.pickerview.R;
import com.bigkoo.pickerview.adapter.ArrayWheelAdapter;
import com.bigkoo.pickerview.listener.OnOptionsSelectChangeListener;
import com.contrarywind.listener.OnItemSelectedListener;
import com.contrarywind.view.WheelView;
import java.util.List;
public class WheelOptions<T> {
private View view;
private WheelView wv_option1;
private WheelView wv_option2;
private WheelView wv_option3;
private List<T> mOptions1Items;
private List<List<T>> mOptions2Items;
private List<List<List<T>>> mOptions3Items;
private boolean linkage = true;//默认联动
private boolean isRestoreItem; //切换时,还原第一项
private OnItemSelectedListener wheelListener_option1;
private OnItemSelectedListener wheelListener_option2;
private OnOptionsSelectChangeListener optionsSelectChangeListener;
//文字的颜色和分割线的颜色
private int textColorOut;
private int textColorCenter;
private int dividerColor;
private WheelView.DividerType dividerType;
// 条目间距倍数
private float lineSpacingMultiplier;
public View getView() {
return view;
}
public void setView(View view) {
this.view = view;
}
public WheelOptions(View view, boolean isRestoreItem) {
super();
this.isRestoreItem = isRestoreItem;
this.view = view;
wv_option1 = (WheelView) view.findViewById(R.id.options1);// 初始化时显示的数据
wv_option2 = (WheelView) view.findViewById(R.id.options2);
wv_option3 = (WheelView) view.findViewById(R.id.options3);
}
public void setPicker(List<T> options1Items,
List<List<T>> options2Items,
List<List<List<T>>> options3Items) {
this.mOptions1Items = options1Items;
this.mOptions2Items = options2Items;
this.mOptions3Items = options3Items;
// 选项1
wv_option1.setAdapter(new ArrayWheelAdapter(mOptions1Items));// 设置显示数据
wv_option1.setCurrentItem(0);// 初始化时显示的数据
// 选项2
if (mOptions2Items != null) {
wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items.get(0)));// 设置显示数据
}
wv_option2.setCurrentItem(wv_option2.getCurrentItem());// 初始化时显示的数据
// 选项3
if (mOptions3Items != null) {
wv_option3.setAdapter(new ArrayWheelAdapter(mOptions3Items.get(0).get(0)));// 设置显示数据
}
wv_option3.setCurrentItem(wv_option3.getCurrentItem());
wv_option1.setIsOptions(true);
wv_option2.setIsOptions(true);
wv_option3.setIsOptions(true);
if (this.mOptions2Items == null) {
wv_option2.setVisibility(View.GONE);
} else {
wv_option2.setVisibility(View.VISIBLE);
}
if (this.mOptions3Items == null) {
wv_option3.setVisibility(View.GONE);
} else {
wv_option3.setVisibility(View.VISIBLE);
}
// 联动监听器
wheelListener_option1 = new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
int opt2Select = 0;
if (mOptions2Items == null) {//只有1级联动数据
if (optionsSelectChangeListener != null) {
optionsSelectChangeListener.onOptionsSelectChanged(wv_option1.getCurrentItem(), 0, 0);
}
} else {
if (!isRestoreItem) {
opt2Select = wv_option2.getCurrentItem();//上一个opt2的选中位置
//新opt2的位置,判断如果旧位置没有超过数据范围,则沿用旧位置,否则选中最后一项
opt2Select = opt2Select >= mOptions2Items.get(index).size() - 1 ? mOptions2Items.get(index).size() - 1 : opt2Select;
}
wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items.get(index)));
wv_option2.setCurrentItem(opt2Select);
if (mOptions3Items != null) {
wheelListener_option2.onItemSelected(opt2Select);
} else {//只有2级联动数据,滑动第1项回调
if (optionsSelectChangeListener != null) {
optionsSelectChangeListener.onOptionsSelectChanged(index, opt2Select, 0);
}
}
}
}
};
wheelListener_option2 = new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
if (mOptions3Items != null) {
int opt1Select = wv_option1.getCurrentItem();
opt1Select = opt1Select >= mOptions3Items.size() - 1 ? mOptions3Items.size() - 1 : opt1Select;
index = index >= mOptions2Items.get(opt1Select).size() - 1 ? mOptions2Items.get(opt1Select).size() - 1 : index;
int opt3 = 0;
if (!isRestoreItem) {
// wv_option3.getCurrentItem() 上一个opt3的选中位置
//新opt3的位置,判断如果旧位置没有超过数据范围,则沿用旧位置,否则选中最后一项
opt3 = wv_option3.getCurrentItem() >= mOptions3Items.get(opt1Select).get(index).size() - 1 ?
mOptions3Items.get(opt1Select).get(index).size() - 1 : wv_option3.getCurrentItem();
}
wv_option3.setAdapter(new ArrayWheelAdapter(mOptions3Items.get(wv_option1.getCurrentItem()).get(index)));
wv_option3.setCurrentItem(opt3);
//3级联动数据实时回调
if (optionsSelectChangeListener != null) {
optionsSelectChangeListener.onOptionsSelectChanged(wv_option1.getCurrentItem(), index, opt3);
}
} else {//只有2级联动数据,滑动第2项回调
if (optionsSelectChangeListener != null) {
optionsSelectChangeListener.onOptionsSelectChanged(wv_option1.getCurrentItem(), index, 0);
}
}
}
};
// 添加联动监听
if (options1Items != null && linkage) {
wv_option1.setOnItemSelectedListener(wheelListener_option1);
}
if (options2Items != null && linkage) {
wv_option2.setOnItemSelectedListener(wheelListener_option2);
}
if (options3Items != null && linkage && optionsSelectChangeListener != null) {
wv_option3.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
optionsSelectChangeListener.onOptionsSelectChanged(wv_option1.getCurrentItem(), wv_option2.getCurrentItem(), index);
}
});
}
}
//不联动情况下
public void setNPicker(List<T> options1Items, List<T> options2Items, List<T> options3Items) {
// 选项1
wv_option1.setAdapter(new ArrayWheelAdapter(options1Items));// 设置显示数据
wv_option1.setCurrentItem(0);// 初始化时显示的数据
// 选项2
if (options2Items != null) {
wv_option2.setAdapter(new ArrayWheelAdapter(options2Items));// 设置显示数据
}
wv_option2.setCurrentItem(wv_option2.getCurrentItem());// 初始化时显示的数据
// 选项3
if (options3Items != null) {
wv_option3.setAdapter(new ArrayWheelAdapter(options3Items));// 设置显示数据
}
wv_option3.setCurrentItem(wv_option3.getCurrentItem());
wv_option1.setIsOptions(true);
wv_option2.setIsOptions(true);
wv_option3.setIsOptions(true);
if (optionsSelectChangeListener != null) {
wv_option1.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
optionsSelectChangeListener.onOptionsSelectChanged(index, wv_option2.getCurrentItem(), wv_option3.getCurrentItem());
}
});
}
if (options2Items == null) {
wv_option2.setVisibility(View.GONE);
} else {
wv_option2.setVisibility(View.VISIBLE);
if (optionsSelectChangeListener != null) {
wv_option2.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
optionsSelectChangeListener.onOptionsSelectChanged(wv_option1.getCurrentItem(), index, wv_option3.getCurrentItem());
}
});
}
}
if (options3Items == null) {
wv_option3.setVisibility(View.GONE);
} else {
wv_option3.setVisibility(View.VISIBLE);
if (optionsSelectChangeListener != null) {
wv_option3.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
optionsSelectChangeListener.onOptionsSelectChanged(wv_option1.getCurrentItem(), wv_option2.getCurrentItem(), index);
}
});
}
}
}
public void setTextContentSize(int textSize) {
wv_option1.setTextSize(textSize);
wv_option2.setTextSize(textSize);
wv_option3.setTextSize(textSize);
}
private void setTextColorOut() {
wv_option1.setTextColorOut(textColorOut);
wv_option2.setTextColorOut(textColorOut);
wv_option3.setTextColorOut(textColorOut);
}
private void setTextColorCenter() {
wv_option1.setTextColorCenter(textColorCenter);
wv_option2.setTextColorCenter(textColorCenter);
wv_option3.setTextColorCenter(textColorCenter);
}
private void setDividerColor() {
wv_option1.setDividerColor(dividerColor);
wv_option2.setDividerColor(dividerColor);
wv_option3.setDividerColor(dividerColor);
}
private void setDividerType() {
wv_option1.setDividerType(dividerType);
wv_option2.setDividerType(dividerType);
wv_option3.setDividerType(dividerType);
}
private void setLineSpacingMultiplier() {
wv_option1.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_option2.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_option3.setLineSpacingMultiplier(lineSpacingMultiplier);
}
/**
* 设置选项的单位
*
* @param label1 单位
* @param label2 单位
* @param label3 单位
*/
public void setLabels(String label1, String label2, String label3) {
if (label1 != null) {
wv_option1.setLabel(label1);
}
if (label2 != null) {
wv_option2.setLabel(label2);
}
if (label3 != null) {
wv_option3.setLabel(label3);
}
}
/**
* 设置x轴偏移量
*/
public void setTextXOffset(int x_offset_one, int x_offset_two, int x_offset_three) {
wv_option1.setTextXOffset(x_offset_one);
wv_option2.setTextXOffset(x_offset_two);
wv_option3.setTextXOffset(x_offset_three);
}
/**
* 设置是否循环滚动
*
* @param cyclic 是否循环
*/
public void setCyclic(boolean cyclic) {
wv_option1.setCyclic(cyclic);
wv_option2.setCyclic(cyclic);
wv_option3.setCyclic(cyclic);
}
/**
* 设置字体样式
*
* @param font 系统提供的几种样式
*/
public void setTypeface(Typeface font) {
wv_option1.setTypeface(font);
wv_option2.setTypeface(font);
wv_option3.setTypeface(font);
}
/**
* 分别设置第一二三级是否循环滚动
*
* @param cyclic1,cyclic2,cyclic3 是否循环
*/
public void setCyclic(boolean cyclic1, boolean cyclic2, boolean cyclic3) {
wv_option1.setCyclic(cyclic1);
wv_option2.setCyclic(cyclic2);
wv_option3.setCyclic(cyclic3);
}
/**
* 返回当前选中的结果对应的位置数组 因为支持三级联动效果,分三个级别索引,0,1,2。
* 在快速滑动未停止时,点击确定按钮,会进行判断,如果匹配数据越界,则设为0,防止index出错导致崩溃。
*
* @return 索引数组
*/
public int[] getCurrentItems() {
int[] currentItems = new int[3];
currentItems[0] = wv_option1.getCurrentItem();
if (mOptions2Items != null && mOptions2Items.size() > 0) {//非空判断
currentItems[1] = wv_option2.getCurrentItem() > (mOptions2Items.get(currentItems[0]).size() - 1) ? 0 : wv_option2.getCurrentItem();
} else {
currentItems[1] = wv_option2.getCurrentItem();
}
if (mOptions3Items != null && mOptions3Items.size() > 0) {//非空判断
currentItems[2] = wv_option3.getCurrentItem() > (mOptions3Items.get(currentItems[0]).get(currentItems[1]).size() - 1) ? 0 : wv_option3.getCurrentItem();
} else {
currentItems[2] = wv_option3.getCurrentItem();
}
return currentItems;
}
public void setCurrentItems(int option1, int option2, int option3) {
if (linkage) {
itemSelected(option1, option2, option3);
} else {
wv_option1.setCurrentItem(option1);
wv_option2.setCurrentItem(option2);
wv_option3.setCurrentItem(option3);
}
}
private void itemSelected(int opt1Select, int opt2Select, int opt3Select) {
if (mOptions1Items != null) {
wv_option1.setCurrentItem(opt1Select);
}
if (mOptions2Items != null) {
wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items.get(opt1Select)));
wv_option2.setCurrentItem(opt2Select);
}
if (mOptions3Items != null) {
wv_option3.setAdapter(new ArrayWheelAdapter(mOptions3Items.get(opt1Select).get(opt2Select)));
wv_option3.setCurrentItem(opt3Select);
}
}
/**
* 设置间距倍数,但是只能在1.2-4.0f之间
*
* @param lineSpacingMultiplier
*/
public void setLineSpacingMultiplier(float lineSpacingMultiplier) {
this.lineSpacingMultiplier = lineSpacingMultiplier;
setLineSpacingMultiplier();
}
/**
* 设置分割线的颜色
*
* @param dividerColor
*/
public void setDividerColor(int dividerColor) {
this.dividerColor = dividerColor;
setDividerColor();
}
/**
* 设置分割线的类型
*
* @param dividerType
*/
public void setDividerType(WheelView.DividerType dividerType) {
this.dividerType = dividerType;
setDividerType();
}
/**
* 设置分割线之间的文字的颜色
*
* @param textColorCenter
*/
public void setTextColorCenter(int textColorCenter) {
this.textColorCenter = textColorCenter;
setTextColorCenter();
}
/**
* 设置分割线以外文字的颜色
*
* @param textColorOut
*/
public void setTextColorOut(int textColorOut) {
this.textColorOut = textColorOut;
setTextColorOut();
}
/**
* Label 是否只显示中间选中项的
*
* @param isCenterLabel
*/
public void isCenterLabel(boolean isCenterLabel) {
wv_option1.isCenterLabel(isCenterLabel);
wv_option2.isCenterLabel(isCenterLabel);
wv_option3.isCenterLabel(isCenterLabel);
}
public void setOptionsSelectChangeListener(OnOptionsSelectChangeListener optionsSelectChangeListener) {
this.optionsSelectChangeListener = optionsSelectChangeListener;
}
public void setLinkage(boolean linkage) {
this.linkage = linkage;
}
}
package com.bigkoo.pickerview.view;
import android.view.View;
import com.bigkoo.pickerview.R;
import com.bigkoo.pickerview.adapter.ArrayWheelAdapter;
import com.bigkoo.pickerview.adapter.NumericWheelAdapter;
import com.bigkoo.pickerview.listener.ISelectTimeCallback;
import com.bigkoo.pickerview.utils.ChinaDate;
import com.bigkoo.pickerview.utils.LunarCalendar;
import com.contrarywind.listener.OnItemSelectedListener;
import com.contrarywind.view.WheelView;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
public class WheelTime {
public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private View view;
private WheelView wv_year;
private WheelView wv_month;
private WheelView wv_day;
private WheelView wv_hours;
private WheelView wv_minutes;
private WheelView wv_seconds;
private int gravity;
private boolean[] type;
private static final int DEFAULT_START_YEAR = 1900;
private static final int DEFAULT_END_YEAR = 2100;
private static final int DEFAULT_START_MONTH = 1;
private static final int DEFAULT_END_MONTH = 12;
private static final int DEFAULT_START_DAY = 1;
private static final int DEFAULT_END_DAY = 31;
private int startYear = DEFAULT_START_YEAR;
private int endYear = DEFAULT_END_YEAR;
private int startMonth = DEFAULT_START_MONTH;
private int endMonth = DEFAULT_END_MONTH;
private int startDay = DEFAULT_START_DAY;
private int endDay = DEFAULT_END_DAY; //表示31天的
private int currentYear;
private int textSize;
//文字的颜色和分割线的颜色
private int textColorOut;
private int textColorCenter;
private int dividerColor;
private float lineSpacingMultiplier;
private WheelView.DividerType dividerType;
private boolean isLunarCalendar = false;
private ISelectTimeCallback mSelectChangeCallback;
private ArrayList<String> mMinutes = new ArrayList<>();
public WheelTime(View view, boolean[] type, int gravity, int textSize) {
super();
this.view = view;
this.type = type;
this.gravity = gravity;
this.textSize = textSize;
mMinutes.add("00");
mMinutes.add("15");
mMinutes.add("30");
mMinutes.add("45");
setView(view);
}
public void setLunarMode(boolean isLunarCalendar) {
this.isLunarCalendar = isLunarCalendar;
}
public boolean isLunarMode() {
return isLunarCalendar;
}
public void setPicker(int year, int month, int day) {
this.setPicker(year, month, day, 0, 0, 0);
}
public void setPicker(int year, final int month, int day, int h, int m, int s) {
if (isLunarCalendar) {
int[] lunar = LunarCalendar.solarToLunar(year, month + 1, day);
setLunar(lunar[0], lunar[1] - 1, lunar[2], lunar[3] == 1, h, m, s);
} else {
setSolar(year, month, day, h, m, s);
}
}
/**
* 设置农历
*
* @param year
* @param month
* @param day
* @param h
* @param m
* @param s
*/
private void setLunar(int year, final int month, int day, boolean isLeap, int h, int m, int s) {
// 年
wv_year = (WheelView) view.findViewById(R.id.year);
wv_year.setAdapter(new ArrayWheelAdapter(ChinaDate.getYears(startYear, endYear)));// 设置"年"的显示数据
wv_year.setLabel("");// 添加文字
wv_year.setCurrentItem(year - startYear);// 初始化时显示的数据
wv_year.setGravity(gravity);
// 月
wv_month = (WheelView) view.findViewById(R.id.month);
wv_month.setAdapter(new ArrayWheelAdapter(ChinaDate.getMonths(year)));
wv_month.setLabel("");
wv_month.setCurrentItem(month);
wv_month.setGravity(gravity);
// 日
wv_day = (WheelView) view.findViewById(R.id.day);
// 判断大小月及是否闰年,用来确定"日"的数据
if (ChinaDate.leapMonth(year) == 0) {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.monthDays(year, month))));
} else {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.leapDays(year))));
}
wv_day.setLabel("");
wv_day.setCurrentItem(day - 1);
wv_day.setGravity(gravity);
wv_hours = (WheelView) view.findViewById(R.id.hour);
wv_hours.setAdapter(new NumericWheelAdapter(0, 23));
//wv_hours.setLabel(context.getString(R.string.pickerview_hours));// 添加文字
wv_hours.setCurrentItem(h);
wv_hours.setGravity(gravity);
wv_minutes = (WheelView) view.findViewById(R.id.min);
// wv_minutes.setAdapter(new NumericWheelAdapter(0, 59));
ArrayList<String> minutes = new ArrayList<>();
minutes.add("00");
minutes.add("15");
minutes.add("30");
minutes.add("45");
wv_minutes.setAdapter(new ArrayWheelAdapter(minutes));
//wv_minutes.setLabel(context.getString(R.string.pickerview_minutes));// 添加文字
wv_minutes.setCurrentItem(0);
wv_minutes.setGravity(gravity);
wv_seconds = (WheelView) view.findViewById(R.id.second);
wv_seconds.setAdapter(new NumericWheelAdapter(0, 59));
//wv_seconds.setLabel(context.getString(R.string.pickerview_minutes));// 添加文字
wv_seconds.setCurrentItem(m);
wv_seconds.setGravity(gravity);
// 添加"年"监听
wv_year.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
int year_num = index + startYear;
// 判断是不是闰年,来确定月和日的选择
wv_month.setAdapter(new ArrayWheelAdapter(ChinaDate.getMonths(year_num)));
if (ChinaDate.leapMonth(year_num) != 0 && wv_month.getCurrentItem() > ChinaDate.leapMonth(year_num) - 1) {
wv_month.setCurrentItem(wv_month.getCurrentItem() + 1);
} else {
wv_month.setCurrentItem(wv_month.getCurrentItem());
}
int maxItem = 29;
if (ChinaDate.leapMonth(year_num) != 0 && wv_month.getCurrentItem() > ChinaDate.leapMonth(year_num) - 1) {
if (wv_month.getCurrentItem() == ChinaDate.leapMonth(year_num) + 1) {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.leapDays(year_num))));
maxItem = ChinaDate.leapDays(year_num);
} else {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.monthDays(year_num, wv_month.getCurrentItem()))));
maxItem = ChinaDate.monthDays(year_num, wv_month.getCurrentItem());
}
} else {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.monthDays(year_num, wv_month.getCurrentItem() + 1))));
maxItem = ChinaDate.monthDays(year_num, wv_month.getCurrentItem() + 1);
}
if (wv_day.getCurrentItem() > maxItem - 1) {
wv_day.setCurrentItem(maxItem - 1);
}
if (mSelectChangeCallback != null) {
mSelectChangeCallback.onTimeSelectChanged();
}
}
});
// 添加"月"监听
wv_month.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
int month_num = index;
int year_num = wv_year.getCurrentItem() + startYear;
int maxItem = 29;
if (ChinaDate.leapMonth(year_num) != 0 && month_num > ChinaDate.leapMonth(year_num) - 1) {
if (wv_month.getCurrentItem() == ChinaDate.leapMonth(year_num) + 1) {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.leapDays(year_num))));
maxItem = ChinaDate.leapDays(year_num);
} else {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.monthDays(year_num, month_num))));
maxItem = ChinaDate.monthDays(year_num, month_num);
}
} else {
wv_day.setAdapter(new ArrayWheelAdapter(ChinaDate.getLunarDays(ChinaDate.monthDays(year_num, month_num + 1))));
maxItem = ChinaDate.monthDays(year_num, month_num + 1);
}
if (wv_day.getCurrentItem() > maxItem - 1) {
wv_day.setCurrentItem(maxItem - 1);
}
if (mSelectChangeCallback != null) {
mSelectChangeCallback.onTimeSelectChanged();
}
}
});
setChangedListener(wv_day);
setChangedListener(wv_hours);
setChangedListener(wv_minutes);
setChangedListener(wv_seconds);
if (type.length != 6) {
throw new RuntimeException("type[] length is not 6");
}
wv_year.setVisibility(type[0] ? View.VISIBLE : View.GONE);
wv_month.setVisibility(type[1] ? View.VISIBLE : View.GONE);
wv_day.setVisibility(type[2] ? View.VISIBLE : View.GONE);
wv_hours.setVisibility(type[3] ? View.VISIBLE : View.GONE);
wv_minutes.setVisibility(type[4] ? View.VISIBLE : View.GONE);
wv_seconds.setVisibility(type[5] ? View.VISIBLE : View.GONE);
setContentTextSize();
}
/**
* 设置公历
*
* @param year
* @param month
* @param day
* @param h
* @param m
* @param s
*/
private void setSolar(int year, final int month, int day, int h, int m, int s) {
// 添加大小月月份并将其转换为list,方便之后的判断
String[] months_big = {"1", "3", "5", "7", "8", "10", "12"};
String[] months_little = {"4", "6", "9", "11"};
final List<String> list_big = Arrays.asList(months_big);
final List<String> list_little = Arrays.asList(months_little);
currentYear = year;
// 年
wv_year = (WheelView) view.findViewById(R.id.year);
wv_year.setAdapter(new NumericWheelAdapter(startYear, endYear));// 设置"年"的显示数据
wv_year.setCurrentItem(year - startYear);// 初始化时显示的数据
wv_year.setGravity(gravity);
// 月
wv_month = (WheelView) view.findViewById(R.id.month);
if (startYear == endYear) {//开始年等于终止年
wv_month.setAdapter(new NumericWheelAdapter(startMonth, endMonth));
wv_month.setCurrentItem(month + 1 - startMonth);
} else if (year == startYear) {
//起始日期的月份控制
wv_month.setAdapter(new NumericWheelAdapter(startMonth, 12));
wv_month.setCurrentItem(month + 1 - startMonth);
} else if (year == endYear) {
//终止日期的月份控制
wv_month.setAdapter(new NumericWheelAdapter(1, endMonth));
wv_month.setCurrentItem(month);
} else {
wv_month.setAdapter(new NumericWheelAdapter(1, 12));
wv_month.setCurrentItem(month);
}
wv_month.setGravity(gravity);
// 日
wv_day = (WheelView) view.findViewById(R.id.day);
if (startYear == endYear && startMonth == endMonth) {
if (list_big.contains(String.valueOf(month + 1))) {
if (endDay > 31) {
endDay = 31;
}
wv_day.setAdapter(new NumericWheelAdapter(startDay, endDay));
} else if (list_little.contains(String.valueOf(month + 1))) {
if (endDay > 30) {
endDay = 30;
}
wv_day.setAdapter(new NumericWheelAdapter(startDay, endDay));
} else {
// 闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
if (endDay > 29) {
endDay = 29;
}
wv_day.setAdapter(new NumericWheelAdapter(startDay, endDay));
} else {
if (endDay > 28) {
endDay = 28;
}
wv_day.setAdapter(new NumericWheelAdapter(startDay, endDay));
}
}
wv_day.setCurrentItem(day - startDay);
} else if (year == startYear && month + 1 == startMonth) {
// 起始日期的天数控制
if (list_big.contains(String.valueOf(month + 1))) {
wv_day.setAdapter(new NumericWheelAdapter(startDay, 31));
} else if (list_little.contains(String.valueOf(month + 1))) {
wv_day.setAdapter(new NumericWheelAdapter(startDay, 30));
} else {
// 闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
wv_day.setAdapter(new NumericWheelAdapter(startDay, 29));
} else {
wv_day.setAdapter(new NumericWheelAdapter(startDay, 28));
}
}
wv_day.setCurrentItem(day - startDay);
} else if (year == endYear && month + 1 == endMonth) {
// 终止日期的天数控制
if (list_big.contains(String.valueOf(month + 1))) {
if (endDay > 31) {
endDay = 31;
}
wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
} else if (list_little.contains(String.valueOf(month + 1))) {
if (endDay > 30) {
endDay = 30;
}
wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
} else {
// 闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
if (endDay > 29) {
endDay = 29;
}
wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
} else {
if (endDay > 28) {
endDay = 28;
}
wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
}
}
wv_day.setCurrentItem(day - 1);
} else {
// 判断大小月及是否闰年,用来确定"日"的数据
if (list_big.contains(String.valueOf(month + 1))) {
wv_day.setAdapter(new NumericWheelAdapter(1, 31));
} else if (list_little.contains(String.valueOf(month + 1))) {
wv_day.setAdapter(new NumericWheelAdapter(1, 30));
} else {
// 闰年
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
wv_day.setAdapter(new NumericWheelAdapter(1, 29));
} else {
wv_day.setAdapter(new NumericWheelAdapter(1, 28));
}
}
wv_day.setCurrentItem(day - 1);
}
wv_day.setGravity(gravity);
//时
wv_hours = (WheelView) view.findViewById(R.id.hour);
wv_hours.setAdapter(new NumericWheelAdapter(0, 23));
wv_hours.setCurrentItem(h);
wv_hours.setGravity(gravity);
//分
wv_minutes = (WheelView) view.findViewById(R.id.min);
// wv_minutes.setAdapter(new NumericWheelAdapter(0, 59));
wv_minutes.setAdapter(new ArrayWheelAdapter(mMinutes));
wv_minutes.setCurrentItem(0);
wv_minutes.setGravity(gravity);
//秒
wv_seconds = (WheelView) view.findViewById(R.id.second);
wv_seconds.setAdapter(new NumericWheelAdapter(0, 59));
wv_seconds.setCurrentItem(s);
wv_seconds.setGravity(gravity);
// 添加"年"监听
wv_year.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
int year_num = index + startYear;
currentYear = year_num;
int currentMonthItem = wv_month.getCurrentItem();//记录上一次的item位置
// 判断大小月及是否闰年,用来确定"日"的数据
if (startYear == endYear) {
//重新设置月份
wv_month.setAdapter(new NumericWheelAdapter(startMonth, endMonth));
if (currentMonthItem > wv_month.getAdapter().getItemsCount() - 1) {
currentMonthItem = wv_month.getAdapter().getItemsCount() - 1;
wv_month.setCurrentItem(currentMonthItem);
}
int monthNum = currentMonthItem + startMonth;
if (startMonth == endMonth) {
//重新设置日
setReDay(year_num, monthNum, startDay, endDay, list_big, list_little);
} else if (monthNum == startMonth) {
//重新设置日
setReDay(year_num, monthNum, startDay, 31, list_big, list_little);
} else if (monthNum == endMonth) {
setReDay(year_num, monthNum, 1, endDay, list_big, list_little);
} else {//重新设置日
setReDay(year_num, monthNum, 1, 31, list_big, list_little);
}
} else if (year_num == startYear) {//等于开始的年
//重新设置月份
wv_month.setAdapter(new NumericWheelAdapter(startMonth, 12));
if (currentMonthItem > wv_month.getAdapter().getItemsCount() - 1) {
currentMonthItem = wv_month.getAdapter().getItemsCount() - 1;
wv_month.setCurrentItem(currentMonthItem);
}
int month = currentMonthItem + startMonth;
if (month == startMonth) {
//重新设置日
setReDay(year_num, month, startDay, 31, list_big, list_little);
} else {
//重新设置日
setReDay(year_num, month, 1, 31, list_big, list_little);
}
} else if (year_num == endYear) {
//重新设置月份
wv_month.setAdapter(new NumericWheelAdapter(1, endMonth));
if (currentMonthItem > wv_month.getAdapter().getItemsCount() - 1) {
currentMonthItem = wv_month.getAdapter().getItemsCount() - 1;
wv_month.setCurrentItem(currentMonthItem);
}
int monthNum = currentMonthItem + 1;
if (monthNum == endMonth) {
//重新设置日
setReDay(year_num, monthNum, 1, endDay, list_big, list_little);
} else {
//重新设置日
setReDay(year_num, monthNum, 1, 31, list_big, list_little);
}
} else {
//重新设置月份
wv_month.setAdapter(new NumericWheelAdapter(1, 12));
//重新设置日
setReDay(year_num, wv_month.getCurrentItem() + 1, 1, 31, list_big, list_little);
}
if (mSelectChangeCallback != null) {
mSelectChangeCallback.onTimeSelectChanged();
}
}
});
// 添加"月"监听
wv_month.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
int month_num = index + 1;
if (startYear == endYear) {
month_num = month_num + startMonth - 1;
if (startMonth == endMonth) {
//重新设置日
setReDay(currentYear, month_num, startDay, endDay, list_big, list_little);
} else if (startMonth == month_num) {
//重新设置日
setReDay(currentYear, month_num, startDay, 31, list_big, list_little);
} else if (endMonth == month_num) {
setReDay(currentYear, month_num, 1, endDay, list_big, list_little);
} else {
setReDay(currentYear, month_num, 1, 31, list_big, list_little);
}
} else if (currentYear == startYear) {
month_num = month_num + startMonth - 1;
if (month_num == startMonth) {
//重新设置日
setReDay(currentYear, month_num, startDay, 31, list_big, list_little);
} else {
//重新设置日
setReDay(currentYear, month_num, 1, 31, list_big, list_little);
}
} else if (currentYear == endYear) {
if (month_num == endMonth) {
//重新设置日
setReDay(currentYear, wv_month.getCurrentItem() + 1, 1, endDay, list_big, list_little);
} else {
setReDay(currentYear, wv_month.getCurrentItem() + 1, 1, 31, list_big, list_little);
}
} else {
//重新设置日
setReDay(currentYear, month_num, 1, 31, list_big, list_little);
}
if (mSelectChangeCallback != null) {
mSelectChangeCallback.onTimeSelectChanged();
}
}
});
setChangedListener(wv_day);
setChangedListener(wv_hours);
setChangedListener(wv_minutes);
setChangedListener(wv_seconds);
if (type.length != 6) {
throw new IllegalArgumentException("type[] length is not 6");
}
wv_year.setVisibility(type[0] ? View.VISIBLE : View.GONE);
wv_month.setVisibility(type[1] ? View.VISIBLE : View.GONE);
wv_day.setVisibility(type[2] ? View.VISIBLE : View.GONE);
wv_hours.setVisibility(type[3] ? View.VISIBLE : View.GONE);
wv_minutes.setVisibility(type[4] ? View.VISIBLE : View.GONE);
wv_seconds.setVisibility(type[5] ? View.VISIBLE : View.GONE);
setContentTextSize();
}
private void setChangedListener(WheelView wheelView) {
if (mSelectChangeCallback != null) {
wheelView.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
mSelectChangeCallback.onTimeSelectChanged();
}
});
}
}
private void setReDay(int year_num, int monthNum, int startD, int endD, List<String> list_big, List<String> list_little) {
int currentItem = wv_day.getCurrentItem();
// int maxItem;
if (list_big.contains(String.valueOf(monthNum))) {
if (endD > 31) {
endD = 31;
}
wv_day.setAdapter(new NumericWheelAdapter(startD, endD));
// maxItem = endD;
} else if (list_little.contains(String.valueOf(monthNum))) {
if (endD > 30) {
endD = 30;
}
wv_day.setAdapter(new NumericWheelAdapter(startD, endD));
// maxItem = endD;
} else {
if ((year_num % 4 == 0 && year_num % 100 != 0)
|| year_num % 400 == 0) {
if (endD > 29) {
endD = 29;
}
wv_day.setAdapter(new NumericWheelAdapter(startD, endD));
// maxItem = endD;
} else {
if (endD > 28) {
endD = 28;
}
wv_day.setAdapter(new NumericWheelAdapter(startD, endD));
// maxItem = endD;
}
}
if (currentItem > wv_day.getAdapter().getItemsCount() - 1) {
currentItem = wv_day.getAdapter().getItemsCount() - 1;
wv_day.setCurrentItem(currentItem);
}
}
private void setContentTextSize() {
wv_day.setTextSize(textSize);
wv_month.setTextSize(textSize);
wv_year.setTextSize(textSize);
wv_hours.setTextSize(textSize);
wv_minutes.setTextSize(textSize);
wv_seconds.setTextSize(textSize);
}
private void setTextColorOut() {
wv_day.setTextColorOut(textColorOut);
wv_month.setTextColorOut(textColorOut);
wv_year.setTextColorOut(textColorOut);
wv_hours.setTextColorOut(textColorOut);
wv_minutes.setTextColorOut(textColorOut);
wv_seconds.setTextColorOut(textColorOut);
}
private void setTextColorCenter() {
wv_day.setTextColorCenter(textColorCenter);
wv_month.setTextColorCenter(textColorCenter);
wv_year.setTextColorCenter(textColorCenter);
wv_hours.setTextColorCenter(textColorCenter);
wv_minutes.setTextColorCenter(textColorCenter);
wv_seconds.setTextColorCenter(textColorCenter);
}
private void setDividerColor() {
wv_day.setDividerColor(dividerColor);
wv_month.setDividerColor(dividerColor);
wv_year.setDividerColor(dividerColor);
wv_hours.setDividerColor(dividerColor);
wv_minutes.setDividerColor(dividerColor);
wv_seconds.setDividerColor(dividerColor);
}
private void setDividerType() {
wv_day.setDividerType(dividerType);
wv_month.setDividerType(dividerType);
wv_year.setDividerType(dividerType);
wv_hours.setDividerType(dividerType);
wv_minutes.setDividerType(dividerType);
wv_seconds.setDividerType(dividerType);
}
private void setLineSpacingMultiplier() {
wv_day.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_month.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_year.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_hours.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_minutes.setLineSpacingMultiplier(lineSpacingMultiplier);
wv_seconds.setLineSpacingMultiplier(lineSpacingMultiplier);
}
public void setLabels(String label_year, String label_month, String label_day, String label_hours, String label_mins, String label_seconds) {
if (isLunarCalendar) {
return;
}
if (label_year != null) {
wv_year.setLabel(label_year);
} else {
wv_year.setLabel(view.getContext().getString(R.string.pickerview_year));
}
if (label_month != null) {
wv_month.setLabel(label_month);
} else {
wv_month.setLabel(view.getContext().getString(R.string.pickerview_month));
}
if (label_day != null) {
wv_day.setLabel(label_day);
} else {
wv_day.setLabel(view.getContext().getString(R.string.pickerview_day));
}
if (label_hours != null) {
wv_hours.setLabel(label_hours);
} else {
wv_hours.setLabel(view.getContext().getString(R.string.pickerview_hours));
}
if (label_mins != null) {
wv_minutes.setLabel(label_mins);
} else {
wv_minutes.setLabel(view.getContext().getString(R.string.pickerview_minutes));
}
if (label_seconds != null) {
wv_seconds.setLabel(label_seconds);
} else {
wv_seconds.setLabel(view.getContext().getString(R.string.pickerview_seconds));
}
}
public void setTextXOffset(int x_offset_year, int x_offset_month, int x_offset_day,
int x_offset_hours, int x_offset_minutes, int x_offset_seconds) {
wv_day.setTextXOffset(x_offset_year);
wv_month.setTextXOffset(x_offset_month);
wv_year.setTextXOffset(x_offset_day);
wv_hours.setTextXOffset(x_offset_hours);
wv_minutes.setTextXOffset(x_offset_minutes);
wv_seconds.setTextXOffset(x_offset_seconds);
}
/**
* 设置是否循环滚动
*
* @param cyclic
*/
public void setCyclic(boolean cyclic) {
wv_year.setCyclic(cyclic);
wv_month.setCyclic(cyclic);
wv_day.setCyclic(cyclic);
wv_hours.setCyclic(cyclic);
wv_minutes.setCyclic(cyclic);
wv_seconds.setCyclic(cyclic);
}
public String getTime() {
if (isLunarCalendar) {
//如果是农历 返回对应的公历时间
return getLunarTime();
}
StringBuilder sb = new StringBuilder();
if (currentYear == startYear) {
/* int i = wv_month.getCurrentItem() + startMonth;
System.out.println("i:" + i);*/
if ((wv_month.getCurrentItem() + startMonth) == startMonth) {
sb.append((wv_year.getCurrentItem() + startYear)).append("-")
.append((wv_month.getCurrentItem() + startMonth)).append("-")
.append((wv_day.getCurrentItem() + startDay)).append(" ")
.append(wv_hours.getCurrentItem()).append(":")
.append(wv_minutes.getCurrentItem()).append(":")
.append(wv_seconds.getCurrentItem());
} else {
sb.append((wv_year.getCurrentItem() + startYear)).append("-")
.append((wv_month.getCurrentItem() + startMonth)).append("-")
.append((wv_day.getCurrentItem() + 1)).append(" ")
.append(wv_hours.getCurrentItem()).append(":")
.append(wv_minutes.getCurrentItem()).append(":")
.append(wv_seconds.getCurrentItem());
}
} else {
if (wv_minutes.getItemsCount() == 4) {
sb.append((wv_year.getCurrentItem() + startYear)).append("-")
.append((wv_month.getCurrentItem() + 1)).append("-")
.append((wv_day.getCurrentItem() + 1)).append(" ")
.append(wv_hours.getCurrentItem()).append(":")
.append(mMinutes.get(wv_minutes.getCurrentItem())).append(":")
.append(wv_seconds.getCurrentItem());
} else {
sb.append((wv_year.getCurrentItem() + startYear)).append("-")
.append((wv_month.getCurrentItem() + 1)).append("-")
.append((wv_day.getCurrentItem() + 1)).append(" ")
.append(wv_hours.getCurrentItem()).append(":")
.append(wv_minutes.getCurrentItem()).append(":")
.append(wv_seconds.getCurrentItem());
}
}
return sb.toString();
}
/**
* 农历返回对应的公历时间
*
* @return
*/
private String getLunarTime() {
StringBuilder sb = new StringBuilder();
int year = wv_year.getCurrentItem() + startYear;
int month = 1;
boolean isLeapMonth = false;
if (ChinaDate.leapMonth(year) == 0) {
month = wv_month.getCurrentItem() + 1;
} else {
if ((wv_month.getCurrentItem() + 1) - ChinaDate.leapMonth(year) <= 0) {
month = wv_month.getCurrentItem() + 1;
} else if ((wv_month.getCurrentItem() + 1) - ChinaDate.leapMonth(year) == 1) {
month = wv_month.getCurrentItem();
isLeapMonth = true;
} else {
month = wv_month.getCurrentItem();
}
}
int day = wv_day.getCurrentItem() + 1;
int[] solar = LunarCalendar.lunarToSolar(year, month, day, isLeapMonth);
sb.append(solar[0]).append("-")
.append(solar[1]).append("-")
.append(solar[2]).append(" ")
.append(wv_hours.getCurrentItem()).append(":")
.append(wv_minutes.getCurrentItem()).append(":")
.append(wv_seconds.getCurrentItem());
return sb.toString();
}
public View getView() {
return view;
}
public void setView(View view) {
this.view = view;
}
public int getStartYear() {
return startYear;
}
public void setStartYear(int startYear) {
this.startYear = startYear;
}
public int getEndYear() {
return endYear;
}
public void setEndYear(int endYear) {
this.endYear = endYear;
}
public void setRangDate(Calendar startDate, Calendar endDate) {
if (startDate == null && endDate != null) {
int year = endDate.get(Calendar.YEAR);
int month = endDate.get(Calendar.MONTH) + 1;
int day = endDate.get(Calendar.DAY_OF_MONTH);
if (year > startYear) {
this.endYear = year;
this.endMonth = month;
this.endDay = day;
} else if (year == startYear) {
if (month > startMonth) {
this.endYear = year;
this.endMonth = month;
this.endDay = day;
} else if (month == startMonth) {
if (day > startDay) {
this.endYear = year;
this.endMonth = month;
this.endDay = day;
}
}
}
} else if (startDate != null && endDate == null) {
int year = startDate.get(Calendar.YEAR);
int month = startDate.get(Calendar.MONTH) + 1;
int day = startDate.get(Calendar.DAY_OF_MONTH);
if (year < endYear) {
this.startMonth = month;
this.startDay = day;
this.startYear = year;
} else if (year == endYear) {
if (month < endMonth) {
this.startMonth = month;
this.startDay = day;
this.startYear = year;
} else if (month == endMonth) {
if (day < endDay) {
this.startMonth = month;
this.startDay = day;
this.startYear = year;
}
}
}
} else if (startDate != null && endDate != null) {
this.startYear = startDate.get(Calendar.YEAR);
this.endYear = endDate.get(Calendar.YEAR);
this.startMonth = startDate.get(Calendar.MONTH) + 1;
this.endMonth = endDate.get(Calendar.MONTH) + 1;
this.startDay = startDate.get(Calendar.DAY_OF_MONTH);
this.endDay = endDate.get(Calendar.DAY_OF_MONTH);
}
}
/**
* 设置间距倍数,但是只能在1.0-4.0f之间
*
* @param lineSpacingMultiplier
*/
public void setLineSpacingMultiplier(float lineSpacingMultiplier) {
this.lineSpacingMultiplier = lineSpacingMultiplier;
setLineSpacingMultiplier();
}
/**
* 设置分割线的颜色
*
* @param dividerColor
*/
public void setDividerColor(int dividerColor) {
this.dividerColor = dividerColor;
setDividerColor();
}
/**
* 设置分割线的类型
*
* @param dividerType
*/
public void setDividerType(WheelView.DividerType dividerType) {
this.dividerType = dividerType;
setDividerType();
}
/**
* 设置分割线之间的文字的颜色
*
* @param textColorCenter
*/
public void setTextColorCenter(int textColorCenter) {
this.textColorCenter = textColorCenter;
setTextColorCenter();
}
/**
* 设置分割线以外文字的颜色
*
* @param textColorOut
*/
public void setTextColorOut(int textColorOut) {
this.textColorOut = textColorOut;
setTextColorOut();
}
/**
* @param isCenterLabel 是否只显示中间选中项的
*/
public void isCenterLabel(boolean isCenterLabel) {
wv_day.isCenterLabel(isCenterLabel);
wv_month.isCenterLabel(isCenterLabel);
wv_year.isCenterLabel(isCenterLabel);
wv_hours.isCenterLabel(isCenterLabel);
wv_minutes.isCenterLabel(isCenterLabel);
wv_seconds.isCenterLabel(isCenterLabel);
}
public void setSelectChangeCallback(ISelectTimeCallback mSelectChangeCallback) {
this.mSelectChangeCallback = mSelectChangeCallback;
}
}
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="@integer/animation_default_duration"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<scale
android:duration="@integer/animation_default_duration"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="@integer/animation_default_duration"
android:fromAlpha="1.0"
android:toAlpha="0.3" />
<scale
android:duration="@integer/animation_default_duration"
android:fromXScale="1.0"
android:toXScale="0.0"
android:fromYScale="1.0"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="@integer/animation_default_duration"
android:fromXDelta="0%"
android:toXDelta="0%"
android:fromYDelta="100%"
android:toYDelta="0%"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:duration="@integer/animation_default_duration"
android:fromXDelta="0%"
android:toXDelta="0%"
android:fromYDelta="0%"
android:toYDelta="100%"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@color/pickerview_timebtn_pre" />
<item android:color="@color/pickerview_timebtn_nor" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rv_topbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/pickerview_bg_topbar">
<Button
android:id="@+id/btnCancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:gravity="left|center_vertical"
android:paddingLeft="@dimen/pickerview_topbar_padding"
android:text="@string/pickerview_cancel"
android:textColor="@drawable/selector_pickerview_btn"
android:textSize="@dimen/pickerview_topbar_btn_textsize" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/btnSubmit"
android:layout_toRightOf="@+id/btnCancel"
android:textColor="@color/pickerview_topbar_title"
android:textSize="@dimen/pickerview_topbar_title_textsize" />
<Button
android:id="@id/btnSubmit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="@android:color/transparent"
android:gravity="right|center_vertical"
android:paddingRight="@dimen/pickerview_topbar_padding"
android:text="@string/pickerview_submit"
android:textColor="@drawable/selector_pickerview_btn"
android:textSize="@dimen/pickerview_topbar_btn_textsize" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/outmost_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:background="@color/pickerview_bgColor_overlay">
<FrameLayout
android:id="@+id/content_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</FrameLayout>
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
layout="@layout/include_pickerview_topbar"
android:layout_width="match_parent"
android:layout_height="@dimen/pickerview_topbar_height" />
<LinearLayout
android:id="@+id/optionspicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="horizontal">
<com.contrarywind.view.WheelView
android:id="@+id/options1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/options2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/options3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
layout="@layout/include_pickerview_topbar"
android:layout_width="match_parent"
android:layout_height="@dimen/pickerview_topbar_height" />
<LinearLayout
android:id="@+id/timepicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="horizontal">
<com.contrarywind.view.WheelView
android:id="@+id/year"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.96" />
<com.contrarywind.view.WheelView
android:id="@+id/month"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/day"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/hour"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/min"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.contrarywind.view.WheelView
android:id="@+id/second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<resources>
<string name="pickerview_cancel">Cancel</string>
<string name="pickerview_submit">Confirm</string>
<string name="pickerview_year"> </string>
<string name="pickerview_month"> </string>
<string name="pickerview_day"> </string>
<string name="pickerview_hours"> </string>
<string name="pickerview_minutes"> </string>
<string name="pickerview_seconds"> </string>
</resources>
<resources>
<!-- 顶部按钮栏高度 -->
<dimen name="pickerview_topbar_height">44dp</dimen>
<!-- 顶部按钮padding -->
<dimen name="pickerview_topbar_padding">20dp</dimen>
<!-- 顶部按钮文字大小 -->
<dimen name="pickerview_topbar_btn_textsize">17sp</dimen>
<dimen name="pickerview_topbar_title_textsize">18sp</dimen>
<!-- 选项文字大小 -->
<dimen name="pickerview_textsize">20sp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="animation_default_duration">300</integer>
</resources>
\ No newline at end of file
<resources>
<string name="pickerview_cancel">取消</string>
<string name="pickerview_submit">确定</string>
<string name="pickerview_year"></string>
<string name="pickerview_month"></string>
<string name="pickerview_day"></string>
<string name="pickerview_hours"></string>
<string name="pickerview_minutes"></string>
<string name="pickerview_seconds"></string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="custom_dialog2" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<!-- Dialog的windowFrame框为无 -->
<item name="android:windowIsFloating">true</item>
<!-- 是否漂现在activity上 -->
<item name="android:windowIsTranslucent">true</item>
<!-- 是否半透明 -->
<item name="android:windowNoTitle">true</item>
<item name="android:background">@null</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<!-- 去除黑色边框的关键设置项 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 屏幕背景是否变暗 -->
<item name="android:backgroundDimAmount">0.3</item>
</style>
<style name="picker_view_scale_anim" mce_bogus="1" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pickerview_dialog_scale_in</item>
<item name="android:windowExitAnimation">@anim/pickerview_dialog_scale_out</item>
</style>
<style name="picker_view_slide_anim" mce_bogus="1" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pickerview_slide_in_bottom</item>
<item name="android:windowExitAnimation">@anim/pickerview_slide_out_bottom</item>
</style>
</resources>
...@@ -4,4 +4,6 @@ include ':app', ...@@ -4,4 +4,6 @@ include ':app',
':messageCenter', ':messageCenter',
':userCenter', ':userCenter',
':orderCenter', ':orderCenter',
':locationComponent' ':locationComponent',
':pickerview',
':wheelview'
apply plugin: 'com.android.library'
//apply plugin: 'com.github.dcendents.android-maven'
//apply plugin: 'com.novoda.bintray-release'//添加插件
android {
compileSdkVersion compile_sdk_version
buildToolsVersion build_tools_version
defaultConfig {
minSdkVersion min_sdk_version
targetSdkVersion target_sdk_version
versionCode version_code
}
buildTypes {
release {
minifyEnabled isReleaseMinify
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
allprojects {
tasks.withType(Javadoc) {//兼容中文字符
options {
encoding "UTF-8"
charSet 'UTF-8'
links "http://docs.oracle.com/javase/7/docs/api"
}
}
}
//publish {
// userOrg = 'contrarywind'//bintray.com 用户名/组织名 user/org name
// groupId = 'com.contrarywind'//JCenter上显示的路径 path
// artifactId = 'wheelview'//项目名称 project name
// publishVersion = '4.0.5'//版本号 version code
// desc = 'this is a wheelview for android'//项目描述 description
// website = 'https://github.com/Bigkoo/Android-PickerView' //项目网址链接 link
//}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\song\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
package test.wheelview;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("test.wheelview.test", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.contrarywind.view">
<application android:allowBackup="true" android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>
package com.contrarywind.adapter;
public interface WheelAdapter<T> {
/**
* Gets items count
* @return the count of wheel items
*/
int getItemsCount();
/**
* Gets a wheel item by index.
* @param index the item index
* @return the wheel item text or null
*/
T getItem(int index);
/**
* Gets maximum item length. It is used to determine the wheel width.
* If -1 is returned there will be used the default wheel width.
* @param o the item object
* @return the maximum item length or -1
*/
int indexOf(T o);
}
package com.contrarywind.interfaces;
/**
* Created by Sai on 2016/7/13.
*/
public interface IPickerViewData {
String getPickerViewText();
}
package com.contrarywind.listener;
import android.view.MotionEvent;
import com.contrarywind.view.WheelView;
/**
* 手势监听
*/
public final class LoopViewGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
private final WheelView wheelView;
public LoopViewGestureListener(WheelView wheelView) {
this.wheelView = wheelView;
}
@Override
public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
wheelView.scrollBy(velocityY);
return true;
}
}
package com.contrarywind.listener;
public interface OnItemSelectedListener {
void onItemSelected(int index);
}
package com.contrarywind.timer;
import com.contrarywind.view.WheelView;
import java.util.TimerTask;
/**
* 滚动惯性的实现
*
* @author 小嵩
* date: 2017-12-23 23:20:44
*/
public final class InertiaTimerTask extends TimerTask {
private float mCurrentVelocityY; //当前滑动速度
private final float mFirstVelocityY;//手指离开屏幕时的初始速度
private final WheelView mWheelView;
/**
* @param wheelView 滚轮对象
* @param velocityY Y轴滑行速度
*/
public InertiaTimerTask(WheelView wheelView, float velocityY) {
super();
this.mWheelView = wheelView;
this.mFirstVelocityY = velocityY;
mCurrentVelocityY = Integer.MAX_VALUE;
}
@Override
public final void run() {
//防止闪动,对速度做一个限制。
if (mCurrentVelocityY == Integer.MAX_VALUE) {
if (Math.abs(mFirstVelocityY) > 2000F) {
mCurrentVelocityY = mFirstVelocityY > 0 ? 2000F : -2000F;
} else {
mCurrentVelocityY = mFirstVelocityY;
}
}
//发送handler消息 处理平顺停止滚动逻辑
if (Math.abs(mCurrentVelocityY) >= 0.0F && Math.abs(mCurrentVelocityY) <= 20F) {
mWheelView.cancelFuture();
mWheelView.getHandler().sendEmptyMessage(MessageHandler.WHAT_SMOOTH_SCROLL);
return;
}
int dy = (int) (mCurrentVelocityY / 100F);
mWheelView.setTotalScrollY(mWheelView.getTotalScrollY() - dy);
if (!mWheelView.isLoop()) {
float itemHeight = mWheelView.getItemHeight();
float top = (-mWheelView.getInitPosition()) * itemHeight;
float bottom = (mWheelView.getItemsCount() - 1 - mWheelView.getInitPosition()) * itemHeight;
if (mWheelView.getTotalScrollY() - itemHeight * 0.25 < top) {
top = mWheelView.getTotalScrollY() + dy;
} else if (mWheelView.getTotalScrollY() + itemHeight * 0.25 > bottom) {
bottom = mWheelView.getTotalScrollY() + dy;
}
if (mWheelView.getTotalScrollY() <= top) {
mCurrentVelocityY = 40F;
mWheelView.setTotalScrollY((int) top);
} else if (mWheelView.getTotalScrollY() >= bottom) {
mWheelView.setTotalScrollY((int) bottom);
mCurrentVelocityY = -40F;
}
}
if (mCurrentVelocityY < 0.0F) {
mCurrentVelocityY = mCurrentVelocityY + 20F;
} else {
mCurrentVelocityY = mCurrentVelocityY - 20F;
}
//刷新UI
mWheelView.getHandler().sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW);
}
}
package com.contrarywind.timer;
import android.os.Handler;
import android.os.Message;
import com.contrarywind.view.WheelView;
/**
* Handler 消息类
*
* @author 小嵩
* date: 2017-12-23 23:20:44
*/
public final class MessageHandler extends Handler {
public static final int WHAT_INVALIDATE_LOOP_VIEW = 1000;
public static final int WHAT_SMOOTH_SCROLL = 2000;
public static final int WHAT_ITEM_SELECTED = 3000;
private final WheelView wheelView;
public MessageHandler(WheelView wheelView) {
this.wheelView = wheelView;
}
@Override
public final void handleMessage(Message msg) {
switch (msg.what) {
case WHAT_INVALIDATE_LOOP_VIEW:
wheelView.invalidate();
break;
case WHAT_SMOOTH_SCROLL:
wheelView.smoothScroll(WheelView.ACTION.FLING);
break;
case WHAT_ITEM_SELECTED:
wheelView.onItemSelected();
break;
}
}
}
package com.contrarywind.timer;
import com.contrarywind.view.WheelView;
import java.util.TimerTask;
/**
* 平滑滚动的实现
*
* @author 小嵩
*/
public final class SmoothScrollTimerTask extends TimerTask {
private int realTotalOffset;
private int realOffset;
private int offset;
private final WheelView wheelView;
public SmoothScrollTimerTask(WheelView wheelView, int offset) {
this.wheelView = wheelView;
this.offset = offset;
realTotalOffset = Integer.MAX_VALUE;
realOffset = 0;
}
@Override
public final void run() {
if (realTotalOffset == Integer.MAX_VALUE) {
realTotalOffset = offset;
}
//把要滚动的范围细分成10小份,按10小份单位来重绘
realOffset = (int) ((float) realTotalOffset * 0.1F);
if (realOffset == 0) {
if (realTotalOffset < 0) {
realOffset = -1;
} else {
realOffset = 1;
}
}
if (Math.abs(realTotalOffset) <= 1) {
wheelView.cancelFuture();
wheelView.getHandler().sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED);
} else {
wheelView.setTotalScrollY(wheelView.getTotalScrollY() + realOffset);
//这里如果不是循环模式,则点击空白位置需要回滚,不然就会出现选到-1 item的 情况
if (!wheelView.isLoop()) {
float itemHeight = wheelView.getItemHeight();
float top = (float) (-wheelView.getInitPosition()) * itemHeight;
float bottom = (float) (wheelView.getItemsCount() - 1 - wheelView.getInitPosition()) * itemHeight;
if (wheelView.getTotalScrollY() <= top || wheelView.getTotalScrollY() >= bottom) {
wheelView.setTotalScrollY(wheelView.getTotalScrollY() - realOffset);
wheelView.cancelFuture();
wheelView.getHandler().sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED);
return;
}
}
wheelView.getHandler().sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW);
realTotalOffset = realTotalOffset - realOffset;
}
}
}
package com.contrarywind.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import com.contrarywind.adapter.WheelAdapter;
import com.contrarywind.interfaces.IPickerViewData;
import com.contrarywind.listener.LoopViewGestureListener;
import com.contrarywind.listener.OnItemSelectedListener;
import com.contrarywind.timer.InertiaTimerTask;
import com.contrarywind.timer.MessageHandler;
import com.contrarywind.timer.SmoothScrollTimerTask;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* 3d滚轮控件
*/
public class WheelView extends View {
public enum ACTION { // 点击,滑翔(滑到尽头),拖拽事件
CLICK, FLING, DAGGLE
}
public enum DividerType { // 分隔线类型
FILL, WRAP
}
private DividerType dividerType;//分隔线类型
private Context context;
private Handler handler;
private GestureDetector gestureDetector;
private OnItemSelectedListener onItemSelectedListener;
private boolean isOptions = false;
private boolean isCenterLabel = true;
// Timer mTimer;
private ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> mFuture;
private Paint paintOuterText;
private Paint paintCenterText;
private Paint paintIndicator;
private WheelAdapter adapter;
private String label;//附加单位
private int textSize;//选项的文字大小
private int maxTextWidth;
private int maxTextHeight;
private int textXOffset;
private float itemHeight;//每行高度
private Typeface typeface = Typeface.MONOSPACE;//字体样式,默认是等宽字体
private int textColorOut;
private int textColorCenter;
private int dividerColor;
// 条目间距倍数
private float lineSpacingMultiplier = 1.6F;
private boolean isLoop;
// 第一条线Y坐标值
private float firstLineY;
//第二条线Y坐标
private float secondLineY;
//中间label绘制的Y坐标
private float centerY;
//当前滚动总高度y值
private float totalScrollY;
//初始化默认选中项
private int initPosition;
//选中的Item是第几个
private int selectedItem;
private int preCurrentIndex;
//滚动偏移值,用于记录滚动了多少个item
private int change;
// 绘制几个条目,实际上第一项和最后一项Y轴压缩成0%了,所以可见的数目实际为9
private int itemsVisible = 11;
private int measuredHeight;// WheelView 控件高度
private int measuredWidth;// WheelView 控件宽度
// 半径
private int radius;
private int mOffset = 0;
private float previousY = 0;
private long startTime = 0;
// 修改这个值可以改变滑行速度
private static final int VELOCITY_FLING = 5;
private int widthMeasureSpec;
private int mGravity = Gravity.CENTER;
private int drawCenterContentStart = 0;//中间选中文字开始绘制位置
private int drawOutContentStart = 0;//非中间文字开始绘制位置
private static final float SCALE_CONTENT = 0.8F;//非中间文字则用此控制高度,压扁形成3d错觉
private float CENTER_CONTENT_OFFSET;//偏移量
private final float DEFAULT_TEXT_TARGET_SKEWX = 0.5f;
public WheelView(Context context) {
this(context, null);
}
public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
textSize = getResources().getDimensionPixelSize(R.dimen.pickerview_textsize);//默认大小
DisplayMetrics dm = getResources().getDisplayMetrics();
float density = dm.density; // 屏幕密度比(0.75/1.0/1.5/2.0/3.0)
if (density < 1) {//根据密度不同进行适配
CENTER_CONTENT_OFFSET = 2.4F;
} else if (1 <= density && density < 2) {
CENTER_CONTENT_OFFSET = 3.6F;
} else if (1 <= density && density < 2) {
CENTER_CONTENT_OFFSET = 4.5F;
} else if (2 <= density && density < 3) {
CENTER_CONTENT_OFFSET = 6.0F;
} else if (density >= 3) {
CENTER_CONTENT_OFFSET = density * 2.5F;
}
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.pickerview, 0, 0);
mGravity = a.getInt(R.styleable.pickerview_wheelview_gravity, Gravity.CENTER);
textColorOut = a.getColor(R.styleable.pickerview_wheelview_textColorOut, 0xFFa8a8a8);
textColorCenter = a.getColor(R.styleable.pickerview_wheelview_textColorCenter, 0xFF2a2a2a);
dividerColor = a.getColor(R.styleable.pickerview_wheelview_dividerColor, 0xFFd5d5d5);
textSize = a.getDimensionPixelOffset(R.styleable.pickerview_wheelview_textSize, textSize);
lineSpacingMultiplier = a.getFloat(R.styleable.pickerview_wheelview_lineSpacingMultiplier, lineSpacingMultiplier);
a.recycle();//回收内存
}
judgeLineSpace();
initLoopView(context);
}
/**
* 判断间距是否在1.0-4.0之间
*/
private void judgeLineSpace() {
if (lineSpacingMultiplier < 1.0f) {
lineSpacingMultiplier = 1.0f;
} else if (lineSpacingMultiplier > 4.0f) {
lineSpacingMultiplier = 4.0f;
}
}
private void initLoopView(Context context) {
this.context = context;
handler = new MessageHandler(this);
gestureDetector = new GestureDetector(context, new LoopViewGestureListener(this));
gestureDetector.setIsLongpressEnabled(false);
isLoop = true;
totalScrollY = 0;
initPosition = -1;
initPaints();
}
private void initPaints() {
paintOuterText = new Paint();
paintOuterText.setColor(textColorOut);
paintOuterText.setAntiAlias(true);
paintOuterText.setTypeface(typeface);
paintOuterText.setTextSize(textSize);
paintCenterText = new Paint();
paintCenterText.setColor(textColorCenter);
paintCenterText.setAntiAlias(true);
paintCenterText.setTextScaleX(1.1F);
paintCenterText.setTypeface(typeface);
paintCenterText.setTextSize(textSize);
paintIndicator = new Paint();
paintIndicator.setColor(dividerColor);
paintIndicator.setAntiAlias(true);
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
private void remeasure() {//重新测量
if (adapter == null) {
return;
}
measureTextWidthHeight();
//半圆的周长 = item高度乘以item数目-1
int halfCircumference = (int) (itemHeight * (itemsVisible - 1));
//整个圆的周长除以PI得到直径,这个直径用作控件的总高度
measuredHeight = (int) ((halfCircumference * 2) / Math.PI);
//求出半径
radius = (int) (halfCircumference / Math.PI);
//控件宽度,这里支持weight
measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
//计算两条横线 和 选中项画笔的基线Y位置
firstLineY = (measuredHeight - itemHeight) / 2.0F;
secondLineY = (measuredHeight + itemHeight) / 2.0F;
centerY = secondLineY - (itemHeight - maxTextHeight) / 2.0f - CENTER_CONTENT_OFFSET;
//初始化显示的item的position
if (initPosition == -1) {
if (isLoop) {
initPosition = (adapter.getItemsCount() + 1) / 2;
} else {
initPosition = 0;
}
}
preCurrentIndex = initPosition;
}
/**
* 计算最大length的Text的宽高度
*/
private void measureTextWidthHeight() {
Rect rect = new Rect();
for (int i = 0; i < adapter.getItemsCount(); i++) {
String s1 = getContentText(adapter.getItem(i));
paintCenterText.getTextBounds(s1, 0, s1.length(), rect);
int textWidth = rect.width();
if (textWidth > maxTextWidth) {
maxTextWidth = textWidth;
}
paintCenterText.getTextBounds("\u661F\u671F", 0, 2, rect); // 星期的字符编码(以它为标准高度)
maxTextHeight = rect.height() + 2;
}
itemHeight = lineSpacingMultiplier * maxTextHeight;
}
public void smoothScroll(ACTION action) {//平滑滚动的实现
cancelFuture();
if (action == ACTION.FLING || action == ACTION.DAGGLE) {
mOffset = (int) ((totalScrollY % itemHeight + itemHeight) % itemHeight);
if ((float) mOffset > itemHeight / 2.0F) {//如果超过Item高度的一半,滚动到下一个Item去
mOffset = (int) (itemHeight - (float) mOffset);
} else {
mOffset = -mOffset;
}
}
//停止的时候,位置有偏移,不是全部都能正确停止到中间位置的,这里把文字位置挪回中间去
mFuture = mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, mOffset), 0, 10, TimeUnit.MILLISECONDS);
}
public final void scrollBy(float velocityY) {//滚动惯性的实现
cancelFuture();
mFuture = mExecutor.scheduleWithFixedDelay(new InertiaTimerTask(this, velocityY), 0, VELOCITY_FLING, TimeUnit.MILLISECONDS);
}
public void cancelFuture() {
if (mFuture != null && !mFuture.isCancelled()) {
mFuture.cancel(true);
mFuture = null;
}
}
/**
* 设置是否循环滚动
*
* @param cyclic 是否循环
*/
public final void setCyclic(boolean cyclic) {
isLoop = cyclic;
}
public final void setTypeface(Typeface font) {
typeface = font;
paintOuterText.setTypeface(typeface);
paintCenterText.setTypeface(typeface);
}
public final void setTextSize(float size) {
if (size > 0.0F) {
textSize = (int) (context.getResources().getDisplayMetrics().density * size);
paintOuterText.setTextSize(textSize);
paintCenterText.setTextSize(textSize);
}
}
public final void setCurrentItem(int currentItem) {
//不添加这句,当这个wheelView不可见时,默认都是0,会导致获取到的时间错误
this.selectedItem = currentItem;
this.initPosition = currentItem;
totalScrollY = 0;//回归顶部,不然重设setCurrentItem的话位置会偏移的,就会显示出不对位置的数据
invalidate();
}
public final void setOnItemSelectedListener(OnItemSelectedListener OnItemSelectedListener) {
this.onItemSelectedListener = OnItemSelectedListener;
}
public final void setAdapter(WheelAdapter adapter) {
this.adapter = adapter;
remeasure();
invalidate();
}
public final WheelAdapter getAdapter() {
return adapter;
}
public final int getCurrentItem() {
return selectedItem;
}
public final void onItemSelected() {
if (onItemSelectedListener != null) {
postDelayed(new Runnable() {
@Override
public void run() {
onItemSelectedListener.onItemSelected(getCurrentItem());
}
}, 200L);
}
}
@Override
protected void onDraw(Canvas canvas) {
if (adapter == null) {
return;
}
//initPosition越界会造成preCurrentIndex的值不正确
initPosition = Math.min(Math.max(0, initPosition), adapter.getItemsCount() - 1);
//可见的item数组
@SuppressLint("DrawAllocation")
Object visibles[] = new Object[itemsVisible];
//滚动的Y值高度除去每行Item的高度,得到滚动了多少个item,即change数
change = (int) (totalScrollY / itemHeight);
// Log.d("change", "" + change);
try {
//滚动中实际的预选中的item(即经过了中间位置的item) = 滑动前的位置 + 滑动相对位置
preCurrentIndex = initPosition + change % adapter.getItemsCount();
} catch (ArithmeticException e) {
Log.e("WheelView", "出错了!adapter.getItemsCount() == 0,联动数据不匹配");
}
if (!isLoop) {//不循环的情况
if (preCurrentIndex < 0) {
preCurrentIndex = 0;
}
if (preCurrentIndex > adapter.getItemsCount() - 1) {
preCurrentIndex = adapter.getItemsCount() - 1;
}
} else {//循环
if (preCurrentIndex < 0) {//举个例子:如果总数是5,preCurrentIndex = -1,那么preCurrentIndex按循环来说,其实是0的上面,也就是4的位置
preCurrentIndex = adapter.getItemsCount() + preCurrentIndex;
}
if (preCurrentIndex > adapter.getItemsCount() - 1) {//同理上面,自己脑补一下
preCurrentIndex = preCurrentIndex - adapter.getItemsCount();
}
}
//跟滚动流畅度有关,总滑动距离与每个item高度取余,即并不是一格格的滚动,每个item不一定滚到对应Rect里的,这个item对应格子的偏移值
float itemHeightOffset = (totalScrollY % itemHeight);
// 设置数组中每个元素的值
int counter = 0;
while (counter < itemsVisible) {
int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值
//判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项
if (isLoop) {
index = getLoopMappingIndex(index);
visibles[counter] = adapter.getItem(index);
} else if (index < 0) {
visibles[counter] = "";
} else if (index > adapter.getItemsCount() - 1) {
visibles[counter] = "";
} else {
visibles[counter] = adapter.getItem(index);
}
counter++;
}
//绘制中间两条横线
if (dividerType == DividerType.WRAP) {//横线长度仅包裹内容
float startX;
float endX;
if (TextUtils.isEmpty(label)) {//隐藏Label的情况
startX = (measuredWidth - maxTextWidth) / 2 - 12;
} else {
startX = (measuredWidth - maxTextWidth) / 4 - 12;
}
if (startX <= 0) {//如果超过了WheelView的边缘
startX = 10;
}
endX = measuredWidth - startX;
canvas.drawLine(startX, firstLineY, endX, firstLineY, paintIndicator);
canvas.drawLine(startX, secondLineY, endX, secondLineY, paintIndicator);
} else {
canvas.drawLine(0.0F, firstLineY, measuredWidth, firstLineY, paintIndicator);
canvas.drawLine(0.0F, secondLineY, measuredWidth, secondLineY, paintIndicator);
}
//只显示选中项Label文字的模式,并且Label文字不为空,则进行绘制
if (!TextUtils.isEmpty(label) && isCenterLabel) {
//绘制文字,靠右并留出空隙
int drawRightContentStart = measuredWidth - getTextWidth(paintCenterText, label);
canvas.drawText(label, drawRightContentStart - CENTER_CONTENT_OFFSET, centerY, paintCenterText);
}
counter = 0;
while (counter < itemsVisible) {
canvas.save();
// 弧长 L = itemHeight * counter - itemHeightOffset
// 求弧度 α = L / r (弧长/半径) [0,π]
double radian = ((itemHeight * counter - itemHeightOffset)) / radius;
// 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限
// angle [-90°,90°]
float angle = (float) (90D - (radian / Math.PI) * 180D);//item第一项,从90度开始,逐渐递减到 -90度
// 计算取值可能有细微偏差,保证负90°到90°以外的不绘制
if (angle >= 90F || angle <= -90F) {
canvas.restore();
} else {
// 根据当前角度计算出偏差系数,用以在绘制时控制文字的 水平移动 透明度 倾斜程度
float offsetCoefficient = (float) Math.pow(Math.abs(angle) / 90f, 2.2);
//获取内容文字
String contentText;
//如果是label每项都显示的模式,并且item内容不为空、label 也不为空
if (!isCenterLabel && !TextUtils.isEmpty(label) && !TextUtils.isEmpty(getContentText(visibles[counter]))) {
contentText = getContentText(visibles[counter]) + label;
} else {
contentText = getContentText(visibles[counter]);
}
reMeasureTextSize(contentText);
//计算开始绘制的位置
measuredCenterContentStart(contentText);
measuredOutContentStart(contentText);
float translateY = (float) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D);
//根据Math.sin(radian)来更改canvas坐标系原点,然后缩放画布,使得文字高度进行缩放,形成弧形3d视觉差
canvas.translate(0.0F, translateY);
// canvas.scale(1.0F, (float) Math.sin(radian));
if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) {
// 条目经过第一条线
canvas.save();
canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
canvas.restore();
canvas.save();
canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText);
canvas.restore();
} else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) {
// 条目经过第二条线
canvas.save();
canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText);
canvas.restore();
canvas.save();
canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
canvas.restore();
} else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
// 中间条目
canvas.clipRect(0, 0, measuredWidth, maxTextHeight);
//让文字居中
float Y = maxTextHeight - CENTER_CONTENT_OFFSET;//因为圆弧角换算的向下取值,导致角度稍微有点偏差,加上画笔的基线会偏上,因此需要偏移量修正一下
canvas.drawText(contentText, drawCenterContentStart, Y, paintCenterText);
//设置选中项
selectedItem = preCurrentIndex - (itemsVisible / 2 - counter);
} else {
// 其他条目
canvas.save();
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
// 控制文字倾斜角度
paintOuterText.setTextSkewX((textXOffset == 0 ? 0 : (textXOffset > 0 ? 1 : -1)) * (angle > 0 ? -1 : 1) * DEFAULT_TEXT_TARGET_SKEWX * offsetCoefficient);
// 控制透明度
paintOuterText.setAlpha((int) ((1 - offsetCoefficient) * 255));
// 控制文字水平偏移距离
canvas.drawText(contentText, drawOutContentStart + textXOffset * offsetCoefficient, maxTextHeight, paintOuterText);
canvas.restore();
}
canvas.restore();
paintCenterText.setTextSize(textSize);
}
counter++;
}
}
/**
* reset the size of the text Let it can fully display
*
* @param contentText item text content.
*/
private void reMeasureTextSize(String contentText) {
Rect rect = new Rect();
paintCenterText.getTextBounds(contentText, 0, contentText.length(), rect);
int width = rect.width();
int size = textSize;
while (width > measuredWidth) {
size--;
//设置2条横线中间的文字大小
paintCenterText.setTextSize(size);
paintCenterText.getTextBounds(contentText, 0, contentText.length(), rect);
width = rect.width();
}
//设置2条横线外面的文字大小
paintOuterText.setTextSize(size);
}
//递归计算出对应的index
private int getLoopMappingIndex(int index) {
if (index < 0) {
index = index + adapter.getItemsCount();
index = getLoopMappingIndex(index);
} else if (index > adapter.getItemsCount() - 1) {
index = index - adapter.getItemsCount();
index = getLoopMappingIndex(index);
}
return index;
}
/**
* 获取所显示的数据源
*
* @param item data resource
* @return 对应显示的字符串
*/
private String getContentText(Object item) {
if (item == null) {
return "";
} else if (item instanceof IPickerViewData) {
return ((IPickerViewData) item).getPickerViewText();
} else if (item instanceof Integer) {
//如果为整形则最少保留两位数.
return String.format(Locale.getDefault(), "%02d", (int) item);
}
return item.toString();
}
private void measuredCenterContentStart(String content) {
Rect rect = new Rect();
paintCenterText.getTextBounds(content, 0, content.length(), rect);
switch (mGravity) {
case Gravity.CENTER://显示内容居中
if (isOptions || label == null || label.equals("") || !isCenterLabel) {
drawCenterContentStart = (int) ((measuredWidth - rect.width()) * 0.5);
} else {//只显示中间label时,时间选择器内容偏左一点,留出空间绘制单位标签
drawCenterContentStart = (int) ((measuredWidth - rect.width()) * 0.25);
}
break;
case Gravity.LEFT:
drawCenterContentStart = 0;
break;
case Gravity.RIGHT://添加偏移量
drawCenterContentStart = measuredWidth - rect.width() - (int) CENTER_CONTENT_OFFSET;
break;
}
}
private void measuredOutContentStart(String content) {
Rect rect = new Rect();
paintOuterText.getTextBounds(content, 0, content.length(), rect);
switch (mGravity) {
case Gravity.CENTER:
if (isOptions || label == null || label.equals("") || !isCenterLabel) {
drawOutContentStart = (int) ((measuredWidth - rect.width()) * 0.5);
} else {//只显示中间label时,时间选择器内容偏左一点,留出空间绘制单位标签
drawOutContentStart = (int) ((measuredWidth - rect.width()) * 0.25);
}
break;
case Gravity.LEFT:
drawOutContentStart = 0;
break;
case Gravity.RIGHT:
drawOutContentStart = measuredWidth - rect.width() - (int) CENTER_CONTENT_OFFSET;
break;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.widthMeasureSpec = widthMeasureSpec;
remeasure();
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean eventConsumed = gestureDetector.onTouchEvent(event);
boolean isIgnore = false;//超过边界滑动时,不再绘制UI。
float top = -initPosition * itemHeight;
float bottom = (adapter.getItemsCount() - 1 - initPosition) * itemHeight;
float ratio = 0.25f;
switch (event.getAction()) {
//按下
case MotionEvent.ACTION_DOWN:
startTime = System.currentTimeMillis();
cancelFuture();
previousY = event.getRawY();
break;
//滑动中
case MotionEvent.ACTION_MOVE:
float dy = previousY - event.getRawY();
previousY = event.getRawY();
totalScrollY = totalScrollY + dy;
// 非循环模式下,边界处理。
if (!isLoop) {
if ((totalScrollY - itemHeight * ratio < top && dy < 0)
|| (totalScrollY + itemHeight * ratio > bottom && dy > 0)) {
//快滑动到边界了,设置已滑动到边界的标志
totalScrollY -= dy;
isIgnore = true;
}/* else if (totalScrollY + itemHeight * ratio > bottom && dy > 0) {
totalScrollY -= dy;
isIgnore = true;
} */else {
isIgnore = false;
}
}
break;
case MotionEvent.ACTION_UP:
default:
if (!eventConsumed) {//未消费掉事件
/**
*@describe <关于弧长的计算>
*
* 弧长公式: L = α*R
* 反余弦公式:arccos(cosα) = α
* 由于之前是有顺时针偏移90度,
* 所以实际弧度范围α2的值 :α2 = π/2-α (α=[0,π] α2 = [-π/2,π/2])
* 根据正弦余弦转换公式 cosα = sin(π/2-α)
* 代入,得: cosα = sin(π/2-α) = sinα2 = (R - y) / R
* 所以弧长 L = arccos(cosα)*R = arccos((R - y) / R)*R
*/
float y = event.getY();
double L = Math.acos((radius - y) / radius) * radius;
//item0 有一半是在不可见区域,所以需要加上 itemHeight / 2
int circlePosition = (int) ((L + itemHeight / 2) / itemHeight);
float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight;
//已滑动的弧长值
mOffset = (int) ((circlePosition - itemsVisible / 2) * itemHeight - extraOffset);
if ((System.currentTimeMillis() - startTime) > 120) {
// 处理拖拽事件
smoothScroll(ACTION.DAGGLE);
} else {
// 处理条目点击事件
smoothScroll(ACTION.CLICK);
}
}
break;
}
if (!isIgnore && event.getAction() != MotionEvent.ACTION_DOWN) {
invalidate();
}
return true;
}
/**
* 获取Item个数
*
* @return item个数
*/
public int getItemsCount() {
return adapter != null ? adapter.getItemsCount() : 0;
}
/**
* 附加在右边的单位字符串
*
* @param label 单位
*/
public void setLabel(String label) {
this.label = label;
}
public void isCenterLabel(boolean isCenterLabel) {
this.isCenterLabel = isCenterLabel;
}
public void setGravity(int gravity) {
this.mGravity = gravity;
}
public int getTextWidth(Paint paint, String str) {//计算文字宽度
int iRet = 0;
if (str != null && str.length() > 0) {
int len = str.length();
float[] widths = new float[len];
paint.getTextWidths(str, widths);
for (int j = 0; j < len; j++) {
iRet += (int) Math.ceil(widths[j]);
}
}
return iRet;
}
public void setIsOptions(boolean options) {
isOptions = options;
}
public void setTextColorOut(int textColorOut) {
if (textColorOut != 0) {
this.textColorOut = textColorOut;
paintOuterText.setColor(this.textColorOut);
}
}
public void setTextColorCenter(int textColorCenter) {
if (textColorCenter != 0) {
this.textColorCenter = textColorCenter;
paintCenterText.setColor(this.textColorCenter);
}
}
public void setTextXOffset(int textXOffset) {
this.textXOffset = textXOffset;
if (textXOffset != 0) {
paintCenterText.setTextScaleX(1.0f);
}
}
public void setDividerColor(int dividerColor) {
if (dividerColor != 0) {
this.dividerColor = dividerColor;
paintIndicator.setColor(this.dividerColor);
}
}
public void setDividerType(DividerType dividerType) {
this.dividerType = dividerType;
}
public void setLineSpacingMultiplier(float lineSpacingMultiplier) {
if (lineSpacingMultiplier != 0) {
this.lineSpacingMultiplier = lineSpacingMultiplier;
judgeLineSpace();
}
}
public boolean isLoop() {
return isLoop;
}
public float getTotalScrollY() {
return totalScrollY;
}
public void setTotalScrollY(float totalScrollY) {
this.totalScrollY = totalScrollY;
}
public float getItemHeight() {
return itemHeight;
}
public void setItemHeight(float itemHeight) {
this.itemHeight = itemHeight;
}
public int getInitPosition() {
return initPosition;
}
public void setInitPosition(int initPosition) {
this.initPosition = initPosition;
}
@Override
public Handler getHandler() {
return handler;
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="pickerview">
<attr name="wheelview_gravity">
<enum name="center" value="17"/>
<enum name="left" value="3"/>
<enum name="right" value="5"/>
</attr>
<attr name="wheelview_textSize" format="dimension"/>
<attr name="wheelview_textColorOut" format="color"/>
<attr name="wheelview_textColorCenter" format="color"/>
<attr name="wheelview_dividerColor" format="color"/>
<attr name="wheelview_lineSpacingMultiplier" format="float"/>
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="pickerview_timebtn_nor">#057dff</color>
<color name="pickerview_timebtn_pre">#c2daf5</color>
<color name="pickerview_bg_topbar">#f5f5f5</color>
<color name="pickerview_topbar_title">#000000</color>
<color name="pickerview_wheelview_textcolor_out">#a8a8a8</color>
<color name="pickerview_wheelview_textcolor_center">#2a2a2a</color>
<color name="pickerview_wheelview_textcolor_divider">#d5d5d5</color>
<color name="pickerview_bgColor_overlay">#60000000</color>
<color name="pickerview_bgColor_default">#FFFFFFFF</color>
</resources>
<resources>
<!-- 顶部按钮栏高度 -->
<dimen name="pickerview_topbar_height">44dp</dimen>
<!-- 顶部按钮padding -->
<dimen name="pickerview_topbar_padding">20dp</dimen>
<!-- 顶部按钮文字大小 -->
<dimen name="pickerview_topbar_btn_textsize">17sp</dimen>
<dimen name="pickerview_topbar_title_textsize">18sp</dimen>
<!-- 选项文字大小 -->
<dimen name="pickerview_textsize">20sp</dimen>
</resources>
<resources>
<string name="app_name">wheelview</string>
</resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment