1,实现效果
【1】scrollTo & scrrllBy的特点
实际上上面2个api滚动是的view绘制的内容,view本身并没有动
scrollTo当x传入正数往做移动.传入负数往右移动. (偏移量x = 0-i)
scrollBy 在上一次移动的基础上在移动X
2,实现逻辑
【1】创建一个类,继承view ,重写onMeasure 和 onDraw
public class LockView extends View {
public LockView(Context context, AttributeSet attrs) {
super(context, attrs);
}
//在这个方法里面测量当前view的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
}
//往当前的view上画内容
@Override
protected void onDraw(Canvas canvas) {
//[1]由于背景我已经在布局中加上 所以只需要往当前的view上画 滑块就可以了
}
【2】MainActivity 的布局中声明使用自定义view
android:background="@drawable/lockviewbg" 设置了背景
【3】布局的绘制
LockView构造方法,BitmapFactory获取图片资源图片
//[1]获取背景图片和 滑动块的图
lockViewBg = BitmapFactory.decodeResource(getResources(), R.drawable.lockviewbg);
slideBg = BitmapFactory.decodeResource(getResources(), R.drawable.switch_button);
在onMeasure进行测量背景图片的大小
//在这个方法里面测量当前view的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(lockViewBg.getWidth(), lockViewBg.getHeight());
}
在onDraw绘制滑块内容
//往当前的view上画内容
@Override
protected void onDraw(Canvas canvas) {
//[1]由于背景我已经在布局中加上 所以只需要往当前的view上画 滑块就可以了
canvas.drawBitmap(slideBg, 0, 0, null);
}
【4】滑动事件处理
重写onTouchEvent 方法
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return true; //消费事件
}
重写scrollTo方法让它符合中国人的思维
/**滚动view的内容 自己重写这个方法让它符合中国人的思维**/
public void startScrollView(int x){
super.scrollTo(-x, 0);
}
ACTION_DOWN中获取按下的坐标,ACTION_MOVE中获取移动的完成坐标,moveX - downX获取偏移量
调用startScrollView进行滑动
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
distaceX = (int) (moveX - downX);
//[1]让view 的内容进行移动
startScrollView(distaceX);
break;
构造方法中获取滑块可以移动的最大左边距
//[2]算出滑动块像右移动最大值
slideLeftMaxSize = lockViewBg.getWidth()-slideBg.getWidth();
ACTION_MOVE中判断边界
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
distaceX = (int) (moveX - downX);
//[0]判断边界
if (distaceX <=0 ) {
distaceX = 0;
}else if (distaceX > slideLeftMaxSize ) {
distaceX = slideLeftMaxSize;
}
//[1]让view 的内容进行移动
startScrollView(distaceX);
break;
ACTION_UP 中判断如果抬起时不是移动的最大边距
case MotionEvent.ACTION_UP:
//[2]当手指抬起 如果
if (distaceX < slideLeftMaxSize) {
//[3]让view的内容回到0
startScrollView(0);
}else {
如果最大值,实现对应逻辑
}
break;
【5】接口回调
在LockView创建监听方法 ,传入变量是一个接口的子类
定义成员变量
private OnLockViewListener mLockViewListener;
public void setOnLockViewListener(OnLockViewListener l){
this.mLockViewListener = l;
}
定义接口的子类,实现开锁
/**
* 定义监听器对象
* @author jinxing
*
*/
public interface OnLockViewListener{
//当滑动解锁的时候调用
void onLock();
}
滑动到位置为最大值解锁
case MotionEvent.ACTION_UP:
//[2]当手指抬起 如果
if (distaceX < slideLeftMaxSize) {
//[3]让view的内容回到0
startScrollView(0);
}else {
//[4]解锁
if (mLockViewListener!=null) {
mLockViewListener.onLock();
}
}
break;
MainActivity调用listener 监听
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LockView lockView = (LockView) findViewById(R.id.lockView1);
lockView.setOnLockViewListener(new OnLockViewListener() {
@Override
public void onLock() {
finish();
}
});
}
}
【6】平滑滚动的效果
创建scroller 可以获取产生移动的数据效果 。
构造方法中创建Scroller对象
//[3]创建一个类 scroller 可以收集数据 并且产生一个滚动动画的效果
mScroller = new Scroller(getContext());
ACTION_UP的时候实现平滑滚动效果
mScroller.startScroll(startX, 0, dx, 0, duration);只能产生数据
case MotionEvent.ACTION_UP:
//[2]当手指抬起 如果
if (distaceX < slideLeftMaxSize) {
//实现平滑滚动
int startX = distaceX;
int endX = 0;
int dx = endX - startX;
int duration = Math.abs(dx)*20;
//下面这句api不可以让view滚动
mScroller.startScroll(startX, 0, dx, 0, duration);
invalidate(); //--->最终会调用到computeScroll这个方法
}else {
//[4]解锁
if (mLockViewListener!=null) {
mLockViewListener.onLock();
}
}
break;
invalidate会调用onDrwa 也会调用computeScroll方法
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) { //为false的时候停止回调
//获取我们在上面模拟的数据
int currX = mScroller.getCurrX();
System.out.println("currX:"+currX);
startScrollView(currX);
invalidate();
}
}
3,全部代码
package com.xiaoshuai.www.lockview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
public class LockView extends View {
private OnLockViewListener mLockViewListener;
/**代表背景**/
private Bitmap lockViewBg;
/**代表滑块**/
private Bitmap slideBg;
/**按下的坐标**/
private float downX;
private int slideLeftMaxSize;
private int distaceX;
private Scroller mScroller;
public LockView(Context context, AttributeSet attrs) {
super(context, attrs);
//[1]获取背景图片和 滑动块的图
lockViewBg = BitmapFactory.decodeResource(getResources(), R.drawable.lockviewbg);
slideBg = BitmapFactory.decodeResource(getResources(), R.drawable.switch_button);
//[2]算出滑动块像右移动最大值
slideLeftMaxSize = lockViewBg.getWidth()-slideBg.getWidth();
//[3]创建一个类 scroller 可以收集数据 并且产生一个滚动动画的效果
mScroller = new Scroller(getContext());
}
//在这个方法里面测量当前view的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(lockViewBg.getWidth(), lockViewBg.getHeight());
}
//往当前的view上画内容
@Override
protected void onDraw(Canvas canvas) {
//[1]由于背景我已经在布局中加上 所以只需要往当前的view上画 滑块就可以了
canvas.drawBitmap(slideBg, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
distaceX = (int) (moveX - downX);
//[0]判断边界
if (distaceX <=0 ) {
distaceX = 0;
}else if (distaceX > slideLeftMaxSize ) {
distaceX = slideLeftMaxSize;
}
//[1]让view 的内容进行移动
startScrollView(distaceX);
break;
case MotionEvent.ACTION_UP:
//[2]当手指抬起 如果
if (distaceX < slideLeftMaxSize) {
//[3]让view的内容回到0
// startScrollView(0);
//实现平滑滚动
int startX = distaceX;
int endX = 0;
int dx = endX - startX;
int duration = Math.abs(dx)*20;
//下面这句api不可以让view滚动
mScroller.startScroll(startX, 0, dx, 0, duration);
invalidate(); //--->最终会调用到computeScroll这个方法
}else {
//[4]解锁
if (mLockViewListener!=null) {
mLockViewListener.onLock();
}
}
break;
}
return true; //消费事件
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
//获取我们在上面模拟的数据
int currX = mScroller.getCurrX();
System.out.println("currX:"+currX);
startScrollView(currX);
invalidate();
}
}
/**滚动view的内容 自己重写这个方法让它符合中国人的思维**/
public void startScrollView(int x){
super.scrollTo(-x, 0);
}
public void setOnLockViewListener(OnLockViewListener l){
this.mLockViewListener = l;
}
/**
* 定义监听器对象
* @author jinxing
*
*/
public interface OnLockViewListener{
//当滑动解锁的时候调用
void onLock();
}
}