Android-PickerView【仿iOS的PickerView控件,并封装了时间选择和选项选择这两种选择器】使用
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
本文主要演示Android-PickerView的选项选择器、时间选择器的简单运用。由于每一个版本略有不用,所以实际使用方式以github项目wiki文档为准。
效果图
代码分析
本文使用的版本是compile 'com.contrarywind:Android-PickerView:4.1.4';
时间选择器搭配DateTimeHelper使用;
需要执行setDecorView方法,否则底部虚拟导航栏会显示在弹出的选择器区域;
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
在APP中的bundle.gradle文件中添加以下代码,引入Android-PickerView控件
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.why.project.pickerviewdemo"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
//PickerView
compile 'com.contrarywind:Android-PickerView:4.1.4'
}
三、使用方法
在colors.xml文件中添加以下代码
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <!-- **************************pickerview选择器常用颜色值********************************** --> <color name="pickerview_divider_color">#9D9D9D</color> <color name="pickerview_cancel_text_color">#979696</color> <color name="pickerview_submit_text_color">#FAA359</color> <color name="pickerview_title_text_color">#1A78EC</color> <color name="pickerview_center_text_color">#333333</color> </resources>
布局文件
需要以RelativeLayout为根布局(LinearLayout不合适,其他的比如FrameLayout可能可以,需要尝试),主要用于setDecorView方法。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_rootview" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff"> <LinearLayout android:id="@+id/optionsPickerLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_margin="10dp"> <!-- 选择爱好 --> <TextView android:id="@+id/hobbyTv" android:layout_width="0.0dp" android:layout_weight="1" android:layout_height="38dp" android:gravity="center_vertical" android:text="选择爱好" android:textSize="16sp" android:textColor="#3090d9" android:drawableRight="@drawable/pickerview_jiantou" android:paddingLeft="5dp" android:paddingRight="5dp" android:background="#E7E7E7" android:layout_marginRight="10dp" /> <!-- 选择地址 --> <TextView android:id="@+id/addressTv" android:layout_width="0.0dp" android:layout_weight="1" android:layout_height="38dp" android:gravity="center_vertical" android:text="选择地址" android:textSize="16sp" android:textColor="#3090d9" android:drawableRight="@drawable/pickerview_jiantou" android:paddingLeft="5dp" android:paddingRight="5dp" android:background="#E7E7E7" /> </LinearLayout> <!-- 开始时间 --> <TextView android:id="@+id/startdateTv" android:layout_alignLeft="@+id/optionsPickerLayout" android:layout_below="@+id/optionsPickerLayout" android:layout_width="wrap_content" android:layout_height="38dp" android:gravity="center_vertical" android:text="开始日期" android:textSize="16sp" android:textColor="#3090d9" android:drawableLeft="@drawable/date_icon" android:drawablePadding="5dp" android:paddingLeft="5dp" android:paddingRight="5dp" android:layout_marginTop="10dp" android:background="#E7E7E7" /> </RelativeLayout>
MainActivity
黄色标记的是选项选择器常规写法;
橙色标记的是选项选择器常规之外的实现文本滑动的效果;
package com.why.project.pickerviewdemo; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.method.ScrollingMovementMethod; import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.bigkoo.pickerview.builder.OptionsPickerBuilder; import com.bigkoo.pickerview.builder.TimePickerBuilder; import com.bigkoo.pickerview.listener.OnOptionsSelectListener; import com.bigkoo.pickerview.listener.OnTimeSelectListener; import com.bigkoo.pickerview.view.OptionsPickerView; import com.bigkoo.pickerview.view.TimePickerView; import com.why.project.pickerviewdemo.bean.SpinnearBean; import com.why.project.pickerviewdemo.util.DateTimeHelper; import org.json.JSONArray; import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; public class MainActivity extends AppCompatActivity { private TextView hobbyTv;//选择爱好 /**爱好列表集合*/ private ArrayList<SpinnearBean> mHobbyList; private ArrayList<String> mHobbyNameList;//用于选择器显示 private OptionsPickerView mHobbyPickerView;//选择器 private TextView addressTv;//选择地址 /**地址列表集合*/ private ArrayList<SpinnearBean> mAddressList; private ArrayList<String> mAddressNameList;//用于选择器显示 private OptionsPickerView mAddressPickerView;//选择器 private TextView startdateTv;//开始日期 private TimePickerView mStartDatePickerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); initDatas(); initEvents(); } private void initViews() { hobbyTv = findViewById(R.id.hobbyTv); addressTv = (TextView) findViewById(R.id.addressTv); //实现文本区域可滑动的效果,用于当显示的文本过长时 addressTv.setMovementMethod(ScrollingMovementMethod.getInstance());//实现可滑动,但是和ScrollView滑动冲突,需要处理下 //https://blog.csdn.net/qq_36070190/article/details/70053228 addressTv.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub if(event.getAction()==MotionEvent.ACTION_DOWN){ //通知父控件不要干扰 v.getParent().requestDisallowInterceptTouchEvent(true); } if(event.getAction()==MotionEvent.ACTION_MOVE){ //通知父控件不要干扰 v.getParent().requestDisallowInterceptTouchEvent(true); } if(event.getAction()==MotionEvent.ACTION_UP){ v.getParent().requestDisallowInterceptTouchEvent(false); } return false; } }); startdateTv = findViewById(R.id.startdateTv); } private void initDatas() { //========================================初始化爱好列表集合======================================== mHobbyList = new ArrayList<SpinnearBean>(); mHobbyNameList = new ArrayList<String>(); //模拟获取数据集合 try{ mHobbyList = parseJsonArray("spinners.txt"); }catch (Exception e) { e.printStackTrace(); } for(SpinnearBean spinnearBean : mHobbyList){ mHobbyNameList.add(spinnearBean.getParaName()); } //============初始化选择器============ initHobbyOptionPicker(); //如果想要直接赋值的话,这样写 /*if(mHobbyNameList.size() > 0){ hobbyTv.setText(mHobbyNameList.get(0));//默认展现第一个 }*/ //========================================初始化地址列表集合======================================== mAddressList = new ArrayList<SpinnearBean>(); mAddressNameList = new ArrayList<String>(); //模拟获取数据集合 try{ mAddressList = parseJsonArray("spinners2.txt"); }catch (Exception e) { e.printStackTrace(); } for(SpinnearBean spinnearBean : mAddressList){ mAddressNameList.add(spinnearBean.getParaName()); } //============初始化选择器============ initAddressOptionPicker(); //当选择器列表项文本过长时,直接赋值的话,会有问题:高度变小了。不太明白什么原因,所以需要延迟设置文本,实际过程中因为有网络请求,所以一般没有问题 /*new Handler().postDelayed(new Runnable() { @Override public void run() { if(mAddressNameList.size() > 0){ addressTv.setText(mAddressNameList.get(0));//默认展现第一个 } } }, 500);*/ //========================================初始化开始日期选择器控件======================================== initStartTimePicker();//初始化开始日期选择器控件 } //初始化爱好选择器 private void initHobbyOptionPicker() { mHobbyPickerView = new OptionsPickerBuilder(MainActivity.this, new OnOptionsSelectListener() { @Override public void onOptionsSelect(int options1, int option2, int options3, View v) { //返回的分别是三个级别的选中位置 String tx = mHobbyNameList.get(options1); hobbyTv.setText(tx); } }) .setDecorView((RelativeLayout)findViewById(R.id.activity_rootview))//必须是RelativeLayout,不设置setDecorView的话,底部虚拟导航栏会显示在弹出的选择器区域 .setTitleText("选择爱好")//标题文字 .setTitleSize(20)//标题文字大小 .setTitleColor(getResources().getColor(R.color.pickerview_title_text_color))//标题文字颜色 .setCancelText("取消")//取消按钮文字 .setCancelColor(getResources().getColor(R.color.pickerview_cancel_text_color))//取消按钮文字颜色 .setSubmitText("确定")//确认按钮文字 .setSubmitColor(getResources().getColor(R.color.pickerview_submit_text_color))//确定按钮文字颜色 .setContentTextSize(20)//滚轮文字大小 .setTextColorCenter(getResources().getColor(R.color.pickerview_center_text_color))//设置选中文本的颜色值 .setLineSpacingMultiplier(1.8f)//行间距 .setDividerColor(getResources().getColor(R.color.pickerview_divider_color))//设置分割线的颜色 .setSelectOptions(0)//设置选择的值 .build(); mHobbyPickerView.setPicker(mHobbyNameList);//添加数据 } //初始化地址选择器 private void initAddressOptionPicker() { mAddressPickerView = new OptionsPickerBuilder(MainActivity.this, new OnOptionsSelectListener() { @Override public void onOptionsSelect(int options1, int option2, int options3, View v) { //返回的分别是三个级别的选中位置 String tx = mAddressNameList.get(options1); addressTv.setText(tx); } }) .setDecorView((RelativeLayout)findViewById(R.id.activity_rootview))//必须是RelativeLayout,不设置setDecorView的话,底部虚拟导航栏会显示在弹出的选择器区域 .setTitleText("选择地址")//标题文字 .setTitleSize(20)//标题文字大小 .setTitleColor(getResources().getColor(R.color.pickerview_title_text_color))//标题文字颜色 .setCancelText("取消")//取消按钮文字 .setCancelColor(getResources().getColor(R.color.pickerview_cancel_text_color))//取消按钮文字颜色 .setSubmitText("确定")//确认按钮文字 .setSubmitColor(getResources().getColor(R.color.pickerview_submit_text_color))//确定按钮文字颜色 .setContentTextSize(20)//滚轮文字大小 .setTextColorCenter(getResources().getColor(R.color.pickerview_center_text_color))//设置选中文本的颜色值 .setLineSpacingMultiplier(1.8f)//行间距 .setDividerColor(getResources().getColor(R.color.pickerview_divider_color))//设置分割线的颜色 .setSelectOptions(0)//设置选择的值 .build(); mAddressPickerView.setPicker(mAddressNameList);//添加数据 } /**初始化开始日期选择器控件*/ private void initStartTimePicker() { //控制时间范围(如果不设置范围,则使用默认时间1900-2100年,此段代码可注释) //因为系统Calendar的月份是从0-11的,所以如果是调用Calendar的set方法来设置时间,月份的范围也要是从0-11 Calendar selectedDate = Calendar.getInstance(); //设置最小日期和最大日期 Calendar startDate = Calendar.getInstance(); try { startDate.setTime(DateTimeHelper.parseStringToDate("1970-01-01"));//设置为2006年4月28日 } catch (ParseException e) { e.printStackTrace(); } Calendar endDate = Calendar.getInstance();//最大日期是今天 //时间选择器 mStartDatePickerView = new TimePickerBuilder(MainActivity.this, new OnTimeSelectListener() { @Override public void onTimeSelect(Date date, View v) {//选中事件回调 // 这里回调过来的v,就是show()方法里面所添加的 View 参数,如果show的时候没有添加参数,v则为null startdateTv.setText(DateTimeHelper.formatToString(date,"yyyy-MM-dd")); } }) .setDecorView((RelativeLayout)findViewById(R.id.activity_rootview))//必须是RelativeLayout,不设置setDecorView的话,底部虚拟导航栏会显示在弹出的选择器区域 //年月日时分秒 的显示与否,不设置则默认全部显示 .setType(new boolean[]{true, true, true, false, false, false}) .setLabel("", "", "", "", "", "") .isCenterLabel(false)//是否只显示中间选中项的label文字,false则每项item全部都带有label。 .setTitleText("开始日期")//标题文字 .setTitleSize(20)//标题文字大小 .setTitleColor(getResources().getColor(R.color.pickerview_title_text_color))//标题文字颜色 .setCancelText("取消")//取消按钮文字 .setCancelColor(getResources().getColor(R.color.pickerview_cancel_text_color))//取消按钮文字颜色 .setSubmitText("确定")//确认按钮文字 .setSubmitColor(getResources().getColor(R.color.pickerview_submit_text_color))//确定按钮文字颜色 .setContentTextSize(20)//滚轮文字大小 .setTextColorCenter(getResources().getColor(R.color.pickerview_center_text_color))//设置选中文本的颜色值 .setLineSpacingMultiplier(1.8f)//行间距 .setDividerColor(getResources().getColor(R.color.pickerview_divider_color))//设置分割线的颜色 .setRangDate(startDate, endDate)//设置最小和最大日期 .setDate(selectedDate)//设置选中的日期 .build(); } private void initEvents() { //选择爱好的下拉菜单点击事件 hobbyTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mHobbyPickerView.show(); } }); //选择地址的下拉菜单点击事件 addressTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mAddressPickerView.show(); } }); //开始日期的下拉菜单点击事件 startdateTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mStartDatePickerView.show(); } }); } /*===========读取assets目录下的js字符串文件(js数组和js对象),然后生成List集合===========*/ public static final String LISTROOTNODE = "spinnerList"; public static final String KEY_LISTITEM_NAME = "paraName"; public static final String KEY_LISTITEM_VALUE = "paraValue"; public static final String KEY_LISTITEM_CHECKCOLOR = "checkColor"; /** * 解析JSON文件的简单数组 */ private ArrayList<SpinnearBean> parseJsonArray(String fileName) throws Exception{ ArrayList<SpinnearBean> itemsList = new ArrayList<SpinnearBean>(); String jsonStr = getStringFromAssert(MainActivity.this, fileName); if(jsonStr.equals("")){ return null; } JSONObject allData = new JSONObject(jsonStr); //全部内容变为一个项 JSONArray jsonArr = allData.getJSONArray(LISTROOTNODE); //取出数组 for(int x = 0;x<jsonArr.length();x++){ SpinnearBean model = new SpinnearBean(); JSONObject jsonobj = jsonArr.getJSONObject(x); model.setParaName(jsonobj.getString(KEY_LISTITEM_NAME)); model.setParaValue(jsonobj.getString(KEY_LISTITEM_VALUE)); if(jsonobj.has(KEY_LISTITEM_CHECKCOLOR)){ model.setCheckColor(jsonobj.getString(KEY_LISTITEM_CHECKCOLOR)); } model.setSelectedState(false); itemsList.add(model); model = null; } return itemsList; } /** * 访问assets目录下的资源文件,获取文件中的字符串 * @param filePath - 文件的相对路径,例如:"listdata.txt"或者"/www/listdata.txt" * @return 内容字符串 * */ public String getStringFromAssert(Context mContext, String filePath) { String content = ""; // 结果字符串 try { InputStream is = mContext.getResources().getAssets().open(filePath);// 打开文件 int ch = 0; ByteArrayOutputStream out = new ByteArrayOutputStream(); // 实现了一个输出流 while ((ch = is.read()) != -1) { out.write(ch); // 将指定的字节写入此 byte 数组输出流 } byte[] buff = out.toByteArray();// 以 byte 数组的形式返回此输出流的当前内容 out.close(); // 关闭流 is.close(); // 关闭流 content = new String(buff, "UTF-8"); // 设置字符串编码 } catch (Exception e) { Toast.makeText(mContext, "对不起,没有找到指定文件!", Toast.LENGTH_SHORT) .show(); } return content; } }
混淆配置
无
参考资料
Android项目总结(二)仿IOS效果的日期选择器和省市县三级联动
完美解决ScrollView与内部嵌套的TextView滚动冲突