Android自定义开关按钮源码解析
更新时间:2021年8月25日 16:00 点击:1451
本文实例为大家分享了Android自定义开关的具体代码,供大家参考,具体内容如下
以 ToggleColorY 为例分析, ToggleImageY逻辑代码差不多
初始化参数
获取背景颜色,按钮颜色,开关状态
@SuppressLint("ResourceAsColor") private void initParame(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ToggleColorY, defStyleAttr, 0); mOpenBGColor = typedArray.getColor(R.styleable.ToggleColorY_tby_open_bg, getResources().getColor(R.color.tby_orange)); mCloseBGColor = typedArray.getColor(R.styleable.ToggleColorY_tby_close_bg, getResources().getColor(R.color.tby_gray)); mTouchColor = typedArray.getColor(R.styleable.ToggleColorY_tby_touch, getResources().getColor(R.color.tby_read)); mIsOpen = typedArray.getBoolean(R.styleable.ToggleColorY_tby_state, false); typedArray.recycle(); }
初始化画笔和 RectF
// Paint.Style.FILL设置只绘制图形内容 // Paint.Style.STROKE设置只绘制图形的边 // Paint.Style.FILL_AND_STROKE设置都绘制 private void initPaint() { //开关 开背景 mOpenBGPaint = new Paint(); mOpenBGPaint.setAntiAlias(true); mOpenBGPaint.setStyle(Paint.Style.FILL_AND_STROKE); mOpenBGPaint.setColor(mOpenBGColor); //开关 关背景 mCloseBGPaint = new Paint(); mCloseBGPaint.setAntiAlias(true); mCloseBGPaint.setStyle(Paint.Style.FILL_AND_STROKE); mCloseBGPaint.setColor(mCloseBGColor); //Touch 圆形 mTouchPaint = new Paint(); mTouchPaint.setAntiAlias(true); mTouchPaint.setStyle(Paint.Style.FILL_AND_STROKE); mTouchPaint.setColor(mTouchColor); //开 RectF mRectFOpen = new RectF(); //关 RectF mRectFClose = new RectF(); }
在 onLayout 时获取整个控件宽高,并且设置 RectF 尺寸
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mWidth = getWidth(); mHeight = getHeight(); initView(); } private void initView() { mRectFClose.set(0, 0, mWidth, mHeight); mRectFOpen.set(0, 0, mWidth, mHeight); }
绘制开关初始状态以及滑动按钮得初始状态
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //开关初始状态 if (mIsOpen) { canvas.drawRoundRect(mRectFOpen, mHeight / 2, mHeight / 2, mOpenBGPaint);//开 } else { canvas.drawRoundRect(mRectFClose, mHeight / 2, mHeight / 2, mCloseBGPaint);//关 } firstDraw(); //绘制滑动按钮 canvas.drawCircle(mSlidingDistance, mHeight / 2, mHeight / 2, mTouchPaint); } /** * 根据开关初始状态设置滑动按钮位置 */ private void firstDraw() { if (!mIsFirst) { if (mIsOpen) { mSlidingDistance = mWidth - mHeight / 2; } else { mSlidingDistance = mHeight / 2; } mIsFirst = !mIsFirst; } }
剩下就是处理开关的滑动和点击
- Down->Up, 点击事件.
- Down->Move->Up,滑动事件
此处分Move小于一定距离也认为是点击,只有Move距离大于定值才认为是一个滑动事件组
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //mLastX 是记录手指按下的点X坐标值 //mStartX 表示的是当前滑动的起始点X坐标值 mLastX = mStartX = event.getX(); //2种情况 //1, Down->Up,若是这个顺序,手指抬起时候,按照点击逻辑切换开关 //2, Down->Move->Up,若是这个顺序, 手指抬起时候, 就按照滑动逻辑切换开关 mIsEnableClick = true; break; case MotionEvent.ACTION_MOVE: float mEndX = event.getX(); //滑动起始坐标与滑动后坐标值相减,得到手指移动距离 float distanceX = mEndX - mStartX; //对手指移动距离进行累加,这个距离是圆心X轴坐标 mSlidingDistance += distanceX; //判断左右两个临界值,不能超出左右侧边值 if (mSlidingDistance < mHeight / 2) { mSlidingDistance = mHeight / 2; } if (mSlidingDistance >= mWidth - mHeight / 2) { mSlidingDistance = mWidth - mHeight / 2; } //重绘,到这一步,圆就随手指开始移动了 invalidate(); //手指按下坐标与滑动最后坐标差值 float mMinDistanceX = Math.abs(mEndX - mLastX); //判断差值 //1,如果差值大于8, 则认为是滑动, 如果用户松开按钮则按照滑动条件判断 //1,如果差值小于8, 则认为是点击, 如果用户此时松开按钮则按照点击条件判断 if (mMinDistanceX > 8) { mIsEnableClick = false; } else { mIsEnableClick = true; } //更新滑动X轴起始坐标,为下一次Move事件滑动做准备 mStartX = event.getX(); break; case MotionEvent.ACTION_UP: if (!mIsEnableClick) { //当判定为滑动时, 首先判断这次滑动累加的距离, 如果大于一半则开关取反 if (mSlidingDistance >= mWidth / 2) { mIsOpen = true; } else { mIsOpen = false; } //设置好开关Flag,执行替换背景 drawToggle(); } else { mIsOpen = !mIsOpen; drawToggle(); } break; } return true; } /** * 按钮重绘 */ public void drawToggle() { if (mIsOpen) { //开 mSlidingDistance = mWidth - mHeight / 2; } else { //关 mSlidingDistance = mHeight / 2; } if (onClick != null) { onClick.click(mIsOpen); } invalidate(); }
项目地址
效果图
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
相关文章
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
- 下面小编就为大家带来一篇利用JS实现点击按钮后图片自动切换的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
- java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
- TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
android.os.BinderProxy cannot be cast to com解决办法
本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20- 这篇文章主要为大家详细解析了BootStrap栅格系统、表单样式与按钮样式源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-01-23
- 这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
- 下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
- 首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
- 下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
用Intel HAXM给Android模拟器Emulator加速
Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20- 在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
Android开发中布局中的onClick简单完成多控件时的监听的利与弊
本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20