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,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,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,centerLinePaint);
  canvas.drawLine(0,itemHeight * 2,centerLinePaint);

  centerLinePaint.setColor(getResources().getColor(R.color.wheel_bg));
  Rect topRect = new Rect(0,itemHeight);
  canvas.drawRect(topRect,centerLinePaint);
  Rect bottomRect = new Rect(0,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,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();就能获取到控件的当前选择的项。获取到所在的项以后剩下的就是逻辑操作了。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


当我们远离最新的 iOS 16 更新版本时,我们听到了困扰 Apple 最新软件的错误和性能问题。
欧版/美版 特别说一下,美版选错了 可能会永久丧失4G,不过只有5%的概率会遇到选择运营商界面且部分必须连接到iTunes才可以激活
一般在接外包的时候, 通常第三方需要安装你的app进行测试(这时候你的app肯定是还没传到app store之前)。
前言为了让更多的人永远记住12月13日,各大厂都在这一天将应用变灰了。那么接下来我们看一下Flutter是如何实现的。Flutter中实现整个App变为灰色在Flutter中实现整个App变为灰色是非常简单的,只需要在最外层的控件上包裹ColorFiltered,用法如下:ColorFiltered(颜色过滤器)看名字就知道是增加颜色滤镜效果的,ColorFiltered( colorFilter:ColorFilter.mode(Colors.grey, BlendMode.
flutter升级/版本切换
(1)在C++11标准时,open函数的文件路径可以传char指针也可以传string指针,而在C++98标准,open函数的文件路径只能传char指针;(2)open函数的第二个参数是打开文件的模式,从函数定义可以看出,如果调用open函数时省略mode模式参数,则默认按照可读可写(ios_base:in | ios_base::out)的方式打开;(3)打开文件时的mode的模式是从内存的角度来定义的,比如:in表示可读,就是从文件读数据往内存读写;out表示可写,就是把内存数据写到文件中;
文章目录方法一:分别将图片和文字置灰UIImage转成灰度图UIColor转成灰度颜色方法二:给App整体添加灰色滤镜参考App页面置灰,本质是将彩色图像转换为灰度图像,本文提供两种方法实现,一种是App整体置灰,一种是单个页面置灰,可结合具体的业务场景使用。方法一:分别将图片和文字置灰一般情况下,App页面的颜色深度是24bit,也就是RGB各8bit;如果算上Alpha通道的话就是32bit,RGBA(或者ARGB)各8bit。灰度图像的颜色深度是8bit,这8bit表示的颜色不是彩色,而是256
领导让调研下黑(灰)白化实现方案,自己调研了两天,根据网上资料,做下记录只是学习过程中的记录,还是写作者牛逼
让学前端不再害怕英语单词(二),通过本文,可以对css,js和es6的单词进行了在逻辑上和联想上的记忆,让初学者更快的上手前端代码
用Python送你一颗跳动的爱心
在uni-app项目中实现人脸识别,既使用uni-app中的live-pusher开启摄像头,创建直播推流。通过快照截取和压缩图片,以base64格式发往后端。
商户APP调用微信提供的SDK调用微信支付模块,商户APP会跳转到微信中完成支付,支付完后跳回到商户APP内,最后展示支付结果。CSDN前端领域优质创作者,资深前端开发工程师,专注前端开发,在CSDN总结工作中遇到的问题或者问题解决方法以及对新技术的分享,欢迎咨询交流,共同学习。),验证通过打开选择支付方式弹窗页面,选择微信支付或者支付宝支付;4.可取消支付,放弃支付会返回会员页面,页面提示支付取消;2.判断支付方式,如果是1,则是微信支付方式。1.判断是否在微信内支付,需要在微信外支付。
Mac命令行修改ipa并重新签名打包
首先在 iOS 设备中打开开发者模式。位于:设置 - 隐私&安全 - 开发者模式(需重启)
一 现象导入MBProgressHUD显示信息时,出现如下异常现象Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_MBProgressHUD", referenced from: objc-class-ref in ViewController.old: symbol(s) not found for architecture x86_64clang: error: linker command failed wit
Profiles >> 加号添加 >> Distribution >> "App Store" >> 选择 2.1 创建的App ID >> 选择绑定 2.3 的发布证书(.cer)>> 输入描述文件名称 >> Generate 生成描述文件 >> Download。Certificates >> 加号添加 >> "App Store and Ad Hoc" >> “Choose File...” >> 选择上一步生成的证书请求文件 >> Continue >> Download。
今天有需求,要实现的功能大致如下:在安卓和ios端实现分享功能可以分享链接,图片,文字,视频,文件,等欢迎大佬多多来给萌新指正,欢迎大家来共同探讨。如果各位看官觉得文章有点点帮助,跪求各位给点个“一键三连”,谢啦~声明:本博文章若非特殊注明皆为原创原文链接。