iOS自定义时间滚动选择控件

本文实例为大家分享了iOS自定义时间滚动选择控件的具体代码,供大家参考,具体内容如下

1.先上自定义的控件:

/**
 * 滚轮选择器
 * author LH
 * data 2016/8/20 17:26
 */
public class WheelView extends View {

 public static final String TAG = "WheelView";

 /**
 * 自动回滚到中间的速度
 */
 public static final float SPEED = 2;

 /**
 * 除选中item外,上下各需要显示的备选项数目
 */
 public static final int SHOW_SIZE = 1;

 private Context context;

 private List<String> itemList;
 private int itemCount;

 /**
 * item高度
 */
 private int itemHeight = 50;

 /**
 * 选中的位置,这个位置是mDataList的中心位置,一直不变
 */
 private int currentItem;

 private Paint selectPaint;
 private Paint mPaint;
 // 画背景图中单独的画笔
 private Paint centerLinePaint;

 private float centerY;
 private float centerX;

 private float mLastDownY;
 /**
 * 滑动的距离
 */
 private float mMoveLen = 0;
 private boolean isInit = false;
 private SelectListener mSelectListener;
 private Timer timer;
 private MyTimerTask mTask;

 Handler updateHandler = new Handler() {

 @Override
 public void handleMessage(Message msg) {
  if (Math.abs(mMoveLen) < SPEED) {
  // 如果偏移量少于最少偏移量
  mMoveLen = 0;
  if (null != timer) {
   timer.cancel();
   timer.purge();
   timer = null;
  }
  if (mTask != null) {
   mTask.cancel();
   mTask = null;
   performSelect();
  }
  } else {
  // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚
  mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
  }
  invalidate();
 }

 };

 public WheelView(Context context) {
 super(context);
 init(context);
 }

 public WheelView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }

 public void setOnSelectListener(SelectListener listener) {
 mSelectListener = listener;
 }

 public void setWheelStyle(int style) {
 itemList = WheelStyle.getItemList(context, style);
 if (itemList != null) {
  itemCount = itemList.size();
  resetCurrentSelect();
  invalidate();
 } else {
  Log.i(TAG, "item is null");
 }
 }

 public void setWheelItemList(List<String> itemList) {
 this.itemList = itemList;
 if (itemList != null) {
  itemCount = itemList.size();
  resetCurrentSelect();
 } else {
  Log.i(TAG, "item is null");
 }
 }

 private void resetCurrentSelect() {
 if (currentItem < 0) {
  currentItem = 0;
 }
 while (currentItem >= itemCount) {
  currentItem--;
 }
 if (currentItem >= 0 && currentItem < itemCount) {
  invalidate();
 } else {
  Log.i(TAG, "current item is invalid");
 }
 }

 public int getItemCount() {
 return itemCount;
 }
 /**
 * 选择选中的item的index
 * author LH
 * data 2016/9/4 11:09
 */
 public void setCurrentItem(int selected) {
 currentItem = selected;
 resetCurrentSelect();
 }

 public int getCurrentItem() {
 return currentItem;
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 int mViewHeight = getMeasuredHeight();
 int mViewWidth = getMeasuredWidth();
 centerX = (float) (mViewWidth / 2.0);
 centerY = (float) (mViewHeight / 2.0);

 isInit = true;
 invalidate();
 }

 private void init(Context context) {
 this.context = context;

 timer = new Timer();
 itemList = new ArrayList<>();

 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mPaint.setStyle(Style.FILL);
 mPaint.setTextAlign(Align.CENTER);
 mPaint.setColor(getResources().getColor(R.color.wheel_unselect_text));
 int size1 = (int) (SupportDisplay.getLayoutScale()*22+0.5);
 mPaint.setTextSize(size1);

 selectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 selectPaint.setStyle(Style.FILL);
 selectPaint.setTextAlign(Align.CENTER);
 selectPaint.setColor(getResources().getColor(R.color.color_1a1a1a));
 int size2 = (int) (SupportDisplay.getLayoutScale()*24+0.5);
 selectPaint.setTextSize(size2);

 centerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 centerLinePaint.setStyle(Style.FILL);
 centerLinePaint.setTextAlign(Align.CENTER);
 centerLinePaint.setColor(getResources().getColor(R.color.wheel_unselect_text));

 // 绘制背景
 setBackground(null);
 }

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 if (isInit) {
  drawData(canvas);
 }
 }

 private void drawData(Canvas canvas) {
 // 先绘制选中的text再往上往下绘制其余的text
 if (!itemList.isEmpty()) {
  // 绘制中间data
  drawCenterText(canvas);
  // 绘制上方data
  for (int i = 1; i < SHOW_SIZE + 1; i++) {
  drawOtherText(canvas, i, -1);
  }
  // 绘制下方data
  for (int i = 1; i < SHOW_SIZE + 1; i++) {
  drawOtherText(canvas, i, 1);
  }
 }
 }

 private void drawCenterText(Canvas canvas) {
 // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标
 float y = centerY + mMoveLen;
 FontMetricsInt fmi = selectPaint.getFontMetricsInt();
 float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
 canvas.drawText(itemList.get(currentItem), centerX, baseline, selectPaint);
 }

 /**
 * 绘制文本
 * author LH
 * data 2016/9/4 11:10
 * @param canvas 画布
 * @param position 距离mCurrentSelected的差值
 * @param type 1表示向下绘制,-1表示向上绘制
 */
 private void drawOtherText(Canvas canvas, int position, int type) {
 int index = currentItem + type * position;
 if (index >= itemCount) {
  index = index - itemCount;
 }
 if (index < 0) {
  index = index + itemCount;
 }
 String text = itemList.get(index);

 int itemHeight = getHeight() / (SHOW_SIZE * 2 + 1);
 float d = itemHeight * position + type * mMoveLen;
 float y = centerY + type * d;

 FontMetricsInt fmi = mPaint.getFontMetricsInt();
 float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
 canvas.drawText(text, centerX, baseline, mPaint);
 }

 @Override
 public void setBackground(Drawable background) {
 background = new Drawable() {
  @Override
  public void draw(Canvas canvas) {
  itemHeight = getHeight() / (SHOW_SIZE * 2 + 1);
  int width = getWidth();

  canvas.drawLine(0, itemHeight, width, itemHeight, centerLinePaint);
  canvas.drawLine(0, itemHeight * 2, width, itemHeight * 2, centerLinePaint);

  centerLinePaint.setColor(getResources().getColor(R.color.wheel_bg));
  Rect topRect = new Rect(0, 0, width, itemHeight);
  canvas.drawRect(topRect, centerLinePaint);
  Rect bottomRect = new Rect(0, itemHeight * 2, width, itemHeight * 3);
  canvas.drawRect(bottomRect, centerLinePaint);
  }

  @Override
  public void setAlpha(int alpha) {

  }

  @Override
  public void setColorFilter(ColorFilter cf) {

  }

  @Override
  public int getOpacity() {
  return 0;
  }
 };
 super.setBackground(background);
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
 switch (event.getActionMasked()) {
  case MotionEvent.ACTION_DOWN:
  doDown(event);
  break;
  case MotionEvent.ACTION_MOVE:
  doMove(event);
  break;
  case MotionEvent.ACTION_UP:
  doUp();
  break;
  default:
  break;
 }
 return true;
 }

 private void doDown(MotionEvent event) {
 if (mTask != null) {
  mTask.cancel();
  mTask = null;
 }
 mLastDownY = event.getY();
 }

 private void doMove(MotionEvent event) {

 mMoveLen += (event.getY() - mLastDownY);
 if (mMoveLen > itemHeight / 2) {
  // 往下滑超过离开距离
  mMoveLen = mMoveLen - itemHeight;
  currentItem--;
  if (currentItem < 0) {
  currentItem = itemCount - 1;
  }
 } else if (mMoveLen < -itemHeight / 2) {
  // 往上滑超过离开距离
  mMoveLen = mMoveLen + itemHeight;
  currentItem++;
  if (currentItem >= itemCount) {
  currentItem = 0;
  }
 }

 mLastDownY = event.getY();
 invalidate();
 }

 private void doUp() {
 // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
 if (Math.abs(mMoveLen) < 0.0001) {
  mMoveLen = 0;
  return;
 }
 if (mTask != null) {
  mTask.cancel();
  mTask = null;
 }
 if (null == timer) {
  timer = new Timer();
 }
 mTask = new MyTimerTask(updateHandler);
 timer.schedule(mTask, 0, 10);
 }

 class MyTimerTask extends TimerTask {
 Handler handler;

 public MyTimerTask(Handler handler) {
  this.handler = handler;
 }

 @Override
 public void run() {
  handler.sendMessage(handler.obtainMessage());
 }

 }

 private void performSelect() {
 if (mSelectListener != null) {
  mSelectListener.onSelect(currentItem, itemList.get(currentItem));
 } else {
  Log.i(TAG, "null listener");
 }
 }

 public interface SelectListener {
 void onSelect(int index, String text);
 }

}

2.然后是时间选择控件的样式工具类

/**
 * 时间选择样式
 * author LH
 * data 2016/9/4 11:05
 */
public class WheelStyle {

 public static final int minYear = 1980;
 public static final int maxYear = 2020;

 /**
 * Wheel Style Hour
 */
 public static final int STYLE_HOUR = 1;
 /**
 * Wheel Style Minute
 */
 public static final int STYLE_MINUTE = 2;
 /**
 * Wheel Style Year
 */
 public static final int STYLE_YEAR = 3;
 /**
 * Wheel Style Month
 */
 public static final int STYLE_MONTH = 4;
 /**
 * Wheel Style Day
 */
 public static final int STYLE_DAY = 5;
 /**
 * Wheel Style Simple Day
 */
 public static final int STYLE_SIMPLE_DAY = 6;
 /**
 * Wheel Style Set Warn
 */
 public static final int STYLE_SET_WARN = 7;
 /**
 * Wheel Style Work Answer
 */
 public static final int STYLE_WORK_ANSWER = 8;

 private WheelStyle() {
 }

 public static List<String> getItemList(Context context, int Style) {
 if (Style == STYLE_HOUR) {
  return createHourString();
 } else if (Style == STYLE_MINUTE) {
  return createMinuteString();
 } else if (Style == STYLE_YEAR) {
  return createYearString();
 } else if (Style == STYLE_MONTH) {
  return createMonthString();
 } else if (Style == STYLE_DAY) {
  return createDayString();
 } else if (Style == STYLE_SIMPLE_DAY) {
  return createSimpleDayString();
 } else if (Style == STYLE_SET_WARN) {
  return createSetWarnTimeString();
 } else {
  throw new IllegalArgumentException("style is illegal");
 }
 }

 private static List<String> createHourString() {
 List<String> wheelString = new ArrayList<>();
 for (int i = 0; i < 24; i++) {
  wheelString.add(String.format("%02d" + "时", i));
 }
 return wheelString;
 }

 private static List<String> createMinuteString() {
 List<String> wheelString = new ArrayList<>();
 for (int i = 0; i < 60; i++) {
  wheelString.add(String.format("%02d" + "分", i));
 }
 return wheelString;
 }

 private static List<String> createYearString() {
 List<String> wheelString = new ArrayList<>();
 for (int i = minYear; i <= maxYear; i++) {
  wheelString.add(Integer.toString(i));
 }
 return wheelString;
 }

 private static List<String> createMonthString() {
 List<String> wheelString = new ArrayList<>();
 for (int i = 1; i <= 12; i++) {
  wheelString.add(String.format("%02d" + "月", i));
 }
 return wheelString;
 }

 private static List<String> createDayString() {
 List<String> wheelString = new ArrayList<>();
 for (int i = 1; i <= 31; i++) {
  wheelString.add(String.format("%02d" + "日", i));
 }
 return wheelString;
 }

 private static List<String> createSimpleDayString() {
 List<String> wheelString = new ArrayList<>();
 wheelString.add("一天后");
 wheelString.add("两天后");
 wheelString.add("三天后");
 return wheelString;
 }

 private static List<String> createSetWarnTimeString() {
 List<String> wheelString = new ArrayList<>();
 wheelString.add("30分钟");
 wheelString.add("60分钟");
 wheelString.add("90分钟");
 wheelString.add("120分钟");
 return wheelString;
 }
 /**
 * 计算闰月
 *
 * @param month
 * @return
 */
 private static boolean isLeapMonth(int month) {
 return month == 1 || month == 3 || month == 5 || month == 7
  || month == 8 || month == 10 || month == 12;
 }

 /**
 * 计算闰年
 *
 * @param year
 * @return
 */
 private static boolean isLeapYear(int year) {
 return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
 }
}

3.使用的xml

<com.example.view.timeview.WheelView
  android:id="@+id/select_time_simple_wheel"
  android:layout_width="match_parent"
  android:layout_height="150dp"
  android:layout_marginLeft="20dp"
  android:layout_marginRight="20dp"
  android:layout_weight="1" />

4.在Java文件中设置mWheelView.setWheelStyle(WheelStyle.STYLE_YEAR);就可以显示WheelStyle类中设置的类型了。这个类中的样式种类读者可以根据自己的需要自行添加。

5.获取当前选择的项也很简单mWheelView.getCurrentItem();就能获取到控件的当前选择的项。获取到所在的项以后剩下的就是逻辑操作了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • iOS如何获取当前日期前后N天的时间示例代码

    前言 记得之前看过一部有关机器人动画片,具体名字叫什么忘记了.但是其中有句台词我记得还是很清楚的 明年的今日就是你的忌日. 联系到iOS,如果在项目中遇到了计算日期的,并且是要获取当前时间(指定日期)n天后的日期,这可该怎么实现呢? 比如我们要获取当前日期7天后的日期,要怎么实现呢 获取当前日期 NSDate *currentDate = [NSDate date]; 前一天或后一天时间 NSDate *lastDay = [NSDate dateWithTimeInterval:-24*60*

  • Android仿IOS10圆盘时间选择器

    介绍 这是一款仿IOS10(就寝功能)的圆盘时间选择器 项目演示 实现思路 以720度为一个周期,0~360°对应0~12小时,360°~720°对应12~24小时 这里以"开始时间设置按钮"为例来谈谈它的滑动实现: 将"开始时间设置按钮"作为点A,表盘中心作为点O,手指触摸点作为点P.通过反正切公式可以计算出∠AOP的大小,然后随着手指的位置不断变化去更新点A的位置(即点A的角度). // 坐标系的直线表达式 // 直线l1的表达式子:过钟表中心点和开始控件中心点

  • iOS实现自定义起始时间选择器视图

    随着界面的整体效果的各种展现, 起始时间选择器的展现也需求突出! 最近项目中发现时间选择器使用处还挺多, 数了数原型图发现有6处. 便决定自定义时间选择器视图写个 Demo, 封装好在所需控制器里直接调用! 主要功能: 调起时间选择器, 传值(起始时间/截止时间), 两者时间均要合理, 不能超过未来时间, 并且起始时间不能大于截止时间. 点击取消或空白处收起时间选择器. 如果需要可以根据自己的需求来修改界面, 效果如下: 主要步骤: 创建时间选择器Picker 且确认取消按钮实现功能逻辑 创建展

  • 详解iOS时间选择框

    本文实例为大家介绍了iOS时间选择框的示例代码,供大家参考,具体内容如下 代码: 一.头文件 #import <UIKit/UIKit.h> @class ITTPickView; @protocol ITTPickViewDelegate <NSObject> @optional -(void)toobarDonBtnHaveClick:(ITTPickView *)pickView resultString:(NSString *)resultString; @end @int

  • jQuery基于muipicker实现仿ios时间选择

    首先我们先来看原始的muipicker的例子 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />

  • iOS自定义时间滚动选择控件

    本文实例为大家分享了iOS自定义时间滚动选择控件的具体代码,供大家参考,具体内容如下 1.先上自定义的控件: /** * 滚轮选择器 * author LH * data 2016/8/20 17:26 */ public class WheelView extends View { public static final String TAG = "WheelView"; /** * 自动回滚到中间的速度 */ public static final float SPEED = 2;

  • Android 自定义日期段选择控件功能(开始时间-结束时间)

    开发中碰到个需求,需要在一个空间中选择完成开始和结束时间.实现的过程走的是程序员开发的老路子,找到轮子后自己改吧改吧就成了. 当时做的时候有几个需求:1.当天为最大的结束日期,2.最大选择范围1年,3.开始时间和结束时间可以为同一天.如有其他需求实现,可以参考代码改进一下.先上效果图: 视频点击后的虚影是屏幕录制的原因.实现步骤:(如有缺失什么资源,请告知.开始时间和结束时间显示自己布局内添加就可以) 1.自定义控件属性 <declare-styleable name="MyCalenda

  • Android自定义view实现滚动选择控件详解

    目录 前言 需求 编写代码 主要问题 前言 上篇文章通过一个有header和footer的滚动控件(Viewgroup)学了下MeasureSpec.onMeasure以及onLayout,接下来就用一个滚动选择的控件(View)来学一下onDraw的使用,并且了解下在XML自定义控件参数. 需求 这里就是一个滚动选择文字的控件,还是挺常见的,之前用别人的,现在选择手撕一个,核心思想如下: 1.有三层不同大小及透明度的选项,选中项放在中间 2.接受一个列表的数据,静态时显示三个值,滚动时显示四个

  • iOS自定义圆形进度提示控件

    iOS中默认的进度条是水平方向的进度条,这往往不能满足我们的需求.但是我们可以自定义类似的圆形的进度提示控件,主要使用iOS中的绘图机制来实现.这里我们要实现一个通过按钮点击然后圆形进度提示不断增加的效果. (1)新建一个Cocoa Touch Class,注意要继承自UIView.这个是绘制图形的类,绘制一个圆形的背景和扇形的进度.具体实现如下: import UIKit class ProgressControl: UIView { override init(frame: CGRect)

  • Android 实现IOS 滚轮选择控件的实例(源码下载)

     Android 实现IOS 滚轮选择控件的实例 最近根据项目需要,整理了一个相对比较全面的 WheelView 使用控件,借用之前看到的一句话来说,就是站在巨人肩膀上,进行了一些小调整. 这里先贴上效果图 一般常用的时间选择格式,,单项选择,以及城市联动,这里基本都可以满足了. 这里把 单项选择,和 日期时间选择 给提出到 Util 类中,代码如下: public class Util { /** * 时间选择回调 */ public interface TimerPickerCallBack

  • 可支持快速搜索筛选的Android自定义选择控件

    Android 自定义支持快速搜索筛选的选择控件使用方法,具体如下 项目中遇到选择控件选项过多,需要快速查找匹配的情况. 做了简单的Demo,效果图如下: 源码地址:https://github.com/whieenz/SearchSelect 这个控件是由Dialog+SearchView+ListView实现的.Dialog用来承载选择控件,SearchView实现输入,ListView展示结果.设计概要图如下: 一.自定义Dialog Dialog布局文件 <?xml version=&quo

  • jQuery带时间的日期控件代码分享

    本文实例讲述了JS+CSS3实现的类似于苹果iwatch计时器特效.分享给大家供大家参考.具体如下: 带时间的jQuery日期控件代码是一款基于jQueryUI实现的,可自定义日期插件语言,这个日期控件的亮点就在于选择的时间可精确到分钟. 运行效果图:                    -------------------查看效果 下载源码------------------- 小提示:浏览器中如果不能正常运行,可以尝试切换浏览模式. 为大家分享的jQuery带时间的日期控件代码如下 <h

  • android自定义WaveView水波纹控件

    本文实例为大家分享了android自定义WaveView水波纹控件的使用方法,供大家参考,具体内容如下 Github Repository and libaray WaveView水波纹控件 首先看下演示demo demo中可以看到不同高度,不同速度,不同幅度的水波纹:你可以通过view的参数直接控制view的表现形式. 引入你的工程 在项目的根目录下的build.gradle文件中添加如下代码: allprojects { repositories { ... maven { url 'htt

  • Ext JS框架中日期函数的用法及日期选择控件的实现

    Ext.Date是一个单例,封装了一系列日期操作函数,扩展JavaScript Date的功能,下面列出一些常用的功能. 基本函数: Ext.Date.add(date, interval, value) 给date增加或减少时间,这个函数不改变原有Date对象的值,而是返回一个新的Date对象. Ext.Date.between(date, start, end) 判断date是否在start和end之间. Ext.Date.clearTime(date, clone) 把date的时间设置成

  • Ext JS 4实现带week(星期)的日期选择控件(实战二)

    前言 JavaScript 中的日期和时间 Ext JS 4实现带week(星期)的日期选择控件(实战一) 如对本篇的一些预备知识需详尽了解,可参考以上两篇. Javascript 有提供Date 对象用于处理时间.但是Date 并没有提供获取星期的方法. 要在web 端通过js 方式获取某个时间是这一年的第几个星期,可以根据一些算法去实现. 当然, jquery 的扩展组件 等有直接提供这样的一些现成包. 像Ext js 就有提供获取星期的方法 Ext.Date.getWeekOfYear(d

随机推荐