Android 开发之 ToggleButton App 滑动开关按钮
来源:互联网 发布:淘宝美工全攻略阅读 编辑:程序博客网 时间:2024/05/21 08:42
现在很多项目都有推送这一块的功能,而用户不一定想看到这些推送,这时候开关按钮就是必须的了,让用户自己设置通知管理。android开发中我也自己写过一个自定义的view,虽然实现了效果不过感觉有点(动画效果)生硬,原理根据Touch 的距离和滑动速度判断开关,指向Toggle的回调函数,以及onClick执行相关毁掉。今日闲来无事,找到个比较满意的开关效果,github地址:https://github.com/zcweng/ToggleButton,效果图如下:
先看看自定义控件ToggleButton,该类调用了onDetachedFromWindow、onAttachedToWindow这两个方法,onAttachedToWindow方法作用是在自定义View
onDraw以前调用,用于绑定相关的监听事件,onDetachedFromWindow则想法,取消相关的监听事件。具体代码如下:
@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();spring.removeListener(springListener);}public void onAttachedToWindow() {super.onAttachedToWindow();spring.addListener(springListener);}
SimpleSpringListener springListener = new SimpleSpringListener(){@Overridepublic void onSpringUpdate(Spring spring) {final double value = spring.getCurrentValue();calculateEffect(value);}};
public ToggleButton(Context context) {this(context,null);}public ToggleButton(Context context, AttributeSet attrs) {this(context, attrs,0);}public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setup(attrs);}
setup(attrs)这里通过TypedArray获取自定义属性值,变量重新赋值,同时绑定自身onClick事件到Toggle。
public void setup(AttributeSet attrs) {paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setStyle(Style.FILL);paint.setStrokeCap(Cap.ROUND);springSystem = SpringSystem.create();spring = springSystem.createSpring();spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(50, 7));this.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {toggle(defaultAnimate);}});TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ToggleButton);offBorderColor = typedArray.getColor(R.styleable.ToggleButton_offBorderColor, offBorderColor);onColor = typedArray.getColor(R.styleable.ToggleButton_onColor, onColor);spotColor = typedArray.getColor(R.styleable.ToggleButton_spotColor, spotColor);offColor = typedArray.getColor(R.styleable.ToggleButton_offColor, offColor);borderWidth = typedArray.getDimensionPixelSize(R.styleable.ToggleButton_borderWidth, borderWidth);defaultAnimate = typedArray.getBoolean(R.styleable.ToggleButton_animate, defaultAnimate);typedArray.recycle();borderColor = offBorderColor;}
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="ToggleButton"> <attr name="borderWidth" format="dimension"> </attr> <attr name="offBorderColor" format="reference|color"> </attr> <attr name="offColor" format="reference|color"> </attr> <attr name="onColor" format="reference|color"> </attr> <attr name="spotColor" format="reference|color"> </attr> <attr name="animate" format="reference|boolean"> </attr> </declare-styleable></resources>
接下来是自定义控件的测量onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法重新测量View和内容,onMeasure方法调用就必须重新Measure保存测量到的宽高,否则measure会抛出异常。先来看看MeasureSpec:
public static class MeasureSpec { private static final int MODE_SHIFT = 30; private static final int MODE_MASK = 0x3 << MODE_SHIFT; /** * Measure specification mode: The parent has not imposed any constraint * on the child. It can be whatever size it wants. */ public static final int UNSPECIFIED = 0 << MODE_SHIFT; /** * Measure specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */ public static final int EXACTLY = 1 << MODE_SHIFT; /** * Measure specification mode: The child can be as large as it wants up * to the specified size. */ public static final int AT_MOST = 2 << MODE_SHIFT;<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> ....此处省略</span>
每个MeasureSpec都有一个Size和Mode,而Mode分三种:MeasureSpec.UNSPECIFIED、MeasureSpec.AT_MOST、MeasureSpec.EXACTLY。
unspecified:父布局对子布局没有任何限制,子布局可以是它想要的任何尺寸。exactly:父布局限制了子布局的绝对宽高,子布局将会被赋予这些边界限制.at-most:子布局可以是自己任意的大小,但是有个绝对尺寸的上限。下面来看看该类的onMeasure代码:
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {final int widthMode = MeasureSpec.getMode(widthMeasureSpec);final int heightMode = MeasureSpec.getMode(heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);Resources r = Resources.getSystem();if(widthMode == MeasureSpec.UNSPECIFIED || widthMode == MeasureSpec.AT_MOST){widthSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, r.getDisplayMetrics());widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);}if(heightMode == MeasureSpec.UNSPECIFIED || heightSize == MeasureSpec.AT_MOST){heightSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, r.getDisplayMetrics());heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}
@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);final int width = getWidth();final int height = getHeight();radius = Math.min(width, height) * 0.5f;centerY = radius;startX = radius;endX = width - radius;spotMinX = startX + borderWidth;spotMaxX = endX - borderWidth;spotSize = height - 4 * borderWidth;spotX = toggleOn ? spotMaxX : spotMinX;offLineWidth = 0;}
@Overridepublic void draw(Canvas canvas) {//rect.set(0, 0, getWidth(), getHeight());paint.setColor(borderColor);canvas.drawRoundRect(rect, radius, radius, paint);if(offLineWidth > 0){final float cy = offLineWidth * 0.5f;rect.set(spotX - cy, centerY - cy, endX + cy, centerY + cy);paint.setColor(offColor);canvas.drawRoundRect(rect, cy, cy, paint);} ............此处省略paint.setColor(spotColor);canvas.drawRoundRect(rect, spotR, spotR, paint);}对于Paint的配置paint.setStrokeCap(Cap.ROUND);画笔笔刷类型 如影响画笔但始末端, paint.setStrokeJoin(Paint.Join.ROUND); 画笔接洽点类型 如影响矩形但角的外轮廓,对于该项目setup里面springSystem这块理解不够透彻:
经过一番折腾,得到结果如下:“Choreographer就是一个消息处理器,根据vsync 信号 来计算frame,而计算frame的方式就是处理三种回调,包括事件回调、动画回调、绘制回调。这三种事件在消息输入、加入动画、准备绘图layout 等动作时均会发给Choreographer。”
public static SpringLooper createSpringLooper() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { return ChoreographerAndroidSpringLooper.create(); } else { return LegacyAndroidSpringLooper.create(); } }
这里项目走版本分支获取SpringLooper,从而注册BaseSpringSystem,在深入暂不涉及,参考相关资料:http://blog.csdn.net/farmer_cc/article/details/18619429,相关demo下载地址:http://download.csdn.net/detail/analyzesystem/8905455
- Android 开发之 ToggleButton App 滑动开关按钮
- Android 开发 ToggleButton 滑动开关按钮
- Android-开关按钮ToggleButton
- Android ToggleButton 开关按钮
- Android学习路之开关按钮ToggleButton和开关Switch
- Android 自定义滑动开关ToggleButton
- Android 滑动开关(ToggleButton) 解析
- Android ToggleButton Example--开关按钮
- Android---19---ToggleButton开关按钮
- 【Android 开发】:UI控件之开关状态按钮 ToggleButton 的使用方法
- android滑动开关按钮
- Android 滑动开关按钮
- Android的ToggleButton实现开关按钮
- 自定义滑动开关(ToggleButton)
- 开关按钮ToggleButton
- ToggleButton开关按钮
- ToggleButton开关按钮使用
- ToggleButton(开关按钮)
- 深度学习必读的一些资料
- Qt学习之路(4):初探信号槽 转
- c_结构体多文件
- hdoj 4612 Warm up 【无向图边双连通求桥数 缩点后求树的直径 桥数-树的直径】
- PB权限控制的完整方案
- Android 开发之 ToggleButton App 滑动开关按钮
- 装双SATA硬盘蓝屏问题
- Algorithms—105.Construct Binary Tree from Preorder and Inorder Traversal
- 数据库分库分表(sharding)系列
- hdu 1075 What Are You Talking About(map)
- 原创CSDN博客阅读器
- Mac下intellij idea环境的项目的新建、配色、快捷键的配置
- c_函数
- linux线程