Android自定义控件之滑动解锁
2016-05-21 20:53
465 查看
我的视频系列 http://edu.csdn.net/course/detail/2741,一起来学习Android…
代码参考地址 https://github.com/liuzhiyuan0932/SlideUnLock
代码效果图>
在xml布局中使用相关的属性
设置图片的方法,设置好图片之后,进行界面的初始 绘制
onTouch事件处理的主要逻辑
对外听设置监听的方法
在OnTouch中解锁的时候,进行设置
定义广播接收器
以上是Android自定义控件–滑动解锁的所有代码逻辑
代码参考地址 https://github.com/liuzhiyuan0932/SlideUnLock
代码效果图>
自定义滑动解锁的控件继承自View
public class SlideUnlockView extends View
自定义SlideUnLockView的属性
在values文件夹中定义属性<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SlideUnlockButton"> <!-- 背景图片的属性, 引用的是R.drawable.xx. --> <attr name="slideUnlockBackgroundResource" format="reference" /> <!-- 滑动块图片的属性, 引用的是R.drawable.xx. --> <attr name="slideUnlockBlockResource" format="reference" /> </declare-styleable> </resources>
在xml布局中使用相关的属性
<com.zhiyuan.slideunlockdemo.view.SlideUnlockView android:id="@+id/slideUnlockView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" test:slideUnlockBackgroundResource="@drawable/jiesuo_bg" test:slideUnlockBlockResource="@drawable/jiesuo_button" />
定义滑块的几种状态
/** * 滑块当前的状态 */ public int currentState; /** * 未解锁 */ public static final int STATE_LOCK = 1; /** * 解锁 */ public static final int STATE_UNLOCK = 2; /** * 正在拖拽 */ public static final int STATE_MOVING = 3;
获取图片资源,并进行初始绘制
在构造方法中获取属性值public SlideUnlockView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // 默认滑动解锁为未解锁状态 currentState = STATE_LOCK; // 命名空间 String namespace = "http://schemas.android.com/apk/res/com.zhiyuan.slideunlockdemo"; // 取出自定义属性中背景图片 int slideUnlockBackgroundResource = attrs.getAttributeResourceValue( namespace, "slideUnlockBackgroundResource", -1); // 取出自定义属性中滑块图片 int slideUnlockBlockResource = attrs.getAttributeResourceValue( namespace, "slideUnlockBlockResource", -1); // 取出自定义属性中当前状态 // 如果解锁状态是true,说明已经解锁 /** * 当取出自定义属性的背景时,设置背景 */ setSlideUnlockBackground(slideUnlockBackgroundResource); /** * 当取出自定义属性的滑块时,设置滑块的图片 */ setSlideUnlockBlock(slideUnlockBlockResource); /** * 执行onDraw方法,进行界面绘制 */ postInvalidate(); }
设置图片的方法,设置好图片之后,进行界面的初始 绘制
/** * 设置背景图 * @param slideUnlockBackgroundResource */ public void setSlideUnlockBackground(int slideUnlockBackgroundResource) { slideUnlockBackground = BitmapFactory.decodeResource(getResources(), slideUnlockBackgroundResource); // 获取背景图的宽和高 blockBackgoundWidth = slideUnlockBackground.getWidth(); } /** * 设置滑块图 * @param slideUnlockBlockResource */ public void setSlideUnlockBlock(int slideUnlockBlockResource) { slideUnlockBlock = BitmapFactory.decodeResource(getResources(), slideUnlockBlockResource); // 获取滑块的宽和高 blockWidth = slideUnlockBlock.getWidth(); blockHeight = slideUnlockBlock.getHeight(); }
通过测量背景图的宽高设置SlideUnLockView的宽高
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //设置控件的宽高为滑块背景图的宽高 setMeasuredDimension(slideUnlockBackground.getWidth(), slideUnlockBackground.getHeight()); }
处理onTouch事件
判断手指是否按在滑块上/** * 计算手指是否是落在了滑块上(默认是按照滑块在未解锁的初始位置来计算的) */ public boolean isDownOnBlock(float x1, float x2, float y1, float y2) { float sqrt = FloatMath.sqrt(Math.abs(x1 - x2) * Math.abs(x1 - x2) + Math.abs(y1 - y2) * Math.abs(y1 - y2)); if (sqrt <= blockWidth / 2) { return true; } return false; }
onTouch事件处理的主要逻辑
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { // 当手指按下的时候,判断手指按下的位置是否在滑块上边 case MotionEvent.ACTION_DOWN: if (currentState != STATE_MOVING) { // 判断一下,如果当前正在移动,则不执行触摸操作 // 获取相对于背景的左上角的x,y值 x = event.getX(); y = event.getY(); // 先计算出滑块的中心点的x,y坐标 float blockCenterX = blockWidth * 1.0f / 2; float blockCenterY = blockHeight * 1.0f / 2; downOnBlock = isDownOnBlock(blockCenterX, x, blockCenterY, y); Log.i(TAG, "down......................"); // 调用onDraw方法 postInvalidate(); } break; case MotionEvent.ACTION_MOVE: // 如果手指确定按在滑块上,就视为开始拖拽滑块 if (downOnBlock) { // 获取相对于背景的左上角的x,y值 x = event.getX(); y = event.getY(); currentState = STATE_MOVING; Log.i(TAG, "move......................"); // 调用onDraw方法 postInvalidate(); } break; case MotionEvent.ACTION_UP: if (currentState == STATE_MOVING) { // 当手指抬起的时候,应该是让滑块归位的 // 说明未解锁 if (x < blockBackgoundWidth - blockWidth) { handler.sendEmptyMessageDelayed(0, 10); // 通过回调设置已解锁 onUnLockListener.setUnLocked(false); } else { currentState = STATE_UNLOCK; // 通过回调设置未解锁 onUnLockListener.setUnLocked(true); } downOnBlock = false; // 调用onDraw方法 postInvalidate(); } break; default: break; } return true; }
调用OnDraw方法并根据状态进行绘制
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 在一开始的使用将背景图绘制出来 canvas.drawBitmap(slideUnlockBackground, 0, 0, null); /** * 判断当前状态 */ switch (currentState) { // 如果是未解锁,就将滑块绘制到最左端 case STATE_LOCK: canvas.drawBitmap(slideUnlockBlock, 0, 0, null); break; // 已解锁,计算出 case STATE_UNLOCK: int unlockX = blockBackgoundWidth - blockWidth; canvas.drawBitmap(slideUnlockBlock, unlockX, 0, null); break; case STATE_MOVING: if (x < 0) { x = 0; } else if (x > blockBackgoundWidth - blockWidth) { x = blockBackgoundWidth - blockWidth; } canvas.drawBitmap(slideUnlockBlock, x, 0, null); break; default: break; } }
设置手指抬起未解锁时滑块缓慢回到初始位置
/** * 通过handler来控制滑块在未解锁的时候,平缓的滑动到左端 */ Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 0) { // 如果x还大于0,就人为的设置缓慢移动到最左端,每次移动距离设置为背景宽的/100 if (x > 0) { x = x - blockBackgoundWidth * 1.0f / 100; // 刷新界面 postInvalidate(); // 设置继续移动 handler.sendEmptyMessageDelayed(0, 10); } else { handler.removeCallbacksAndMessages(null); currentState = STATE_LOCK; Log.i(TAG, "state---lock....."); } } }; };
case MotionEvent.ACTION_UP: if (currentState == STATE_MOVING) { // 当手指抬起的时候,应该是让滑块归位的 // 说明未解锁 if (x < blockBackgoundWidth - blockWidth) { handler.sendEmptyMessageDelayed(0, 10); // 通过回调设置已解锁 onUnLockListener.setUnLocked(false); } else { currentState = STATE_UNLOCK; // 通过回调设置未解锁 onUnLockListener.setUnLocked(true); } downOnBlock = false; // 调用onDraw方法 postInvalidate(); } break;
设置滑动解锁的监听
定义一个解锁监听的接口public interface OnUnLockListener { public void setUnLocked(boolean lock); }
对外听设置监听的方法
public void setOnUnLockListener(OnUnLockListener onUnLockListener) { this.onUnLockListener = onUnLockListener; }
在OnTouch中解锁的时候,进行设置
if (currentState == STATE_MOVING) { // 当手指抬起的时候,应该是让滑块归位的 // 说明未解锁 if (x < blockBackgoundWidth - blockWidth) { handler.sendEmptyMessageDelayed(0, 10); // 通过回调设置已解锁 onUnLockListener.setUnLocked(false); } else { currentState = STATE_UNLOCK; // 通过回调设置未解锁 onUnLockListener.setUnLocked(true); } downOnBlock = false; // 调用onDraw方法 postInvalidate(); }
定义滑动解锁时手机震动的震动器
// 获取系统振动器服务 vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); // 启动震动器 100ms vibrator.vibrate(100);
在类中使用SlideUnLockView
slideUnlockView = (SlideUnlockView) findViewById(R.id.slideUnlockView); // 设置滑动解锁-解锁的监听 slideUnlockView.setOnUnLockListener(new OnUnLockListener() { @Override public void setUnLocked(boolean unLock) { // 如果是true,证明解锁 if (unLock) { // 启动震动器 100ms vibrator.vibrate(100); // 当解锁的时候,执行逻辑操作,在这里仅仅是将图片进行展示 imageView.setVisibility(View.VISIBLE); // 重置一下滑动解锁的控件 slideUnlockView.reset(); // 让滑动解锁控件消失 slideUnlockView.setVisibility(View.GONE); } } }); }
用户屏幕锁屏的监听
注册Android锁屏广播/** * 注册一个屏幕锁屏的广播 */ private void registScreenOffReceiver() { // TODO Auto-generated method stub receiver = new ScreenOnOffReceiver(); // 创建一个意图过滤器 IntentFilter filter = new IntentFilter(); // 添加屏幕锁屏的广播 filter.addAction("android.intent.action.SCREEN_OFF"); // 在代码里边来注册广播 this.registerReceiver(receiver, filter); }
定义广播接收器
class ScreenOnOffReceiver extends BroadcastReceiver { private static final String TAG = "ScreenOnOffReceiver"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 关屏的操作 if ("android.intent.action.SCREEN_OFF".equals(action)) { // 当手机关屏时,我们同时也锁屏 slideUnlockView.setVisibility(View.VISIBLE); // 设置图片消失 imageView.setVisibility(View.GONE); } } }
以上是Android自定义控件–滑动解锁的所有代码逻辑
相关文章推荐
- flex 控件的重要属性
- 麻雀虽小五脏俱全 Dojo自定义控件应用
- Delphi控件ListView的属性及使用方法详解
- web下载的ActiveX控件自动更新
- WinForm自定义控件应用实例
- WinForm实现按名称递归查找控件的方法
- C#中父窗口和子窗口之间控件互操作实例
- Android编程之Button控件用法实例分析
- Android控件之CheckBox、RadioButton用法实例分析
- 在Android开发中使用自定义组合控件的例子
- Android组合控件实现功能强大的自定义控件
- Android重写View实现全新的控件
- C++ 自定义控件的移植问题
- MFC中动态创建控件以及事件响应实现方法
- WinForm自定义函数FindControl实现按名称查找控件
- Android控件之ProgressBar用法实例分析
- WinForm拖拽控件生成副本的解决方法
- C#实现用户自定义控件中嵌入自己的图标
- ASP.NET动态添加用户控件的方法
- ASP.NET的HtmlForm控件学习及Post与Get的区别概述