Initial commit

This commit is contained in:
linglongxin24
2016-06-14 13:49:26 +08:00
commit ceed245fb3
154 changed files with 16198 additions and 0 deletions

2
library/WheelPicker/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/build
/*.iml

View File

@@ -0,0 +1,11 @@
apply plugin: 'com.android.library'
ext {
isLibrary = true
pomArtifactId = "WheelPicker"
pomDescription = "wheel picker for android, include date picker, time picker, option picker, address picker, etc."
}
dependencies {
compile project(":library:Common")
}

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="cn.qqtheme.framework.wheelpicker" />

View File

@@ -0,0 +1,358 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import java.util.ArrayList;
import cn.qqtheme.framework.util.LogUtils;
import cn.qqtheme.framework.widget.WheelView;
/**
* 地址选择器(包括省级、地级、县级)。
* 地址数据见示例项目的“city.json”来源于国家统计局官网http://www.stats.gov.cn/tjsj/tjbz/xzqhdm
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/15
*/
public class AddressPicker extends WheelPicker {
private ArrayList<String> provinceList = new ArrayList<String>();
private ArrayList<ArrayList<String>> cityList = new ArrayList<ArrayList<String>>();
private ArrayList<ArrayList<ArrayList<String>>> countyList = new ArrayList<ArrayList<ArrayList<String>>>();
private OnAddressPickListener onAddressPickListener;
private String selectedProvince = "", selectedCity = "", selectedCounty = "";
private int selectedProvinceIndex = 0, selectedCityIndex = 0, selectedCountyIndex = 0;
private boolean hideProvince = false;
private boolean hideCounty = false;
/**
* Instantiates a new Address picker.
*
* @param activity the activity
* @param data the data
*/
public AddressPicker(Activity activity, ArrayList<Province> data) {
super(activity);
int provinceSize = data.size();
//添加省
for (int x = 0; x < provinceSize; x++) {
Province pro = data.get(x);
provinceList.add(pro.getAreaName());
ArrayList<City> cities = pro.getCities();
ArrayList<String> xCities = new ArrayList<String>();
ArrayList<ArrayList<String>> xCounties = new ArrayList<ArrayList<String>>();
int citySize = cities.size();
//添加地市
for (int y = 0; y < citySize; y++) {
City cit = cities.get(y);
xCities.add(cit.getAreaName());
ArrayList<County> counties = cit.getCounties();
ArrayList<String> yCounties = new ArrayList<String>();
int countySize = counties.size();
//添加区县
if (countySize == 0) {
yCounties.add(cit.getAreaName());
} else {
for (int z = 0; z < countySize; z++) {
yCounties.add(counties.get(z).getAreaName());
}
}
xCounties.add(yCounties);
}
cityList.add(xCities);
countyList.add(xCounties);
}
}
/**
* Sets selected item.
*
* @param province the province
* @param city the city
* @param county the county
*/
public void setSelectedItem(String province, String city, String county) {
for (int i = 0; i < provinceList.size(); i++) {
String pro = provinceList.get(i);
if (pro.contains(province)) {
selectedProvinceIndex = i;
LogUtils.debug("init select province: " + pro);
break;
}
}
ArrayList<String> cities = cityList.get(selectedProvinceIndex);
for (int j = 0; j < cities.size(); j++) {
String cit = cities.get(j);
if (cit.contains(city)) {
selectedCityIndex = j;
LogUtils.debug("init select city: " + cit);
break;
}
}
ArrayList<String> counties = countyList.get(selectedProvinceIndex).get(selectedCityIndex);
for (int k = 0; k < counties.size(); k++) {
String cou = counties.get(k);
if (cou.contains(county)) {
selectedCountyIndex = k;
LogUtils.debug("init select county: " + cou);
break;
}
}
LogUtils.debug(String.format("init select index: %s-%s-%s", selectedProvinceIndex, selectedCityIndex, selectedCountyIndex));
}
/**
* 隐藏省级行政区,只显示地市级和区县级。
* 设置为true的话地址数据中只需要某个省份的即可
* 参见示例中的“city2.json”
*
* @param hideProvince the hide province
*/
public void setHideProvince(boolean hideProvince) {
this.hideProvince = hideProvince;
}
/**
* 隐藏县级行政区,只显示省级和市级。
* 设置为true的话hideProvince将强制为false
* 数据源依然使用“city.json” 仅在逻辑上隐藏县级选择框。
*
* @param hideCounty the hide county
*/
public void setHideCounty(boolean hideCounty) {
this.hideCounty = hideCounty;
}
/**
* Sets on address pick listener.
*
* @param listener the listener
*/
public void setOnAddressPickListener(OnAddressPickListener listener) {
this.onAddressPickListener = listener;
}
@Override
@NonNull
protected View makeCenterView() {
if (hideCounty) {
hideProvince = false;
}
if (provinceList.size() == 0) {
throw new IllegalArgumentException("please initial options at first, can't be empty");
}
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
final WheelView provinceView = new WheelView(activity);
provinceView.setLayoutParams(new LinearLayout.LayoutParams(screenWidthPixels / 3, WRAP_CONTENT));
provinceView.setTextSize(textSize);
provinceView.setTextColor(textColorNormal, textColorFocus);
provinceView.setLineVisible(lineVisible);
provinceView.setLineColor(lineColor);
provinceView.setOffset(offset);
layout.addView(provinceView);
if (hideProvince) {
provinceView.setVisibility(View.GONE);
}
final WheelView cityView = new WheelView(activity);
cityView.setLayoutParams(new LinearLayout.LayoutParams(screenWidthPixels / 3, WRAP_CONTENT));
cityView.setTextSize(textSize);
cityView.setTextColor(textColorNormal, textColorFocus);
cityView.setLineVisible(lineVisible);
cityView.setLineColor(lineColor);
cityView.setOffset(offset);
layout.addView(cityView);
final WheelView countyView = new WheelView(activity);
countyView.setLayoutParams(new LinearLayout.LayoutParams(screenWidthPixels / 3, WRAP_CONTENT));
countyView.setTextSize(textSize);
countyView.setTextColor(textColorNormal, textColorFocus);
countyView.setLineVisible(lineVisible);
countyView.setLineColor(lineColor);
countyView.setOffset(offset);
layout.addView(countyView);
if (hideCounty) {
countyView.setVisibility(View.GONE);
}
provinceView.setItems(provinceList, selectedProvinceIndex);
provinceView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedProvince = item;
selectedProvinceIndex = selectedIndex;
selectedCountyIndex = 0;
//根据省份获取地市
cityView.setItems(cityList.get(selectedProvinceIndex), isUserScroll ? 0 : selectedCityIndex);
//根据地市获取区县
countyView.setItems(countyList.get(selectedProvinceIndex).get(0), isUserScroll ? 0 : selectedCountyIndex);
}
});
cityView.setItems(cityList.get(selectedProvinceIndex), selectedCityIndex);
cityView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedCity = item;
selectedCityIndex = selectedIndex;
//根据地市获取区县
countyView.setItems(countyList.get(selectedProvinceIndex).get(selectedCityIndex), isUserScroll ? 0 : selectedCountyIndex);
}
});
countyView.setItems(countyList.get(selectedProvinceIndex).get(selectedCityIndex), selectedCountyIndex);
countyView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedCounty = item;
selectedCountyIndex = selectedIndex;
}
});
return layout;
}
@Override
public void onSubmit() {
if (onAddressPickListener != null) {
if (hideCounty) {
onAddressPickListener.onAddressPicked(selectedProvince, selectedCity, null);
} else {
onAddressPickListener.onAddressPicked(selectedProvince, selectedCity, selectedCounty);
}
}
}
/**
* The interface On address pick listener.
*/
public interface OnAddressPickListener {
/**
* On address picked.
*
* @param province the province
* @param city the city
* @param county the county if {@hideCounty} is truethis is null
*/
void onAddressPicked(String province, String city, String county);
}
/**
* The type Area.
*/
public abstract static class Area {
/**
* The Area id.
*/
String areaId;
/**
* The Area name.
*/
String areaName;
/**
* Gets area id.
*
* @return the area id
*/
public String getAreaId() {
return areaId;
}
/**
* Sets area id.
*
* @param areaId the area id
*/
public void setAreaId(String areaId) {
this.areaId = areaId;
}
/**
* Gets area name.
*
* @return the area name
*/
public String getAreaName() {
return areaName;
}
/**
* Sets area name.
*
* @param areaName the area name
*/
public void setAreaName(String areaName) {
this.areaName = areaName;
}
@Override
public String toString() {
return "areaId=" + areaId + ",areaName=" + areaName;
}
}
/**
* The type Province.
*/
public static class Province extends Area {
/**
* The Cities.
*/
ArrayList<City> cities = new ArrayList<City>();
/**
* Gets cities.
*
* @return the cities
*/
public ArrayList<City> getCities() {
return cities;
}
/**
* Sets cities.
*
* @param cities the cities
*/
public void setCities(ArrayList<City> cities) {
this.cities = cities;
}
}
/**
* The type City.
*/
public static class City extends Area {
private ArrayList<County> counties = new ArrayList<County>();
/**
* Gets counties.
*
* @return the counties
*/
public ArrayList<County> getCounties() {
return counties;
}
/**
* Sets counties.
*
* @param counties the counties
*/
public void setCounties(ArrayList<County> counties) {
this.counties = counties;
}
}
/**
* The type County.
*/
public static class County extends Area {
}
}

View File

@@ -0,0 +1,35 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
/**
* 生肖选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/15
*/
public class ChineseZodiacPicker extends OptionPicker {
/**
* Instantiates a new Chinese zodiac picker.
*
* @param activity the activity
*/
public ChineseZodiacPicker(Activity activity) {
super(activity, new String[]{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
});
}
}

View File

@@ -0,0 +1,36 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
/**
* 星座选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/15
*/
public class ConstellationPicker extends OptionPicker {
/**
* Instantiates a new Constellation picker.
*
* @param activity the activity
*/
public ConstellationPicker(Activity activity) {
super(activity, new String[]{
"水瓶",
"双鱼",
"白羊",
"金牛",
"双子",
"巨蟹",
"狮子",
"处女",
"天秤",
"天蝎",
"射手",
"摩羯",
});
setLabel("");
}
}

View File

@@ -0,0 +1,414 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import cn.qqtheme.framework.util.DateUtils;
import cn.qqtheme.framework.widget.WheelView;
/**
* 日期选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/14
*/
public class DatePicker extends WheelPicker {
/**
* 年月日
*/
public static final int YEAR_MONTH_DAY = 0;
/**
* 年月
*/
public static final int YEAR_MONTH = 1;
/**
* 月日
*/
public static final int MONTH_DAY = 2;
private ArrayList<String> years = new ArrayList<String>();
private ArrayList<String> months = new ArrayList<String>();
private ArrayList<String> days = new ArrayList<String>();
private OnDatePickListener onDatePickListener;
private String yearLabel = "", monthLabel = "", dayLabel = "";
private int selectedYearIndex = 0, selectedMonthIndex = 0, selectedDayIndex = 0;
private int mode = YEAR_MONTH_DAY;
/**
* 安卓开发应避免使用枚举类enum因为相比于静态常量enum会花费两倍以上的内存。
*
* @link http ://developer.android.com/training/articles/memory.html#Overhead
*/
@IntDef(flag = false, value = {YEAR_MONTH_DAY, YEAR_MONTH, MONTH_DAY})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
/**
* Instantiates a new Date picker.
*
* @param activity the activity
*/
public DatePicker(Activity activity) {
this(activity, YEAR_MONTH_DAY);
}
/**
* Instantiates a new Date picker.
*
* @param activity the activity
* @param mode the mode
* @see #YEAR_MONTH_DAY #YEAR_MONTH_DAY#YEAR_MONTH_DAY
* @see #YEAR_MONTH #YEAR_MONTH#YEAR_MONTH
* @see #MONTH_DAY #MONTH_DAY#MONTH_DAY
*/
public DatePicker(Activity activity, @Mode int mode) {
super(activity);
this.mode = mode;
for (int i = 2000; i <= 2050; i++) {
years.add(String.valueOf(i));
}
for (int i = 1; i <= 12; i++) {
months.add(DateUtils.fillZero(i));
}
for (int i = 1; i <= 31; i++) {
days.add(DateUtils.fillZero(i));
}
}
/**
* Sets label.
*
* @param yearLabel the year label
* @param monthLabel the month label
* @param dayLabel the day label
*/
public void setLabel(String yearLabel, String monthLabel, String dayLabel) {
this.yearLabel = yearLabel;
this.monthLabel = monthLabel;
this.dayLabel = dayLabel;
}
/**
* Sets range.
*
* @param startYear the start year
* @param endYear the end year
*/
public void setRange(int startYear, int endYear) {
years.clear();
for (int i = startYear; i <= endYear; i++) {
years.add(String.valueOf(i));
}
}
private int findItemIndex(ArrayList<String> items, int item) {
//折半查找有序元素的索引
int index = Collections.binarySearch(items, item, new Comparator<Object>() {
@Override
public int compare(Object lhs, Object rhs) {
String lhsStr = lhs.toString();
String rhsStr = rhs.toString();
lhsStr = lhsStr.startsWith("0") ? lhsStr.substring(1) : lhsStr;
rhsStr = rhsStr.startsWith("0") ? rhsStr.substring(1) : rhsStr;
return Integer.parseInt(lhsStr) - Integer.parseInt(rhsStr);
}
});
if (index < 0) {
index = 0;
}
return index;
}
/**
* Sets selected item.
*
* @param year the year
* @param month the month
* @param day the day
*/
public void setSelectedItem(int year, int month, int day) {
selectedYearIndex = findItemIndex(years, year);
selectedMonthIndex = findItemIndex(months, month);
selectedDayIndex = findItemIndex(days, day);
}
/**
* Sets selected item.
*
* @param yearOrMonth the year or month
* @param monthOrDay the month or day
*/
public void setSelectedItem(int yearOrMonth, int monthOrDay) {
if (mode == MONTH_DAY) {
selectedMonthIndex = findItemIndex(months, yearOrMonth);
selectedDayIndex = findItemIndex(days, monthOrDay);
} else {
selectedYearIndex = findItemIndex(years, yearOrMonth);
selectedMonthIndex = findItemIndex(months, monthOrDay);
}
}
/**
* Sets on date pick listener.
*
* @param listener the listener
*/
public void setOnDatePickListener(OnDatePickListener listener) {
this.onDatePickListener = listener;
}
@Override
@NonNull
protected View makeCenterView() {
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
WheelView yearView = new WheelView(activity);
yearView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
yearView.setTextSize(textSize);
yearView.setTextColor(textColorNormal, textColorFocus);
yearView.setLineVisible(lineVisible);
yearView.setLineColor(lineColor);
yearView.setOffset(offset);
layout.addView(yearView);
TextView yearTextView = new TextView(activity);
yearTextView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
yearTextView.setTextSize(textSize);
yearTextView.setTextColor(textColorFocus);
if (!TextUtils.isEmpty(yearLabel)) {
yearTextView.setText(yearLabel);
}
layout.addView(yearTextView);
WheelView monthView = new WheelView(activity);
monthView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
monthView.setTextSize(textSize);
monthView.setTextColor(textColorNormal, textColorFocus);
monthView.setLineVisible(lineVisible);
monthView.setLineColor(lineColor);
monthView.setOffset(offset);
layout.addView(monthView);
TextView monthTextView = new TextView(activity);
monthTextView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
monthTextView.setTextSize(textSize);
monthTextView.setTextColor(textColorFocus);
if (!TextUtils.isEmpty(monthLabel)) {
monthTextView.setText(monthLabel);
}
layout.addView(monthTextView);
final WheelView dayView = new WheelView(activity);
dayView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
dayView.setTextSize(textSize);
dayView.setTextColor(textColorNormal, textColorFocus);
dayView.setLineVisible(lineVisible);
dayView.setLineColor(lineColor);
dayView.setOffset(offset);
layout.addView(dayView);
TextView dayTextView = new TextView(activity);
dayTextView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
dayTextView.setTextSize(textSize);
dayTextView.setTextColor(textColorFocus);
if (!TextUtils.isEmpty(dayLabel)) {
dayTextView.setText(dayLabel);
}
layout.addView(dayTextView);
if (mode == YEAR_MONTH) {
dayView.setVisibility(View.GONE);
dayTextView.setVisibility(View.GONE);
} else if (mode == MONTH_DAY) {
yearView.setVisibility(View.GONE);
yearTextView.setVisibility(View.GONE);
}
if (mode != MONTH_DAY) {
if (!TextUtils.isEmpty(yearLabel)) {
yearTextView.setText(yearLabel);
}
if (selectedYearIndex == 0) {
yearView.setItems(years);
} else {
yearView.setItems(years, selectedYearIndex);
}
yearView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedYearIndex = selectedIndex;
//需要根据年份及月份动态计算天数
days.clear();
int maxDays = DateUtils.calculateDaysInMonth(stringToYearMonthDay(item), stringToYearMonthDay(months.get(selectedMonthIndex)));
for (int i = 1; i <= maxDays; i++) {
days.add(DateUtils.fillZero(i));
}
if (selectedDayIndex >= maxDays) {
//年或月变动时,保持之前选择的日不动:如果之前选择的日是之前年月的最大日,则日自动为该年月的最大日
selectedDayIndex = days.size() - 1;
}
dayView.setItems(days, selectedDayIndex);
}
});
}
if (!TextUtils.isEmpty(monthLabel)) {
monthTextView.setText(monthLabel);
}
if (selectedMonthIndex == 0) {
monthView.setItems(months);
} else {
monthView.setItems(months, selectedMonthIndex);
}
monthView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedMonthIndex = selectedIndex;
if (mode != YEAR_MONTH) {
//年月日或年月模式下,需要根据年份及月份动态计算天数
days.clear();
int maxDays = DateUtils.calculateDaysInMonth(stringToYearMonthDay(years.get(selectedYearIndex)), stringToYearMonthDay(item));
for (int i = 1; i <= maxDays; i++) {
days.add(DateUtils.fillZero(i));
}
if (selectedDayIndex >= maxDays) {
//年或月变动时,保持之前选择的日不动:如果之前选择的日是之前年月的最大日,则日自动为该年月的最大日
selectedDayIndex = days.size() - 1;
}
dayView.setItems(days, selectedDayIndex);
}
}
});
if (mode != YEAR_MONTH) {
if (!TextUtils.isEmpty(dayLabel)) {
dayTextView.setText(dayLabel);
}
if (selectedDayIndex == 0) {
dayView.setItems(days);
} else {
dayView.setItems(days, selectedDayIndex);
}
dayView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedDayIndex = selectedIndex;
}
});
}
return layout;
}
private int stringToYearMonthDay(String text) {
if (text.startsWith("0")) {
//截取掉前缀0以便转换为整数
text = text.substring(1);
}
return Integer.parseInt(text);
}
@Override
protected void onSubmit() {
if (onDatePickListener != null) {
String year = getSelectedYear();
String month = getSelectedMonth();
String day = getSelectedDay();
switch (mode) {
case YEAR_MONTH:
((OnYearMonthPickListener) onDatePickListener).onDatePicked(year, month);
break;
case MONTH_DAY:
((OnMonthDayPickListener) onDatePickListener).onDatePicked(month, day);
break;
default:
((OnYearMonthDayPickListener) onDatePickListener).onDatePicked(year, month, day);
break;
}
}
}
/**
* Gets selected year.
*
* @return the selected year
*/
public String getSelectedYear() {
return years.get(selectedYearIndex);
}
/**
* Gets selected month.
*
* @return the selected month
*/
public String getSelectedMonth() {
return months.get(selectedMonthIndex);
}
/**
* Gets selected day.
*
* @return the selected day
*/
public String getSelectedDay() {
return days.get(selectedDayIndex);
}
/**
* The interface On date pick listener.
*/
protected interface OnDatePickListener {
}
/**
* The interface On year month day pick listener.
*/
public interface OnYearMonthDayPickListener extends OnDatePickListener {
/**
* On date picked.
*
* @param year the year
* @param month the month
* @param day the day
*/
void onDatePicked(String year, String month, String day);
}
/**
* The interface On year month pick listener.
*/
public interface OnYearMonthPickListener extends OnDatePickListener {
/**
* On date picked.
*
* @param year the year
* @param month the month
*/
void onDatePicked(String year, String month);
}
/**
* The interface On month day pick listener.
*/
public interface OnMonthDayPickListener extends OnDatePickListener {
/**
* On date picked.
*
* @param month the month
* @param day the day
*/
void onDatePicked(String month, String day);
}
}

View File

@@ -0,0 +1,370 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import cn.qqtheme.framework.util.LogUtils;
import cn.qqtheme.framework.widget.WheelView;
/**
* 地址选择器(包括省级、地级、县级)。
* 地址数据见示例项目的“city.json”来源于国家统计局官网http://www.stats.gov.cn/tjsj/tjbz/xzqhdm
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/15
*/
public class MyTimePicker extends WheelPicker {
private ArrayList<String> provinceList = new ArrayList<String>();
private ArrayList<String> cityList = new ArrayList<String>();
private ArrayList<String> countyList = new ArrayList<String>();
private OnAddressPickListener onAddressPickListener;
private String selectedProvince = "", selectedCity = "", selectedCounty = "";
private int selectedProvinceIndex = 0, selectedCityIndex = 0, selectedCountyIndex = 0;
private boolean hideProvince = false;
private boolean hideCounty = false;
//
// /**
// * Instantiates a new Address picker.
// *
// * @param activity the activity
// * @param data the data
// */
// public MyTimePicker(Activity activity, ArrayList<String> provinceList,ArrayList<String> cityList ,ArrayList<String> countyList) {
// super(activity);
//
//// int provinceSize = data.size();
//// //添加省
//// for (int x = 0; x < provinceSize; x++) {
//// Province pro = data.get(x);
//// provinceList.add(pro.getAreaName());
//// ArrayList<City> cities = pro.getCities();
//// ArrayList<String> xCities = new ArrayList<String>();
//// ArrayList<ArrayList<String>> xCounties = new ArrayList<ArrayList<String>>();
//// int citySize = cities.size();
//// //添加地市
//// for (int y = 0; y < citySize; y++) {
//// City cit = cities.get(y);
//// xCities.add(cit.getAreaName());
//// ArrayList<County> counties = cit.getCounties();
//// ArrayList<String> yCounties = new ArrayList<String>();
//// int countySize = counties.size();
//// //添加区县
//// if (countySize == 0) {
//// yCounties.add(cit.getAreaName());
//// } else {
//// for (int z = 0; z < countySize; z++) {
//// yCounties.add(counties.get(z).getAreaName());
//// }
//// }
//// xCounties.add(yCounties);
//// }
//// cityList.add(xCities);
//// countyList.add(xCounties);
//// }
// }
public MyTimePicker(Activity activity, ArrayList<String> provinceList, ArrayList<String> cityList, ArrayList<String> countyList) {
super(activity);
this.provinceList = provinceList;
this.cityList = cityList;
this.countyList = countyList;
}
/**
* Sets selected item.
*
* @param selectedProvinceIndex the province
* @param selectedCityIndex the city
* @param selectedCountyIndex the county
*/
public void setSelectedItem(int selectedProvinceIndex, int selectedCityIndex,int selectedCountyIndex) {
this.selectedProvinceIndex=selectedProvinceIndex;
this.selectedCityIndex=selectedCityIndex;
this.selectedCountyIndex=selectedCountyIndex;
// LogUtils.debug(String.format("init select index: %s-%s-%s", selectedProvinceIndex, selectedCityIndex, selectedCountyIndex));
}
/**
* 隐藏省级行政区,只显示地市级和区县级。
* 设置为true的话地址数据中只需要某个省份的即可
* 参见示例中的“city2.json”
*
* @param hideProvince the hide province
*/
public void setHideProvince(boolean hideProvince) {
this.hideProvince = hideProvince;
}
/**
* 隐藏县级行政区,只显示省级和市级。
* 设置为true的话hideProvince将强制为false
* 数据源依然使用“city.json” 仅在逻辑上隐藏县级选择框。
*
* @param hideCounty the hide county
*/
public void setHideCounty(boolean hideCounty) {
this.hideCounty = hideCounty;
}
/**
* Sets on address pick listener.
*
* @param listener the listener
*/
public void setOnAddressPickListener(OnAddressPickListener listener) {
this.onAddressPickListener = listener;
}
@Override
@NonNull
protected View makeCenterView() {
if (hideCounty) {
hideProvince = false;
}
if (provinceList.size() == 0) {
throw new IllegalArgumentException("please initial options at first, can't be empty");
}
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
final WheelView provinceView = new WheelView(activity);
provinceView.setLayoutParams(new LinearLayout.LayoutParams(screenWidthPixels / 3, WRAP_CONTENT));
provinceView.setTextSize(textSize);
provinceView.setTextColor(textColorNormal, textColorFocus);
provinceView.setLineVisible(lineVisible);
provinceView.setLineColor(lineColor);
provinceView.setOffset(offset);
layout.addView(provinceView);
if (hideProvince) {
provinceView.setVisibility(View.GONE);
}
final WheelView cityView = new WheelView(activity);
cityView.setLayoutParams(new LinearLayout.LayoutParams(screenWidthPixels / 3, WRAP_CONTENT));
cityView.setTextSize(textSize);
cityView.setTextColor(textColorNormal, textColorFocus);
cityView.setLineVisible(lineVisible);
cityView.setLineColor(lineColor);
cityView.setOffset(offset);
layout.addView(cityView);
final WheelView countyView = new WheelView(activity);
countyView.setLayoutParams(new LinearLayout.LayoutParams(screenWidthPixels / 3, WRAP_CONTENT));
countyView.setTextSize(textSize);
countyView.setTextColor(textColorNormal, textColorFocus);
countyView.setLineVisible(lineVisible);
countyView.setLineColor(lineColor);
countyView.setOffset(offset);
layout.addView(countyView);
if (hideCounty) {
countyView.setVisibility(View.GONE);
}
provinceView.setItems(provinceList, selectedProvinceIndex);
provinceView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedProvince = item;
selectedProvinceIndex = selectedIndex;
if(0==selectedIndex){
cityView.setItems(cityList.subList(getSelectHours(),cityList.size()),0);
countyView.setItems(countyList.subList(getSelectMinutes(),countyList.size()),0);
}else{
cityView.setItems(cityList,selectedCityIndex);
countyView.setItems(countyList, selectedCountyIndex);
}
//根据省份获取地市
// cityView.setItems(cityList, isUserScroll ? 0 : selectedCityIndex);
// //根据地市获取区县
// countyView.setItems(countyList, isUserScroll ? 0 : selectedCountyIndex);
}
});
// cityView.setItems(cityList,selectedCityIndex);
cityView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedCity = item;
selectedCityIndex = selectedIndex;
//根据地市获取区县
// countyView.setItems(countyList, isUserScroll ? 0 : selectedCountyIndex);
}
});
// countyView.setItems(countyList, selectedCountyIndex);
countyView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedCounty = item;
selectedCountyIndex = selectedIndex;
System.out.println("selectedCountyIndex="+selectedCountyIndex);
}
});
return layout;
}
private int getSelectHours() {
SimpleDateFormat sdf = new SimpleDateFormat("HH时");
Calendar c = Calendar.getInstance();
Date monday = c.getTime();
String preMonday = sdf.format(monday);
return cityList.indexOf(preMonday);
}
private int getSelectMinutes() {
SimpleDateFormat sdf = new SimpleDateFormat("mm分");
Calendar c = Calendar.getInstance();
Date monday = c.getTime();
String preMonday = sdf.format(monday);
return countyList.indexOf(preMonday);
}
@Override
public void onSubmit() {
if (onAddressPickListener != null) {
if (hideCounty) {
onAddressPickListener.onAddressPicked(selectedProvince, selectedCity, null);
} else {
onAddressPickListener.onAddressPicked(selectedProvince, selectedCity, selectedCounty);
}
}
}
/**
* The interface On address pick listener.
*/
public interface OnAddressPickListener {
/**
* On address picked.
*
* @param province the province
* @param city the city
* @param county the county if {@hideCounty} is truethis is null
*/
void onAddressPicked(String province, String city, String county);
}
/**
* The type Area.
*/
public abstract static class Area {
/**
* The Area id.
*/
String areaId;
/**
* The Area name.
*/
String areaName;
/**
* Gets area id.
*
* @return the area id
*/
public String getAreaId() {
return areaId;
}
/**
* Sets area id.
*
* @param areaId the area id
*/
public void setAreaId(String areaId) {
this.areaId = areaId;
}
/**
* Gets area name.
*
* @return the area name
*/
public String getAreaName() {
return areaName;
}
/**
* Sets area name.
*
* @param areaName the area name
*/
public void setAreaName(String areaName) {
this.areaName = areaName;
}
@Override
public String toString() {
return "areaId=" + areaId + ",areaName=" + areaName;
}
}
/**
* The type Province.
*/
public static class Province extends Area {
/**
* The Cities.
*/
ArrayList<City> cities = new ArrayList<City>();
/**
* Gets cities.
*
* @return the cities
*/
public ArrayList<City> getCities() {
return cities;
}
/**
* Sets cities.
*
* @param cities the cities
*/
public void setCities(ArrayList<City> cities) {
this.cities = cities;
}
}
/**
* The type City.
*/
public static class City extends Area {
private ArrayList<County> counties = new ArrayList<County>();
/**
* Gets counties.
*
* @return the counties
*/
public ArrayList<County> getCounties() {
return counties;
}
/**
* Sets counties.
*
* @param counties the counties
*/
public void setCounties(ArrayList<County> counties) {
this.counties = counties;
}
}
/**
* The type County.
*/
public static class County extends Area {
}
}

View File

@@ -0,0 +1,55 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
/**
* 数字选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /10/24
*/
public class NumberPicker extends OptionPicker {
/**
* Instantiates a new Number picker.
*
* @param activity the activity
*/
public NumberPicker(Activity activity) {
super(activity, new String[]{});
}
/**
* Sets range.
*
* @param startNumber the start number
* @param endNumber the end number
*/
public void setRange(int startNumber, int endNumber) {
setRange(startNumber, endNumber, 1);
}
/**
* Sets range.
*
* @param startNumber the start number
* @param endNumber the end number
* @param step the step
*/
public void setRange(int startNumber, int endNumber, int step) {
for (int i = startNumber; i <= endNumber; i = i + step) {
options.add(String.valueOf(i));
}
}
/**
* Sets selected item.
*
* @param number the number
*/
public void setSelectedItem(int number) {
setSelectedItem(String.valueOf(number));
}
}

View File

@@ -0,0 +1,152 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import cn.qqtheme.framework.widget.WheelView;
/**
* 单项选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /9/29
*/
public class OptionPicker extends WheelPicker {
/**
* The Options.
*/
protected ArrayList<String> options = new ArrayList<String>();
private OnOptionPickListener onOptionPickListener;
private String selectedOption = "";
private String label = "";
/**
* Instantiates a new Option picker.
*
* @param activity the activity
* @param options the options
*/
public OptionPicker(Activity activity, String[] options) {
super(activity);
this.options.addAll(Arrays.asList(options));
}
/**
* Sets label.
*
* @param label the label
*/
public void setLabel(String label) {
this.label = label;
}
/**
* Sets selected index.
*
* @param index the index
*/
public void setSelectedIndex(int index) {
for (int i = 0; i < options.size(); i++) {
if (index == i) {
selectedOption = options.get(index);
break;
}
}
}
/**
* Sets selected item.
*
* @param option the option
*/
public void setSelectedItem(String option) {
selectedOption = option;
}
/**
* Sets on option pick listener.
*
* @param listener the listener
*/
public void setOnOptionPickListener(OnOptionPickListener listener) {
this.onOptionPickListener = listener;
}
@Override
@NonNull
protected View makeCenterView() {
if (options.size() == 0) {
throw new IllegalArgumentException("please initial options at first, can't be empty");
}
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
WheelView optionView = new WheelView(activity);
optionView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
optionView.setTextSize(textSize);
optionView.setTextColor(textColorNormal, textColorFocus);
optionView.setLineVisible(lineVisible);
optionView.setLineColor(lineColor);
optionView.setOffset(offset);
layout.addView(optionView);
TextView labelView = new TextView(activity);
labelView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
labelView.setTextColor(textColorFocus);
labelView.setTextSize(textSize);
layout.addView(labelView);
if (!TextUtils.isEmpty(label)) {
labelView.setText(label);
}
if (TextUtils.isEmpty(selectedOption)) {
optionView.setItems(options);
} else {
optionView.setItems(options, selectedOption);
}
optionView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedOption = item;
}
});
return layout;
}
@Override
public void onSubmit() {
if (onOptionPickListener != null) {
onOptionPickListener.onOptionPicked(selectedOption);
}
}
/**
* Gets selected option.
*
* @return the selected option
*/
public String getSelectedOption() {
return selectedOption;
}
/**
* The interface On option pick listener.
*/
public interface OnOptionPickListener {
/**
* On option picked.
*
* @param option the option
*/
void onOptionPicked(String option);
}
}

View File

@@ -0,0 +1,33 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
/**
* 性别
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/15
*/
public class SexPicker extends OptionPicker {
/**
* Instantiates a new Sex picker.
*
* @param activity the activity
*/
public SexPicker(Activity activity) {
super(activity, new String[]{
"",
"",
"保密"
});
}
/**
* 仅仅提供男和女来选择
*/
public void onlyMaleAndFemale() {
options.remove(options.size() - 1);
}
}

View File

@@ -0,0 +1,213 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Calendar;
import cn.qqtheme.framework.util.DateUtils;
import cn.qqtheme.framework.widget.WheelView;
/**
* 时间选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/14
*/
public class TimePicker extends WheelPicker {
/**
* 24小时
*/
public static final int HOUR_OF_DAY = 0;
/**
* 12小时
*/
public static final int HOUR = 1;
private OnTimePickListener onTimePickListener;
private int mode;
private String hourLabel = "", minuteLabel = "";
private String selectedHour = "", selectedMinute = "";
/**
* 安卓开发应避免使用枚举类enum因为相比于静态常量enum会花费两倍以上的内存。
*
* @link http ://developer.android.com/training/articles/memory.html#Overhead
*/
@IntDef(flag = false, value = {HOUR_OF_DAY, HOUR})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
/**
* Instantiates a new Time picker.
*
* @param activity the activity
*/
public TimePicker(Activity activity) {
this(activity, HOUR_OF_DAY);
}
/**
* Instantiates a new Time picker.
*
* @param activity the activity
* @param mode the mode
* @see #HOUR_OF_DAY #HOUR_OF_DAY#HOUR_OF_DAY
* @see #HOUR #HOUR#HOUR
*/
public TimePicker(Activity activity, @Mode int mode) {
super(activity);
this.mode = mode;
selectedHour = DateUtils.fillZero(Calendar.getInstance().get(Calendar.HOUR_OF_DAY));
selectedMinute = DateUtils.fillZero(Calendar.getInstance().get(Calendar.MINUTE));
}
/**
* Sets label.
*
* @param hourLabel the hour label
* @param minuteLabel the minute label
*/
public void setLabel(String hourLabel, String minuteLabel) {
this.hourLabel = hourLabel;
this.minuteLabel = minuteLabel;
}
/**
* Sets selected item.
*
* @param hour the hour
* @param minute the minute
*/
public void setSelectedItem(int hour, int minute) {
selectedHour = String.valueOf(hour);
selectedMinute = String.valueOf(minute);
}
/**
* Sets on time pick listener.
*
* @param listener the listener
*/
public void setOnTimePickListener(OnTimePickListener listener) {
this.onTimePickListener = listener;
}
@Override
@NonNull
protected View makeCenterView() {
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
WheelView hourView = new WheelView(activity);
hourView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
hourView.setTextSize(textSize);
hourView.setTextColor(textColorNormal, textColorFocus);
hourView.setLineVisible(lineVisible);
hourView.setLineColor(lineColor);
layout.addView(hourView);
TextView hourTextView = new TextView(activity);
hourTextView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
hourTextView.setTextSize(textSize);
hourTextView.setTextColor(textColorFocus);
if (!TextUtils.isEmpty(hourLabel)) {
hourTextView.setText(hourLabel);
}
layout.addView(hourTextView);
WheelView minuteView = new WheelView(activity);
minuteView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
minuteView.setTextSize(textSize);
minuteView.setTextColor(textColorNormal, textColorFocus);
minuteView.setLineVisible(lineVisible);
minuteView.setLineColor(lineColor);
minuteView.setOffset(offset);
layout.addView(minuteView);
TextView minuteTextView = new TextView(activity);
minuteTextView.setLayoutParams(new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
minuteTextView.setTextSize(textSize);
minuteTextView.setTextColor(textColorFocus);
if (!TextUtils.isEmpty(minuteLabel)) {
minuteTextView.setText(minuteLabel);
}
layout.addView(minuteTextView);
ArrayList<String> hours = new ArrayList<String>();
if (mode == HOUR) {
for (int i = 1; i <= 12; i++) {
hours.add(DateUtils.fillZero(i));
}
} else {
for (int i = 0; i < 24; i++) {
hours.add(DateUtils.fillZero(i));
}
}
hourView.setItems(hours, selectedHour);
ArrayList<String> minutes = new ArrayList<String>();
for (int i = 0; i < 60; i++) {
minutes.add(DateUtils.fillZero(i));
}
minuteView.setItems(minutes, selectedMinute);
hourView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedHour = item;
}
});
minuteView.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(boolean isUserScroll, int selectedIndex, String item) {
selectedMinute = item;
}
});
return layout;
}
@Override
public void onSubmit() {
if (onTimePickListener != null) {
onTimePickListener.onTimePicked(selectedHour, selectedMinute);
}
}
/**
* Gets selected hour.
*
* @return the selected hour
*/
public String getSelectedHour() {
return selectedHour;
}
/**
* Gets selected minute.
*
* @return the selected minute
*/
public String getSelectedMinute() {
return selectedMinute;
}
/**
* The interface On time pick listener.
*/
public interface OnTimePickListener {
/**
* On time picked.
*
* @param hour the hour
* @param minute the minute
*/
void onTimePicked(String hour, String minute);
}
}

View File

@@ -0,0 +1,108 @@
package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
import android.view.View;
import cn.qqtheme.framework.popup.ConfirmPopup;
import cn.qqtheme.framework.widget.WheelView;
/**
* 滑轮选择器
*
* @author 李玉江[QQ :1032694760]
* @version 2015 /12/22
*/
public abstract class WheelPicker extends ConfirmPopup<View> {
/**
* The Text size.
*/
protected int textSize = WheelView.TEXT_SIZE;
/**
* The Text color normal.
*/
protected int textColorNormal = WheelView.TEXT_COLOR_NORMAL;
/**
* The Text color focus.
*/
protected int textColorFocus = WheelView.TEXT_COLOR_FOCUS;
/**
* The Line color.
*/
protected int lineColor = WheelView.LINE_COLOR;
/**
* The Line visible.
*/
protected boolean lineVisible = true;
/**
* The Offset.
*/
protected int offset = WheelView.OFF_SET;
/**
* Instantiates a new Wheel picker.
*
* @param activity the activity
*/
public WheelPicker(Activity activity) {
super(activity);
}
/**
* Sets text size.
*
* @param textSize the text size
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
}
/**
* Sets text color.
*
* @param textColorFocus the text color focus
* @param textColorNormal the text color normal
*/
public void setTextColor(@ColorInt int textColorFocus, @ColorInt int textColorNormal) {
this.textColorFocus = textColorFocus;
this.textColorNormal = textColorNormal;
}
/**
* Sets text color.
*
* @param textColor the text color
*/
public void setTextColor(@ColorInt int textColor) {
this.textColorFocus = textColor;
}
/**
* Sets line visible.
*
* @param lineVisible the line visible
*/
public void setLineVisible(boolean lineVisible) {
this.lineVisible = lineVisible;
}
/**
* Sets line color.
*
* @param lineColor the line color
*/
public void setLineColor(@ColorInt int lineColor) {
this.lineColor = lineColor;
}
/**
* Sets offset.
*
* @param offset the offset
*/
public void setOffset(@IntRange(from = 1, to = 4) int offset) {
this.offset = offset;
}
}

View File

@@ -0,0 +1,617 @@
package cn.qqtheme.framework.widget;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import cn.qqtheme.framework.util.LogUtils;
/**
* 基于原版作了一下修改:
* 去掉回弹阴影
* 修正以便支持联动效果
* 可设置颜色
* 设置文字大小
* 分隔线是否可见
* 初始设置选中选项
*
* @author 李玉江[QQ :1023694760]
* @version 2015 -12-17
* @link https ://github.com/wangjiegulu/WheelView
*/
public class WheelView extends ScrollView {
/**
* The constant TEXT_SIZE.
*/
public static final int TEXT_SIZE = 20;
/**
* The constant TEXT_COLOR_FOCUS.
*/
public static final int TEXT_COLOR_FOCUS = 0XFF0288CE;
/**
* The constant TEXT_COLOR_NORMAL.
*/
public static final int TEXT_COLOR_NORMAL = 0XFFBBBBBB;
/**
* The constant LINE_COLOR.
*/
public static final int LINE_COLOR = 0XFF83CDE6;
/**
* The constant OFF_SET.
*/
public static final int OFF_SET = 1;
private static final int DELAY = 50;
private Context context;
private LinearLayout views;
private List<String> items = new ArrayList<String>();
private int offset = OFF_SET; // 偏移量(需要在最前面和最后面补全)
private int displayItemCount; // 每页显示的数量
private int selectedIndex = OFF_SET;
private int initialY;
private Runnable scrollerTask = new ScrollerTask();
private int itemHeight = 0;
private int[] selectedAreaBorder;//获取选中区域的边界
private OnWheelViewListener onWheelViewListener;
private Paint paint;
private int viewWidth;
private int textSize = TEXT_SIZE;
private int textColorNormal = TEXT_COLOR_NORMAL;
private int textColorFocus = TEXT_COLOR_FOCUS;
private int lineColor = LINE_COLOR;
private boolean lineVisible = true;
private boolean isUserScroll = false;//是否用户手动滚动
private float previousY = 0;//记录按下时的Y坐标
/**
* Instantiates a new Wheel view.
*
* @param context the context
*/
public WheelView(Context context) {
super(context);
init(context);
}
/**
* Instantiates a new Wheel view.
*
* @param context the context
* @param attrs the attrs
*/
public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* Instantiates a new Wheel view.
*
* @param context the context
* @param attrs the attrs
* @param defStyle the def style
*/
public WheelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
this.context = context;
// 2015/12/15 去掉ScrollView的阴影
setFadingEdgeLength(0);
if (Build.VERSION.SDK_INT >= 9) {
setOverScrollMode(OVER_SCROLL_NEVER);
}
setVerticalScrollBarEnabled(false);
views = new LinearLayout(context);
views.setOrientation(LinearLayout.VERTICAL);
addView(views);
}
private void startScrollerTask() {
initialY = getScrollY();
postDelayed(scrollerTask, DELAY);
}
private void initData() {
displayItemCount = offset * 2 + 1;
// 2015/12/15 添加此句才可以支持联动效果
views.removeAllViews();
for (String item : items) {
views.addView(createView(item));
}
// 2016/1/15 焦点文字颜色高亮位置逆推“int position = y / itemHeight + offset”
refreshItemView(itemHeight * (selectedIndex - offset));
}
private TextView createView(String item) {
TextView tv = new TextView(context);
tv.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
tv.setSingleLine(true);
tv.setEllipsize(TextUtils.TruncateAt.END);
tv.setText(item);
tv.setTextSize(textSize);
tv.setGravity(Gravity.CENTER);
int padding = dip2px(15);
tv.setPadding(padding, padding, padding, padding);
if (0 == itemHeight) {
itemHeight = getViewMeasuredHeight(tv);
LogUtils.debug(this, "itemHeight: " + itemHeight);
views.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemHeight * displayItemCount));
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.getLayoutParams();
setLayoutParams(new LinearLayout.LayoutParams(lp.width, itemHeight * displayItemCount));
}
return tv;
}
private void refreshItemView(int y) {
int position = y / itemHeight + offset;
int remainder = y % itemHeight;
int divided = y / itemHeight;
if (remainder == 0) {
position = divided + offset;
} else {
if (remainder > itemHeight / 2) {
position = divided + offset + 1;
}
}
int childSize = views.getChildCount();
for (int i = 0; i < childSize; i++) {
TextView itemView = (TextView) views.getChildAt(i);
if (null == itemView) {
return;
}
// 2015/12/15 可设置颜色
if (position == i) {
itemView.setTextColor(textColorFocus);
} else {
itemView.setTextColor(textColorNormal);
}
}
}
private int[] obtainSelectedAreaBorder() {
if (null == selectedAreaBorder) {
selectedAreaBorder = new int[2];
selectedAreaBorder[0] = itemHeight * offset;
selectedAreaBorder[1] = itemHeight * (offset + 1);
}
return selectedAreaBorder;
}
/**
* 选中回调
*/
private void onSelectedCallBack() {
if (null != onWheelViewListener) {
// 2015/12/25 真实的index应该忽略偏移量
onWheelViewListener.onSelected(isUserScroll, selectedIndex - offset, items.get(selectedIndex));
}
}
private int dip2px(float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
private int getViewMeasuredHeight(View view) {
int width = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
view.measure(width, expandSpec);
return view.getMeasuredHeight();
}
@Override
public void setBackground(Drawable background) {
setBackgroundDrawable(background);
}
@SuppressWarnings("deprecation")
@Override
public void setBackgroundDrawable(Drawable background) {
if (viewWidth == 0) {
viewWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();
LogUtils.debug(this, "viewWidth: " + viewWidth);
}
// 2015/12/22 可设置分隔线是否可见
if (!lineVisible) {
return;
}
if (null == paint) {
paint = new Paint();
paint.setColor(lineColor);
paint.setStrokeWidth(dip2px(1f));
}
background = new Drawable() {
@Override
public void draw(Canvas canvas) {
int[] areaBorder = obtainSelectedAreaBorder();
canvas.drawLine(0, areaBorder[0], viewWidth , areaBorder[0], paint);
canvas.drawLine(0, areaBorder[1], viewWidth , areaBorder[1], paint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return 0;
}
};
super.setBackgroundDrawable(background);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
refreshItemView(t);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
LogUtils.debug(this, "w: " + w + ", h: " + h + ", oldw: " + oldw + ", oldh: " + oldh);
viewWidth = w;
setBackgroundDrawable(null);
}
@Override
public void fling(int velocityY) {
super.fling(velocityY / 3);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
previousY = ev.getY();
break;
case MotionEvent.ACTION_UP:
LogUtils.debug(this, String.format("items=%s, offset=%s", items.size(), offset));
LogUtils.debug(this, "selectedIndex=" + selectedIndex);
float delta = ev.getY() - previousY;
LogUtils.debug(this, "delta=" + delta);
if (selectedIndex == offset && delta > 0) {
//滑动到第一项时,若继续向下滑动,则自动跳到最后一项
setSelectedIndex(items.size() - offset * 2 - 1);
} else if (selectedIndex == items.size() - offset - 1 && delta < 0) {
//滑动到最后一项时,若继续向上滑动,则自动跳到第一项
setSelectedIndex(0);
} else {
isUserScroll = true;
startScrollerTask();
}
break;
}
return super.onTouchEvent(ev);
}
private void _setItems(List<String> list) {
items.clear();
items.addAll(list);
// 前面和后面补全
for (int i = 0; i < offset; i++) {
items.add(0, "");
items.add("");
}
initData();
}
/**
* Sets items.
*
* @param list the list
*/
public void setItems(List<String> list) {
_setItems(list);
// 2015/12/25 初始化时设置默认选中项
setSelectedIndex(0);
}
/**
* Sets items.
*
* @param list the list
* @param index the index
*/
public void setItems(List<String> list, int index) {
_setItems(list);
setSelectedIndex(index);
}
/**
* Sets items.
*
* @param list the list
* @param item the item
*/
public void setItems(List<String> list, String item) {
_setItems(list);
setSelectedItem(item);
}
/**
* Gets text size.
*
* @return the text size
*/
public int getTextSize() {
return textSize;
}
/**
* Sets text size.
*
* @param textSize the text size
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
}
/**
* Gets text color.
*
* @return the text color
*/
public int getTextColor() {
return textColorFocus;
}
/**
* Sets text color.
*
* @param textColorNormal the text color normal
* @param textColorFocus the text color focus
*/
public void setTextColor(@ColorInt int textColorNormal, @ColorInt int textColorFocus) {
this.textColorNormal = textColorNormal;
this.textColorFocus = textColorFocus;
}
/**
* Sets text color.
*
* @param textColor the text color
*/
public void setTextColor(@ColorInt int textColor) {
this.textColorFocus = textColor;
}
/**
* Is line visible boolean.
*
* @return the boolean
*/
public boolean isLineVisible() {
return lineVisible;
}
/**
* Sets line visible.
*
* @param lineVisible the line visible
*/
public void setLineVisible(boolean lineVisible) {
this.lineVisible = lineVisible;
}
/**
* Gets line color.
*
* @return the line color
*/
public int getLineColor() {
return lineColor;
}
/**
* Sets line color.
*
* @param lineColor the line color
*/
public void setLineColor(@ColorInt int lineColor) {
this.lineColor = lineColor;
}
/**
* Gets offset.
*
* @return the offset
*/
public int getOffset() {
return offset;
}
/**
* Sets offset.
*
* @param offset the offset
*/
public void setOffset(int offset) {
if (offset < 1 || offset > 4) {
throw new IllegalArgumentException("Offset must between 1 and 4");
}
this.offset = offset;
}
/**
* 从0开始计数所有项包括偏移量
*
* @param index
*/
private void setSelectedIndex(final int index) {
isUserScroll = false;
this.post(new Runnable() {
@Override
public void run() {
//滚动到选中项的位置
smoothScrollTo(0, index * itemHeight);
//选中这一项的值
selectedIndex = index + offset;
onSelectedCallBack();
}
});
}
/**
* Sets selected item.
*
* @param item the item
*/
public void setSelectedItem(String item) {
for (int i = 0; i < items.size(); i++) {
if (items.get(i).equals(item)) {
//调用_setItems(List)时额外添加了offset个占位符到items里需要忽略占位符所占的位
setSelectedIndex(i - offset);
break;
}
}
}
/**
* Use {@link #getSelectedItem()} instead
*/
@Deprecated
public String getSeletedItem() {
return getSelectedItem();
}
/**
* Gets selected item.
*
* @return the selected item
*/
public String getSelectedItem() {
return items.get(selectedIndex);
}
/**
* Use {@link #getSelectedIndex()} instead
*/
@Deprecated
public int getSeletedIndex() {
return getSelectedIndex();
}
/**
* Gets selected index.
*
* @return the selected index
*/
public int getSelectedIndex() {
return selectedIndex - offset;
}
/**
* Sets on wheel view listener.
*
* @param onWheelViewListener the on wheel view listener
*/
public void setOnWheelViewListener(OnWheelViewListener onWheelViewListener) {
this.onWheelViewListener = onWheelViewListener;
}
/**
* The interface On wheel view listener.
*/
public interface OnWheelViewListener {
/**
* On selected.
*
* @param isUserScroll the is user scroll
* @param selectedIndex the selected index
* @param item the item
*/
void onSelected(boolean isUserScroll, int selectedIndex, String item);
}
private class ScrollerTask implements Runnable {
@Override
public void run() {
// 2015/12/17 java.lang.ArithmeticException: divide by zero
if (itemHeight == 0) {
LogUtils.debug(this, "itemHeight is zero");
return;
}
int newY = getScrollY();
if (initialY - newY == 0) { // stopped
final int remainder = initialY % itemHeight;
final int divided = initialY / itemHeight;
LogUtils.debug(this, "initialY: " + initialY + ", remainder: " + remainder + ", divided: " + divided);
if (remainder == 0) {
selectedIndex = divided + offset;
onSelectedCallBack();
} else {
if (remainder > itemHeight / 2) {
post(new Runnable() {
@Override
public void run() {
smoothScrollTo(0, initialY - remainder + itemHeight);
selectedIndex = divided + offset + 1;
onSelectedCallBack();
}
});
} else {
post(new Runnable() {
@Override
public void run() {
smoothScrollTo(0, initialY - remainder);
selectedIndex = divided + offset;
onSelectedCallBack();
}
});
}
}
} else {
startScrollerTask();
}
}
}
}