当前位置: 首页 > news >正文

Android仿京东金融的数值滚动尺功能

自定义数值滚动尺,这个用的还是挺多的,例如京东金融的通过滚动尺选择金额等,而这次就是高仿京东金融的数值滚动尺。首先看看下效果图,如下:

首先先给你们各个变量的含义,以免在后面的讲解中不知变量的意思,代码如下:

//最小值
private int minValue;
//最大值
private int maxValue;
//当前值
private int currentValue;
//最小单位值
private int minUnitValue;
//最小当前值
private int minCurrentValue;
//字体大小
private int textSize;
//字体颜色
private int textColor;
//线颜色
private int dividerColor;
//指示线颜色
private int indicatrixColor;
//画线的画笔
private Paint linePaint;
//控价的宽度
private int slideRulerWidth=0;
//滑动的宽度
private int rollingWidth;
//屏幕的宽
private int wrapcontentWidth;
//屏幕的高
private int wrapcontentHeight;
//一屏显示Item
private int showItemSize;
//刻度和数值的间距
private int marginCursorData;
//长刻度的大小
private int longCursor;
//短刻度的大小
private int shortCursor;
//计算每个刻度的间距
private int marginWidth=0;
//数据回调接口
private SlideRulerDataInterface slideRulerDataInterface;
//正在滑动状态
private int isScrollingState=1;
//快速一滑
private int fastScrollState=2;
//结束滑动
private int finishScrollState=3;private GestureDetector mDetector;
private Display display =null;
private Scroller scroller;public SlideRuler(Context context, AttributeSet attrs, int defStyleAttr) {super(context,attrs,defStyleAttr);display=((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();//屏幕宽高wrapcontentWidth=display.getWidth();wrapcontentHeight=display.getHeight();//初始化自定义的参数TypedArray typedArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.slideruler,defStyleAttr,0);textSize = typedArray.getDimensionPixelSize(R.styleable.slideruler_textSize,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,15,getResources().getDisplayMetrics()));textColor=typedArray.getColor(R.styleable.slideruler_textColor,Color.DKGRAY);dividerColor=typedArray.getColor(R.styleable.slideruler_dividerColor,Color.BLACK);indicatrixColor=typedArray.getColor(R.styleable.slideruler_indicatrixColor,Color.BLACK);minValue=typedArray.getInteger(R.styleable.slideruler_min_value,0);maxValue=typedArray.getInteger(R.styleable.slideruler_max_value,199000);currentValue=typedArray.getInteger(R.styleable.slideruler_current_value,10000);minUnitValue=typedArray.getInteger(R.styleable.slideruler_min_unitValue,1000);minCurrentValue=typedArray.getInteger(R.styleable.slideruler_min_currentValue,1000);showItemSize=typedArray.getInteger(R.styleable.slideruler_show_itemSize,30);marginCursorData=typedArray.getDimensionPixelSize(R.styleable.slideruler_margin_cursor_data,(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,10,getResources().getDisplayMetrics()));longCursor=typedArray.getDimensionPixelSize(R.styleable.slideruler_longCursor,(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,25,getResources().getDisplayMetrics()));shortCursor=typedArray.getDimensionPixelSize(R.styleable.slideruler_shortCursor,(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,15,getResources().getDisplayMetrics()));scroller=new Scroller(context);mDetector=new GestureDetector(context,myGestureListener);//初始化PaintlinePaint=new Paint();linePaint.setAntiAlias(true);linePaint.setTextAlign(Paint.Align.CENTER);linePaint.setStyle(Paint.Style.STROKE);linePaint.setTextSize(textSize);//检查当前值是不是正确值checkCurrentValue();}

其次自定义View也好自定义控价也好

protected void onMeasure(int widthMeasureSpec, int heigh)

也是蛮重要的所以照例也讲讲,用来确定控件的大小,代码如下:

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthModel=MeasureSpec.getMode(widthMeasureSpec);int heightModel=MeasureSpec.getMode(heightMeasureSpec);int widthSize=MeasureSpec.getSize(widthMeasureSpec);    int heightSize=MeasureSpec.getSize(heightMeasureSpec);int width;int height;if(widthModel==MeasureSpec.EXACTLY){width=widthSize;}else{width=wrapcontentWidth;}if(heightModel==MeasureSpec.EXACTLY){height=heightSize;}else{height=(getPaddingBottom()+getPaddingTop()+(wrapcontentHeight/4));}setMeasuredDimension(width,height);}

代码的意思也很简单,当MeasureSpec里的specMode类型是EXACTLY时,即设置了明确的值或者是MATCH_PARENT时,就直接把MeasureSpec.getSize()的值赋进去,如果不是即为WARP_CONTENT时,就直接赋给屏幕的宽高。控件的宽高都是同一样的做法。

当控件大小确定之后,我们再利用

protected void onSizeChanged(int w, int h, int oldw, int oldh)

进行一些变量的赋值,代码如下:

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {//计算每个刻度的间距marginWidth=getWidth()/showItemSize;//开始时的距离rollingWidth=(int)(marginWidth*cursorNum());//整个控件的宽度slideRulerWidth=(maxValue/minUnitValue)*marginWidth;super.onSizeChanged(w, h, oldw, oldh);}

到此我们就可以在onDraw(Canvas canvas)方法里画出初始的界面,而以后的动态只是通过不断的改变数值再进行绘画而已,代码如下:

@Override
protected void onDraw(Canvas canvas){//画最基础的两条线drawBaseView(canvas);//画初始的界面drawBaseLine(canvas);
}//画最基础的两条线
public void drawBaseLine(Canvas canvas){//画中间的线linePaint.setColor(indicatrixColor);canvas.drawLine(getWidth()/2,0,getWidth()/2,getHeight(),linePaint);//画底部的直线linePaint.setColor(dividerColor);canvas.drawLine(0,getHeight(),slideRulerWidth,getHeight(),linePaint);
}//画初始的界面
public void drawBaseView(Canvas canvas){//整数刻度的个数int integerWidth= (int)Math.rint((currentValue-minValue)/minUnitValue);//剩余不整一个刻度的数值int residueWidth=(currentValue-minValue)%minUnitValue;//开始画图的X轴位置int startCursor=(getWidth()/2)-(marginWidth*integerWidth)-(int)(marginWidth*(float)residueWidth/minUnitValue);for(int i=0;i<(maxValue/minUnitValue)+1;i++){float xValue=startCursor+(marginWidth*i);if(i%10==0){//画长刻度linePaint.setColor(textColor);canvas.drawText((minCurrentValue*i)+"",xValue,getHeight()-longCursor-marginCursorData,linePaint);linePaint.setColor(dividerColor);canvas.drawLine(xValue,getHeight(),xValue,getHeight()-longCursor,linePaint);}else{//画短刻度canvas.drawLine(xValue,getHeight(),xValue,getHeight()-shortCursor,linePaint);}}}    

在drawBaseView()方法里,也很简单,就是在二分之一宽度,画一条直线,然后在控价的底部画出宽度为整个控件的宽度的底线。接着在下方法里

drawBaseView(Canvas canvas)
  1. 首先用当前值(currentValue)-最小值(minValue)之后再除于最小单位值(minUnitValue)以获取整数刻度的个数

  1. 因为有余数的情况,我们再当前值(currentValue)-最小值(minValue)之后求余与最小单位值(minUnitValue)以获取余数

  1. 接着我们要获取我们画图的X轴开始的位置,因为最小值只能滑到中间,所以开始的位置为控件一半的宽度(getWidth()/2)
    减去计算每个刻度的间距(marginWidth)乘以整数刻度的个数(integerWidth)即marginWidth*integerWidth再减去余数对应所产生的X轴距离即 :

(int)(marginWidth*(float)residueWidth/minUnitValue)

4、再通过For循环刻度的个数,不同的进行刻度的绘画,当i%10==0时即为一个大的单位刻度否者为一个小的单位刻度,具体代码我上面已有注释,原理和画中间线一直就不在赘述。

到此我们就已经把自定义控价静态的部分写完了,效果如下:

接着我们用GestureDetector绑定手势事件,根据回调手势事件的方法来改变数据和刷新页面,在GestureDetector里,我们只会回调:

//手指在触摸屏上滑动
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)//手指在触摸屏上迅速移动,并松开的动作
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)

这两个方法就可以了。

具体代码如下:

private GestureDetector.SimpleOnGestureListener myGestureListener =new  GestureDetector.SimpleOnGestureListener(){@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {//滑动刷新UIupdateView(rollingWidth+(int)distanceX,isScrollingState);return true;}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {//快速滑动的动画scroller.fling(rollingWidth,0,(int)(-velocityX/1.5),0,0,(maxValue/minUnitValue)*marginWidth,0,0);return true;}};//动态更新滑动View
public void updateView(int srcollWidth,int action){if(action==isScrollingState){//正在滑动状态(onScroll())rollingWidth=srcollWidth;float itemNum=(float)srcollWidth/marginWidth;currentValue=(int)(minUnitValue*itemNum);}else if(action==fastScrollState){//快速一滑(onFling())rollingWidth=srcollWidth;int itemNum=(int)Math.rint((float)rollingWidth/marginWidth);currentValue=(minUnitValue*itemNum);}else if(action==finishScrollState){//结束滑动(ACTION_UP)int itemNum=(int)Math.rint((float)rollingWidth/marginWidth);currentValue=minUnitValue*itemNum;}//判断是否在最小选择值if(currentValue<=minCurrentValue){rollingWidth=(minCurrentValue/minUnitValue)*marginWidth;currentValue=minCurrentValue;}//判断是否在最大值if(currentValue>=maxValue){rollingWidth=marginWidth*allCursorNum();currentValue=maxValue;}//回调数值if(slideRulerDataInterface!=null){slideRulerDataInterface.getText(currentValue+"");}invalidate();
} 
  1. 当我们滑动我们的控件是,就会回调GestureDetector里的onScroll()方法,然后rollingWidth+(int)distanceX即当前滑动的宽度(rollingWidth)加上滑动产生的宽度(distanceX)为动态产生的宽度,再除于计算每个刻度的间距(marginWidth)从而得到刻度的数量,有了刻度的数量即可得到当前值

currentValue=(int)(minUnitValue*itemNum);

有了当前值调用invalidate();刷新onDraw()即可完成连续滑动时动态绘制。

  1. 当我们快速一划时,就会回调GestureDetector里的onFling()方法,在方法里用

scroller.fling(rollingWidth,0,(int)(-velocityX/1.5),0,0,(maxValue/minUnitValue)*marginWidth,0,0);

以实现滑动有一个好的动画效果,此时在如下代码里:

  @Overridepublic void computeScroll() {if(scroller.computeScrollOffset()){//快滑刷新UIupdateView(scroller.getCurrX(),fastScrollState);}}
scroller.computeScrollOffset()==true;而scroller.getCurrX()

就相当于为动态产生的滑动宽度剩下的也是调用updateView()方法不断的刷新,当

scroller.computeScrollOffset()==false

就滑动动画结束了。

  1. 最后当我们滑动结束手指抬起时:

    @Overridepublic boolean onTouchEvent(MotionEvent event) {switch(event.getAction()){case MotionEvent.ACTION_UP:updateView(0,finishScrollState);default:mDetector.onTouchEvent(event);break;}return true;}

我们也要掉updateView(),以保持滑动的最后结构都指在指针上。

源码地址:

https://github.com/gaojuanjuan/MaterialDesign_V7

相关文章:

Android仿京东金融的数值滚动尺功能

自定义数值滚动尺,这个用的还是挺多的&#xff0c;例如京东金融的通过滚动尺选择金额等,而这次就是高仿京东金融的数值滚动尺。首先看看下效果图&#xff0c;如下&#xff1a;首先先给你们各个变量的含义&#xff0c;以免在后面的讲解中不知变量的意思&#xff0c;代码如下://最…...

Nginx 和 Tomcat 实现负载均衡

Nginx 和 tomcat 实现负载均衡 &#x1f3c6;荣誉认证&#xff1a;51CTO博客专家博主、TOP红人、明日之星&#xff1b;阿里云开发者社区专家博主、技术博主、星级博主。 &#x1f4bb;微信公众号&#xff1a;微笑的段嘉许 &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &am…...

【万能排序之qsort、b_sort 、s_sort】

文章目录前言:star:qsort函数函数参数qsort函数的使用:star:模拟实现万冒泡排序函数参数模拟实现b_sort注意点:star:模拟实现万能选择排序函数参数模拟实现s_sort最后前言 我们所熟悉的冒泡排序&#xff0c;选择排序&#xff0c;插入排序&#xff0c;二分排序等都是基于给定的一…...

利用InceptionV3实现图像分类

最近在做一个机审的项目&#xff0c;初步希望实现图像的四分类&#xff0c;即&#xff1a;正常&#xff08;neutral&#xff09;、涉政&#xff08;political&#xff09;、涉黄&#xff08;porn&#xff09;、涉恐&#xff08;terrorism&#xff09;。有朋友给推荐了个github上…...

【Java】CAS锁

一、什么是CAS机制&#xff08;compare and swap&#xff09; 1.概述 CAS的全称为Compare-And-Swap&#xff0c;直译就是对比交换。是一条CPU的原子指令&#xff0c;其作用是让CPU先进行比较两个值是否相等&#xff0c;然后原子地更新某个位置的值。经过调查发现&#xff0c;…...

Linux服务器配置系统安全加固方法

1. SSH空闲超时时间建议为: 600-900 解决方案: 在【/etc/ssh/sshd_config】文件中设置【ClientAliveInterval】设置为600到900之间 vim /etc/ssh/sshd_config #将 ClientAliveInterval 参数值设置为 900 2. 修改检查SSH密码修改最小间隔 解决方案: 在【/etc/login.defs】文件…...

Codeforces Round #850 (Div. 2, based on VK Cup 2022 - Final Round)(A~E)

t宝酱紫喜欢出这种分类讨论的题&#xff1f;&#xff01;A1. Non-alternating Deck (easy version)给出n张牌&#xff0c;按照题目给的顺序分给两人&#xff0c;问最后两人手中各有几张牌。思路&#xff1a;模拟。AC Code&#xff1a;#include <bits/stdc.h>typedef long…...

qt源码--信号槽

本篇主要从Qt信号槽的连接、断开、调用、对象释放等方面展开&#xff1b; 1.信号建立连接过程 connect有多个重载函数&#xff0c;主要是为了方便使用者&#xff0c;比较常用的有2种方式&#xff1a; a. QObject::connect(&timer, &QTimer::timeout, &loop, &am…...

RecycleView详解

listview缓存请看: listview优化和详解RecycleView 和 ListView对比&#xff1a;使用方法上ListView&#xff1a;继承重写 BaseAdapter&#xff0c;自定义 ViewHolder 与 converView优化。RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 Layou…...

【算法】最短路算法

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…...

< Linux > 进程间通信

目录 1、进程间通信介绍 进程间通信的概念 进程间通信的本质 进程间通信的分类 2、管道 2.1、什么是管道 2.2、匿名管道 匿名管道的原理 pipe函数 匿名管道使用步骤 2.3、管道的读写规则 2.4、管道的特点 2.5、命名管道 命名管道的原理 使用命令创建命名管道 mkfifo创建命名管…...

学习 Python 之 Pygame 开发魂斗罗(二)

学习 Python 之 Pygame 开发魂斗罗&#xff08;二&#xff09;魂斗罗的需求开始编写魂斗罗1. 搭建主类框架2. 设置游戏运行遍历和创建窗口3. 获取窗口中的事件4. 创建角色5. 完成角色更新函数魂斗罗的需求 魂斗罗游戏中包含很多个物体&#xff0c;现在要对这些物体进行总结 类…...

户籍管理系统测试用例

目录 一、根据页面的不同分别设计测试用例 登录页面 用户信息列表 用户编辑页面 用户更新页面 二、根据目的不同分别设计测试用例 一、根据页面的不同分别设计测试用例 上图是针对一个网站的测试&#xff0c;按照页面的不同分别来设计对应的测试用例。 登录页面 用户信息列…...

(三)代表性物质点邻域的变形分析

本文主要内容如下&#xff1a;1. 伸长张量与Cauchy-Green 张量2. 线元长度的改变2.1. 初始/当前构型下的长度比2.2. 主长度比与 Lagrange/Euler 主方向2.3. 初始/当前构型下任意方向的长度比3. 线元夹角的改变4. 面元的改变5. 体元的改变1. 伸长张量与Cauchy-Green 张量 由于变…...

Stream操作流 练习

基础数据&#xff1a;Data AllArgsConstructor NoArgsConstructor public class User {private String name;private int age;private String sex;private String city;private Integer money; static List<User> users new ArrayList<>();public static void m…...

【模拟集成电路】宽摆幅压控振荡器(VCO)设计

鉴频鉴相器设计&#xff08;Phase Frequency Detector&#xff0c;PFD&#xff09;前言一、VCO工作原理二、VCO电路设计VCO原理图三、压控振荡器&#xff08;VCO&#xff09;测试VCO测试电路图瞬态测试&#xff08;1&#xff09;瞬态输出&#xff08;2&#xff09;局部放大图&a…...

《英雄编程体验课》第 13 课 | 双指针

文章目录 零、写在前面一、最长不重复子串1、初步分析2、朴素算法3、优化算法二、双指针1、算法定义2、算法描述3、条件1)单调性2)时效性三、双指针的应用1、前缀和问题2、哈希问题3、K 大数问题零、写在前面 该章节节选自 《夜深人静写算法》,主要讲解最基础的枚举算法 ——…...

DS期末复习卷(十)

一、选择题(24分) 1&#xff0e;下列程序段的时间复杂度为&#xff08; A &#xff09;。 i0&#xff0c;s0&#xff1b; while (s<n) {ssi&#xff1b;i&#xff1b;} (A) O(n^1/2) (B) O(n ^1/3) © O(n) (D) O(n ^2) 12…xn xn^1/2 2&#xff0e;设某链表中最常用的…...

QT+OpenGL模板测试和混合

QTOpenGL模板测试和混合 本篇完整工程见gitee:QtOpenGL 对应点的tag&#xff0c;由turbolove提供技术支持&#xff0c;您可以关注博主或者私信博主 模板测试 当片段着色器处理完一个片段之后&#xff0c;模板测试会开始执行。和深度测试一样&#xff0c;它可能会丢弃片段&am…...

《英雄编程体验课》第 11 课 | 前缀和

文章目录 零、写在前面一、概念定义1、部分和2、朴素做法3、前缀和4、前缀和的边界值5、边界处理6、再看部分和二、题目描述1、定义2、求解三、算法详解四、源码剖析五、推荐专栏六、习题练习零、写在前面 该章节节选自 《算法零基础100讲》,主要讲解最基础的算法 —— 前缀和…...

为什么92%的ElevenLabs山东话项目上线失败?——5大隐性技术红线与3种合规替代方案(附GitHub可运行Demo)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;山东话语音合成落地失败的行业现象与本质归因 山东话语音合成项目在政务热线、乡村广播、文旅导览等场景中频繁试点&#xff0c;但超76%的落地项目在6个月内被迫下线。用户反馈集中于“听不懂”“像普通…...

实测好用降AI工具盘点 2026高性价比首选

前言 刚完成毕业答辩的过来人真心建议&#xff0c;别再跟论文AI检测死磕了&#xff01;我当初对着检测报告上飘红的高风险提示熬了好几个通宵&#xff0c;自己改了三版&#xff0c;导师扫了两眼就说“AI痕迹太重&#xff0c;回去重改”。那段时间我把市面上能找到的降AI工具试了…...

别再死记硬背真值表了!用C++和Verilog代码实战,5分钟搞懂所有逻辑门

用代码实战解锁逻辑门&#xff1a;从C到Verilog的沉浸式学习 第一次接触数字逻辑时&#xff0c;那些密密麻麻的真值表总让人望而生畏。与其机械记忆&#xff0c;不如打开代码编辑器&#xff0c;让程序运行结果告诉你逻辑门的秘密。本文将带你用两种语言&#xff08;C和Verilog&…...

如何快速上手OpenBoardView:免费开源PCB查看器的完整指南

如何快速上手OpenBoardView&#xff1a;免费开源PCB查看器的完整指南 【免费下载链接】OpenBoardView View .brd files 项目地址: https://gitcode.com/gh_mirrors/op/OpenBoardView OpenBoardView是一款完全免费开源的PCB文件查看器&#xff0c;专门用于查看和分析各种…...

1993-2025年《中国汽车工业年鉴》Excel/PDF格式

一、资源介绍图片今日数据&#xff1a;《中国汽车工业年鉴》1993~2025《中国汽车工业年鉴》汇聚全国汽车行业最新最全的数据资讯。从宏观经济指标到微观企业动态&#xff0c;从整车产销到零部件配套&#xff0c;从燃油车到新能源汽车&#xff0c;每一页都记录着中国汽车工业发展…...

程序员会被产品经理替代吗?——当AI让“全栈”成为常态,我们的价值在哪里?

程序员会被产品经理替代吗&#xff1f;——当AI让“全栈”成为常态&#xff0c;我们的价值在哪里&#xff1f; 最近&#xff0c;V2EX上一个帖子引发了激烈讨论&#xff1a;随着AI能力的指数级增长&#xff0c;一个人就能完成从前需要整个团队才能做到的全栈开发。如果产品经理借…...

抢先揭秘 |高端进口宠物食品用品代理商睿哲国际即将亮相广州潮宠展GPI+

抢先揭秘 |高端进口宠物食品用品代理商睿哲国际即将亮相广州潮宠展GPI第四届广州国际潮宠展暨全球宠业生态创新展&#xff08;GPI&#xff09;将于6月5-7日在广州保利世贸博览馆盛大启幕&#xff01;本届展会以“宠业当燃”为全新主题&#xff0c;打造超5万㎡三馆联动的全域生态…...

DeltaV私有协议逆向分析与流量识别实战

1. 这不是普通工控协议——DeltaV私有协议为何让安全团队彻夜难眠Emerson DeltaV&#xff0c;这个名字在石化、制药、精细化工等连续流程工业现场几乎等同于“控制系统心脏”。但真正让一线自动化工程师和网络安全人员同时皱眉的&#xff0c;从来不是它那套成熟稳定的DCS架构&a…...

终极Windows与Office智能激活解决方案:KMS_VL_ALL_AIO全面解析与实战指南

终极Windows与Office智能激活解决方案&#xff1a;KMS_VL_ALL_AIO全面解析与实战指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO KMS_VL_ALL_AIO是一款功能强大的Windows与Office智能激活脚…...

mpv.net 高效配置实战:从媒体播放到专业调优的进阶指南

mpv.net 高效配置实战&#xff1a;从媒体播放到专业调优的进阶指南 【免费下载链接】mpv.net &#x1f39e; mpv.net is a media player for Windows with a modern GUI. 项目地址: https://gitcode.com/gh_mirrors/mp/mpv.net 作为一款基于mpv核心的现代化Windows媒体播…...