Android-自定义开关(升级版)
效果图:
定义一个类,取名为MySwitch.java,此类去继承View,为何是继承View而不是去继承ViewGroup呢,是因为自定义开关没有子控件,之需要操作自身绘制即可
- package custom.view.upgrade.my_switch;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.drawable.BitmapDrawable;
- import android.graphics.drawable.Drawable;
- import android.support.annotation.Nullable;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- import custom.view.R;
- public class MySwitch extends View implements View.OnClickListener {
- private static String TAG = MySwitch.class.getSimpleName();
- private Paint mPaint;
- /**
- * 让布局中来指定实例化,得到属性集合AttributeSet
- * @param context
- * @param attrs
- */
- public MySwitch(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- initView(context, attrs);
- initListener();
- }
- // 定义按钮背景图片
- private Bitmap bmSwitchBackground;
- // 定义按钮拖动的图片
- private Bitmap bmSwitchDrag;
- // 定义开关的状态 true || false , 默认是关闭状态
- private boolean switchStatus;
- // 定义开关的临时记录状态
- private boolean tempSwitchStatus;
- // 定义按钮拖动距离左边的距离
- private int dragLife = -1;
- /**
- * 初始化工作
- */
- private void initView(Context context, AttributeSet attrs) {
- mPaint = new Paint();
- mPaint.setAntiAlias(true); // 抗锯齿
- // 获取属性
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MySwitch);
- bmSwitchBackground = ((BitmapDrawable) typedArray.getDrawable(R.styleable.MySwitch_switch_background)).getBitmap();
- bmSwitchDrag = ((BitmapDrawable) typedArray.getDrawable(R.styleable.MySwitch_switch_drag)).getBitmap();
- switchStatus = typedArray.getBoolean(R.styleable.MySwitch_switch_status, false);
- }
- public void setBmSwitchBackground(int switchBackground) {
- this.bmSwitchBackground = BitmapFactory.decodeResource(getResources() ,switchBackground);
- }
- public void setBmSwitchDrag(int switchDrag) {
- this.bmSwitchDrag = BitmapFactory.decodeResource(getResources(), switchDrag);
- }
- public void setSwitChStatus(boolean switchStatus) {
- this.switchStatus = switchStatus;
- dragLife = -1;
- }
- /**
- * 初始化事件
- */
- private void initListener() {
- setOnClickListener(this);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- // 宽度是:按钮背景的宽度
- // 高度是:按钮背景的高度
- // 测量自身View
- setMeasuredDimension(bmSwitchBackground.getWidth(), bmSwitchBackground.getHeight());
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- // 绘制按钮背景
- canvas.drawBitmap(bmSwitchBackground, 0, 0, mPaint);
- if (dragLife != -1) {
- canvas.drawBitmap(bmSwitchDrag, dragLife, 0 , mPaint);
- } else if (dragLife == -1) {
- if (switchStatus) {
- // 打开状态
- // 滑动点向右就是开启状态
- int openDragLife = getLifeDragMaxValue();
- canvas.drawBitmap(bmSwitchDrag, openDragLife, 0, mPaint);
- moveEndX = openDragLife;
- } else {
- // 关闭状态
- canvas.drawBitmap(bmSwitchDrag, 0, 0, mPaint);
- moveEndX = 0;
- }
- // 当开关的状态发生变化后,回调方法告诉用户,开关改变了
- if (null != onSwitchChangeListener && switchStatusChange) {
- if (tempSwitchStatus != switchStatus) {
- onSwitchChangeListener.onSwitchChange(switchStatus);
- }
- }
- }
- }
- private float downX;
- private int moveEndX;
- private float clickDown;
- private float clickMove;
- // 开关状态是否发送了改变
- private boolean switchStatusChange;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event); // 必须要调用此方法,onClick点击事件方法才会生效
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- downX = event.getX();
- isClick = true;
- clickDown = event.getX();
- switchStatusChange = false;
- tempSwitchStatus = switchStatus;
- break;
- case MotionEvent.ACTION_MOVE:
- // Log.d(TAG, ">>>>>不加等于:" + (int) (event.getX() - downX));
- moveEndX += (int) (event.getX() - downX);
- Log.d(TAG,">>>>>>加等于:" + moveEndX);
- if (moveEndX > getLifeDragMaxValue()) {
- moveEndX = getLifeDragMaxValue();
- } else if (moveEndX < 0){
- moveEndX = 0;
- }
- dragLife = moveEndX;
- invalidate();
- downX = event.getX();
- clickMove = downX;
- if (Math.abs(clickMove - clickDown) > 5) {
- isClick = false;
- }
- break;
- case MotionEvent.ACTION_UP:
- if (dragLife > (getLifeDragMaxValue() / 2)) {
- dragLife = -1;
- switchStatus = true;
- switchStatusChange = true;
- } else if (dragLife >= 0){
- dragLife = -1;
- switchStatus = false;
- switchStatusChange = true;
- } else {
- switchStatusChange = false;
- }
- invalidate();
- // upX = (int) event.getX();
- break;
- default:
- break;
- }
- return true;
- }
- private int getLifeDragMaxValue() {
- return bmSwitchBackground.getWidth() - bmSwitchDrag.getWidth();
- }
- /*@Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (switchStatus) {
- moveEndX = getLifeDragMaxValue();
- Log.d(TAG, ">>>>>>>>>>>>>>>>>onFinishInflate()............ getLifeDragMaxValue():" + getLifeDragMaxValue());
- }
- }*/
- /**
- * 定义点击事件状态
- */
- private boolean isClick = true;
- @Override
- public void onClick(View v) {
- Log.d(TAG, "onClick() isClick:" + isClick);
- if (isClick) {
- if (switchStatus) {
- switchStatus = false;
- switchStatusChange = true;
- } else {
- switchStatus = true;
- switchStatusChange = true;
- }
- // switchStatus = (switchStatus==true?false:true);
- dragLife = -1;
- invalidate();
- }
- }
- private OnSwitchChangeListener onSwitchChangeListener;
- /**
- * 用户设置的 状态监听
- * @param onSwitchChangeListener
- */
- public void setOnSwitchChangeListener(OnSwitchChangeListener onSwitchChangeListener) {
- this.onSwitchChangeListener = onSwitchChangeListener;
- }
- }
布局文件中去引用写好的自定义开关类
并设置自定义属性:
- myswitch:switch_background="@mipmap/switch_background"
- myswitch:switch_drag="@mipmap/switch_drag"
- myswitch:switch_status="true"
- <!-- 自定义开关升级版 -->
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:myswitch="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".upgrade.MainActivity">
- <!-- 使用wrap_content,是因为不知道按钮的背景有多大,更加按钮图片的改变而变化 -->
- <custom.view.upgrade.my_switch.MySwitch
- android:id="@+id/custom_myswitch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- myswitch:switch_background="@mipmap/switch_background"
- myswitch:switch_drag="@mipmap/switch_drag"
- myswitch:switch_status="true"
- />
- </RelativeLayout>
自定义规则arrts.xml文件声明:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="MySwitch">
- <attr name="switch_status" format="boolean" />
- <attr name="switch_background" format="reference" />
- <attr name="switch_drag" format="reference" />
- </declare-styleable>
- </resources>
模拟用户来使用:
- MySwitch mySwitch = findViewById(R.id.custom_myswitch);
- // 设置开关的背景图片
- mySwitch.setBmSwitchBackground(R.mipmap.switch_background);
- // 设置开关拖动的图片
- mySwitch.setBmSwitchDrag(R.mipmap.switch_drag);
- // 设置开关的状态,打开、关闭
- mySwitch.setSwitChStatus(false);
- mySwitch.setOnSwitchChangeListener(new OnSwitchChangeListener() {
- @Override
- public void onSwitchChange(boolean switchChangeStatus) {
- String result;
- if (switchChangeStatus) {
- result = "打开";
- } else {
- result = "关闭";
- }
- Toast.makeText(MainActivity.this, "开关已" + result, Toast.LENGTH_SHORT).show();
- }
- });
Android-自定义开关(升级版)的更多相关文章
- Android 自定义 View 绘制
在 Android 自定义View 里面,介绍了自定义的View的基本概念.同时在 Android 控件架构及View.ViewGroup的测量 里面介绍了 Android 的坐标系 View.Vie ...
- android 自定义动画
android自定义动画注意是继承Animation,重写里面的initialize和applyTransformation,在initialize方法做一些初始化的工作,在applyTransfor ...
- Android自定义View 画弧形,文字,并增加动画效果
一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类 B ...
- Android自定义View4——统计图View
1.介绍 周末在逛慕课网的时候,看到了一张学习计划报告图,详细记录了自己一周的学习情况,天天都是0节课啊!正好在学习Android自定义View,于是就想着自己去写了一个,这里先给出一张慕课网的图,和 ...
- (转)[原] Android 自定义View 密码框 例子
遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- Android 自定义View (五)——实践
前言: 前面已经介绍了<Android 自定义 view(四)-- onMeasure 方法理解>,那么这次我们就来小实践下吧 任务: 公司现有两个任务需要我完成 (1)监测液化天然气液压 ...
- Android 自定义 view(四)—— onMeasure 方法理解
前言: 前面我们已经学过<Android 自定义 view(三)-- onDraw 方法理解>,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法 推荐文章: htt ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
随机推荐
- (转)html中使用表单和input file上传图片
本文转载自:http://hi.baidu.com/love_1210/item/120e452b42b2a854c38d59eb 客户端代码: <form name="form1&q ...
- Thinkphp 查询条件 and 和 or同时使用即复合查询
thinkphp 3.2快捷查询OR查询&分割表示AND查询讲解 快捷查询方式是一种多字段查询的简化写法,可以进一步简化查询条件的写法,在多个字段之间用|分割表 ...
- 性能基准测试:KVM大战Xen
编译自:http://major.io/2014/06/22/performance-benchmarks-kvm-vs-xen/作者: Major Hayden原创:LCTT https://lin ...
- Solr -- 查询语法/参数
1. 常用查询参数 参数 描述 defType 指定用于处理查询语句(参数q的内容)的查询解析器,eg:defType=lucene sort 指定响应的排序方式:升序asc或降序desc.同时需要指 ...
- Jenkins是什么?
Jenkins 是一个可扩展的持续集成引擎. 主要用于: l 持续.自动地构建/测试软件项目. l 监控一些定时执行的任务. Jenkins拥有的特性包括: l 易于安装-只要把jenkins.war ...
- vba截屏保存
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVa ...
- Python列表练习题
1.创建一个空列表,命名为names,往里面添加 Lihua.Rain.Jack.Xiuxiu.Peiqi和Black元素. #!-*- coding:utf-8 -*- names = [" ...
- sqlserver job 执行时间
select instance_id,jh.run_date,jh.job_id,jh.step_name, case jh.run_status then 'failed' then 'Succee ...
- JSP中系统Date的几点不符合中国时间观的地方
正常调用系统时间的显示格式是Date date = new Date 显示出来的当前时间为Sun Nov 22 18:39:51 CST 2015 星期天的英文单词是Sun, 这个大家都是熟悉的, 这 ...
- eclipse-jee-mars-2-win32-x86_64安装activiti
离线安装老是不行,只能在线安装了 选择Activiti BPMN Desisner,然后一直选择下一步,直到出现如下窗体: 幸亏这个插件很小,在线安装也不算慢