Android开发之仿滑动解锁
来源:互联网 发布:excel2010数据透视图 编辑:程序博客网 时间:2024/05/18 19:42
由于项目需求,现总结一下:自定义滑动开锁,先看效果图。
看了几眼美女啦!!!接下来我们看怎么实现的吧。
准备
1、在 build.gradle 文件中添加
compile 'com.nineoldandroids:library:2.4.0'compile 'com.github.florent37:viewanimator:1.0.0@aar'
2、在清单文件中添加震动权限:
<uses-permission android:name="android.permission.VIBRATE" />
3、attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources> <!-- 滑动解锁控件 xml配置属性 --> <declare-styleable name="SlideToUnlockView"> <attr name="slideImageViewWidth" format="dimension"/><!-- 滑块宽度 --> <attr name="slideImageViewResId" format="reference"/><!-- 滑块资源id --> <attr name="slideImageViewResIdAfter" format="reference"/><!-- 滑动到右边时,滑块资源id --> <attr name="viewBackgroundResId" format="reference"/><!-- 背景资源id --> <attr name="textHint" format="string"/><!-- 文本内容 --> <attr name="textSize" format="integer"/><!-- 文本字号 --> <attr name="textColorResId" format="color"/><!-- 文本字色 --> <attr name="slideThreshold" format="float"/><!-- 滑动阈值,默认是0.5,当右滑距离不满整个控件宽度的0.5,就会回弹至左边 --> </declare-styleable></resources>
自定义 View
package com.gyq.slideunclock.view;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.widget.ImageView;import android.widget.RelativeLayout;import com.github.florent37.viewanimator.AnimationListener;import com.github.florent37.viewanimator.ViewAnimator;import com.gyq.slideunclock.R;import com.gyq.slideunclock.utils.DensityUtil;import com.nineoldandroids.view.ViewHelper;/** * Created by gyq on 2017/8/7 11:16 */public class SlidingView extends RelativeLayout { private static final String TAG="CustomSlideToUnlockView"; private static final long DEAFULT_DURATIN_LONG = 200;//左弹回,动画时长 private static final long DEAFULT_DURATIN_SHORT = 100;//右弹,动画时长 private static final boolean LOG = true;//打印开关 private static int DISTANCE_LIMIT = 600;//滑动阈值 private static float THRESHOLD = 0.5F;//滑动阈值比例:默认是0.5,即滑动超过父容器宽度的一半再松手就会触发 protected Context mContext; private ImageView iv_slide;//滑块 private RelativeLayout rl_slide;//滑动view private RelativeLayout rl_root;//父容器 private boolean mIsUnLocked;//已经滑到最右边,将不再响应touch事件 private CallBack mCallBack;//回调 private int slideImageViewWidth;//滑块宽度 private int slideImageViewResId;//滑块资源 private int slideImageViewResIdAfter;//滑动到右边时,滑块资源id private int viewBackgroundResId;//root 背景 private String textHint;//文本 private int textSize;//单位是sp,只拿数值 private int textColorResId;//颜色,@color public SlidingView(Context mContext) { super(mContext); this.mContext = mContext; initView(); } public SlidingView(Context mContext, AttributeSet attrs) { super(mContext, attrs); this.mContext = mContext; TypedArray mTypedArray = mContext.obtainStyledAttributes(attrs, R.styleable.SlideToUnlockView); init(mTypedArray); initView(); } public SlidingView(Context mContext, AttributeSet attrs, int defStyleAttr) { super(mContext, attrs, defStyleAttr); this.mContext = mContext; TypedArray mTypedArray = mContext.obtainStyledAttributes(attrs, R.styleable.SlideToUnlockView); init(mTypedArray); initView(); } private void init(TypedArray mTypedArray) { slideImageViewWidth= (int) mTypedArray.getDimension(R.styleable.SlideToUnlockView_slideImageViewWidth, DensityUtil.dp2px(getContext(), 50)); slideImageViewResId= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_slideImageViewResId, -1); slideImageViewResIdAfter= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_slideImageViewResIdAfter, -1); viewBackgroundResId= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_viewBackgroundResId, -1); textHint=mTypedArray.getString(R.styleable.SlideToUnlockView_textHint); textSize=mTypedArray.getInteger(R.styleable.SlideToUnlockView_textSize, 7); textColorResId= mTypedArray.getColor(R.styleable.SlideToUnlockView_textColorResId, getResources().getColor(android.R.color.white)); THRESHOLD=mTypedArray.getFloat(R.styleable.SlideToUnlockView_slideThreshold, 0.5f); mTypedArray.recycle(); } private int mActionDownX, mLastX, mSlidedDistance; /** * 初始化界面布局 */ protected void initView() { LayoutInflater.from(mContext).inflate(R.layout.layout_view_slide_to_unlock, this, true); rl_root = (RelativeLayout) findViewById(R.id.rl_root); rl_slide = (RelativeLayout) findViewById(R.id.rl_slide); iv_slide = (ImageView) findViewById(R.id.iv_slide); //tv_hint = (TextView) findViewById(R.id.tv_hint); LayoutParams params= (LayoutParams) iv_slide .getLayoutParams(); //获取当前控件的布局对象 params.width= slideImageViewWidth;//设置当前控件布局的高度 iv_slide.setLayoutParams(params);//将设置好的布局参数应用到控件中 setImageDefault(); if(viewBackgroundResId>0){ rl_slide.setBackgroundResource(viewBackgroundResId);//rootView设置背景 } //MarginLayoutParams tvParams = (MarginLayoutParams) tv_hint.getLayoutParams(); // tvParams.setMargins(0, 0, slideImageViewWidth, 0);//textview的marginRight设置为和滑块的宽度一致 //添加滑动监听 rl_slide.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { DISTANCE_LIMIT= (int) (SlidingView.this.getWidth()*THRESHOLD);//默认阈值是控件宽度的一半 switch (event.getAction()) { case MotionEvent.ACTION_DOWN://按下时记录纵坐标 if(mIsUnLocked){//滑块已经在最右边则不处理touch return false; } mLastX = (int) event.getRawX();//最后一个action时x值 mActionDownX = (int) event.getRawX();//按下的瞬间x break; case MotionEvent.ACTION_MOVE://上滑才处理,如果用户一开始就下滑,则过掉不处理 int dX = (int) event.getRawX() - mLastX; mSlidedDistance = (int) event.getRawX() - mActionDownX; final MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams(); int left = params.leftMargin; int top = params.topMargin; int right = params.rightMargin; int bottom = params.bottomMargin; int leftNew = left + dX; int rightNew =right - dX; if (mSlidedDistance > 0) {//直接通过margin实现滑动 params.setMargins(leftNew, top, rightNew, bottom); v.setLayoutParams(params); //回调 if(mCallBack!=null){ mCallBack.onSlide(mSlidedDistance); } mLastX = (int) event.getRawX(); } else { return true; } break; case MotionEvent.ACTION_UP: if (Math.abs(mSlidedDistance) > DISTANCE_LIMIT) { scrollToRight(v);//右边 } else { scrollToLeft(v);//左边 } break; default: break; } return true; } }); } private void logI(String tag,String content){ if(LOG){ Log.i(tag,content); } } /** * 滑动未到阈值时松开手指,弹回到最左边 **/ private void scrollToLeft(final View v) { final MarginLayoutParams params1 = (MarginLayoutParams) v.getLayoutParams(); ViewAnimator .animate( rl_slide) .translationX(ViewHelper.getTranslationX(v), -params1.leftMargin) .interpolator(new AccelerateInterpolator()) .duration(DEAFULT_DURATIN_LONG) .onStop(new AnimationListener.Stop() { @Override public void onStop() { MarginLayoutParams para = (MarginLayoutParams) v.getLayoutParams(); logI(TAG, "scrollToLeft动画结束para.leftMargin:" + para.leftMargin); logI(TAG, "scrollToLeft动画结束para.rightMargin:" + para.rightMargin); logI(TAG, "scrollToLeft动画结束,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v)); mSlidedDistance = 0; //tv_hint.setAlpha(1.0f); mIsUnLocked=false; if(mCallBack!=null){ mCallBack.onSlide(mSlidedDistance); } setImageDefault(); } }) .start(); } /** * @des:滑动到右边,并触发回调 **/ private void scrollToRight(final View v) { final MarginLayoutParams params1 = (MarginLayoutParams) v.getLayoutParams(); //移动到最右端 移动的距离是 父容器宽度-leftMargin ViewAnimator .animate( rl_slide) //.translationX(ViewHelper.getTranslationX(v), ViewHelper.getTranslationX(v)+100) .translationX(ViewHelper.getTranslationX(v), ( rl_slide.getWidth() - params1.leftMargin-slideImageViewWidth)) //.translationX(params1.leftMargin, ( rl_slide.getWidth() - params1.leftMargin-100)) .interpolator(new AccelerateInterpolator()) .duration(DEAFULT_DURATIN_SHORT) .onStop(new AnimationListener.Stop() { @Override public void onStop() { MarginLayoutParams para = (MarginLayoutParams) v.getLayoutParams(); mSlidedDistance = 0; //tv_hint.setAlpha(0.0f); mIsUnLocked=true; if(slideImageViewResIdAfter>0){ iv_slide.setImageResource(slideImageViewResIdAfter);//滑块imagview设置资源 } //回调 if(mCallBack!=null){ mCallBack.onUnlocked(); } } }) .start(); } public void resetView(){ mIsUnLocked=false; setImageDefault(); scrollToLeft(rl_slide); } private void setImageDefault() { if(slideImageViewResId>0){ iv_slide.setImageResource(slideImageViewResId);//滑块imagview设置资源 } } public interface CallBack{ void onSlide(int distance);//右滑距离回调 void onUnlocked();//滑动到了右边,事件回调 } public CallBack getmCallBack() { return mCallBack; } public void setmCallBack(CallBack mCallBack) { this.mCallBack = mCallBack; }}
MainActivity.java
package com.gyq.slideunclock;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.Vibrator;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.Window;import android.widget.ImageView;import android.widget.TextView;import com.gyq.slideunclock.view.SlidingView;import java.text.SimpleDateFormat;import java.util.Date;public class MainActivity extends AppCompatActivity { private SlidingView mSlide; private ImageView mGirl; private TextView mTime,mDate; private Vibrator vibrator; private ScreenReceiver receiver; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); refreshUI(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); // 获取系统振动器服务 vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); mSlide = (SlidingView)findViewById(R.id.slide_to_unlock); mGirl = (ImageView)findViewById(R.id.iv_girl); mTime = (TextView) findViewById(R.id.tv_time); mDate = (TextView) findViewById(R.id.tv_date); SlidingView.CallBack callBack = new SlidingView.CallBack() { @Override public void onSlide(int distance) { //mText.setText("slide distance:"+distance); } @Override public void onUnlocked() { // 启动震动器 100ms vibrator.vibrate(100); mGirl.setVisibility(View.VISIBLE); mSlide.resetView(); mSlide.setVisibility(View.GONE); mTime.setVisibility(View.GONE); mDate.setVisibility(View.GONE); } }; mSlide.setmCallBack(callBack); } @Override protected void onStart() { super.onStart(); initData(); // 注册屏幕锁屏的广播 registScreenOffReceiver(); } private void initData() { SimpleDateFormat format = new SimpleDateFormat("E yyyy/MM/dd"); String str = format.format(new Date(System.currentTimeMillis())); if (str.contains("周")) str = "星期" + str.substring(1); mDate.setText(str); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(1000); mHandler.sendMessage(mHandler.obtainMessage()); } catch (Exception e) { e.printStackTrace(); } } } }).start(); } /** * 通过handler及时更新时间显示效果 */ public void refreshUI() { SimpleDateFormat formatter = new SimpleDateFormat("HH:mm"); Date date = new Date(System.currentTimeMillis()); String curTime = formatter.format(date); mTime.setText(curTime); //当前时间格式 } /** * 注册一个屏幕锁屏的广播 */ private void registScreenOffReceiver() { // TODO Auto-generated method stub receiver = new ScreenReceiver(); // 创建一个意图过滤器 IntentFilter filter = new IntentFilter(); // 添加屏幕锁屏的广播 filter.addAction("android.intent.action.SCREEN_OFF"); // 在代码里边来注册广播 this.registerReceiver(receiver, filter); } class ScreenReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 关屏的操作 if ("android.intent.action.SCREEN_OFF".equals(action)) { // 当手机关屏时,我们同时也锁屏 mSlide.setVisibility(View.VISIBLE); mTime.setVisibility(View.VISIBLE); mDate.setVisibility(View.VISIBLE); // 设置图片消失 mGirl.setVisibility(View.GONE); } } } @Override protected void onDestroy() { super.onDestroy(); // 注销注册的广播 unregisterReceiver(receiver); receiver = null; }}
工具类:DensityUtil.java
package com.gyq.slideunclock.utils;import android.content.Context;import android.util.DisplayMetrics;import android.util.TypedValue;import android.view.WindowManager;/** * Created by gyq on 2017/8/7 11:05 */public class DensityUtil { @Deprecated public static int dip2px(Context paramContext, float paramFloat) { return (int) (0.5F + paramFloat * paramContext.getResources().getDisplayMetrics().density); } @Deprecated public static int px2dip(Context context, float paramFloat) { return (int) (0.5F + paramFloat / context.getResources().getDisplayMetrics().density); } @Deprecated public static int sp2px(Context context, float spValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); } @Deprecated public static int px2sp(Context context, float value) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (value / fontScale + 0.5f); } public static int dip2px(float density, float value) { return (int) (0.5F + value * density); } public static int px2dip(float density, float value) { return (int) (0.5F + value / density); } public static int sp2px(float scaledDensity, float value) { return (int) (0.5F + value * scaledDensity); } public static int px2sp(float fontScale /** scaledDensity */ , float value) { return (int) (value / fontScale + 0.5f); } public static final int getStatusHeighByDensity(Context context) { int h = 38; int density = context.getResources().getDisplayMetrics().densityDpi; switch (density) { case 120: h = 19; break; case 160: h = 25; break; case 240: h = 38; break; case 320: h = 50; break; case 400: h = 63; break; case 480: h = 75; break; default: break; } return h; } private static int displayWidth, displayHeight; private static void initDisplay(Context context) { DisplayMetrics dm = new DisplayMetrics(); ((WindowManager) context.getApplicationContext().getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm); displayWidth = dm.widthPixels; displayHeight = dm.heightPixels; } public static final int getDisplayWidth(Context context) { if (displayWidth == 0) { initDisplay(context); } return displayWidth; } public static final int getDisplayHeight(Context context) { if (displayHeight == 0) { initDisplay(context); } return displayHeight; } public static int dp2px(Context context, int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,context.getResources().getDisplayMetrics()); } public static int dp2px(Context context, float dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,context.getResources().getDisplayMetrics()); } public static int px2dp(Context context, int px) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,context.getResources().getDisplayMetrics()); } public static int px2sp(Context context, int px) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, px,context.getResources().getDisplayMetrics()); } public static int getScreenWidth(Context context) { WindowManager wm = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE ); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics( outMetrics); return outMetrics .widthPixels ; }}
记录下来方便今后开发使用。
阅读全文
0 0
- Android开发之仿滑动解锁
- android仿iphone滑动解锁
- android仿三星I900滑动解锁
- android 仿三星I900滑动解锁
- android 仿三星I900滑动解锁
- android仿ipone滑动解锁控件
- Android开发之滑动选择菜单(仿QQ滑动删除)
- Android自定义控件之滑动解锁
- Android自定义控件之滑动解锁
- android滑动解锁
- Android滑动解锁控件
- Android 滑动解锁
- Android开发仿QQ聊天滑动listview
- android开发仿IOS滑动开关
- Android之高仿手机QQ图案解锁
- Android之高仿手机QQ图案解锁
- Android之高仿手机QQ图案解锁
- Android之高仿手机QQ图案解锁
- 倒排索引
- Mybatis学习心得
- 欢迎使用CSDN-markdown编辑器
- POJ 3974Palindrome
- maven之pom.xml详解
- Android开发之仿滑动解锁
- Hive:hive在查询语句时Error during job, obtaining debugging information.
- 笔记:ScrollView中布局高度无法match_parent
- 安装mysql时,visual distributable package 2013报错
- 深入理解String和StringBuilder
- 微信小程序开发(一)--数据存储
- LintCode 212 空格替换
- xgboost中自定义损失函数的使用方法
- 提升域功能级别