├── README.md ├── SlideToUnlockView ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── slidetounlockview.iml └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── qdong │ │ └── slide_to_unlock_view │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── qdong │ │ │ └── slide_to_unlock_view │ │ │ ├── CustomSlideToUnlockView.java │ │ │ └── DensityUtil.java │ └── res │ │ ├── drawable │ │ └── shape_round_normal_green.xml │ │ ├── layout │ │ └── layout_view_slide_to_unlock.xml │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── icon_slide.png │ │ └── values │ │ ├── attrs.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── qdong │ └── slide_to_unlock_view │ └── ExampleUnitTest.java ├── app-debug.apk ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── qdong │ │ └── slidetounlockdemo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── qdong │ │ │ └── slidetounlockdemo │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable │ │ └── shape_round_normal_green.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── icon_slide.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── qdong │ └── slidetounlockdemo │ └── ExampleUnitTest.java ├── build.gradle ├── demo.gif └── gradle └── wrapper ├── gradle-wrapper.jar └── gradle-wrapper.properties /README.md: -------------------------------------------------------------------------------- 1 | # AndroidCustomSlideToUnlockView 2 | ## 安卓自定义滑动解锁控件 3 | 4 | ### 添加依赖:
5 | dependencies {
6 | // your dependencies ...
7 | compile 'com.linklink.views:slide_to_unlock_view:1.0.0'
8 | }
9 | 10 | ### 效果图:
11 | 12 | ![img](https://github.com/506954774/AndroidCustomSlideToUnlockView/blob/master/demo.gif?raw=true) 13 | 14 | ## 可以自定义的属性:
15 | >>name="slideImageViewWidth" format="dimension" //滑块宽度
16 | >>name="slideImageViewResId" format="reference"//滑块资源id
17 | >>name="slideImageViewResIdAfter" format="reference"//滑动到右边时,滑块资源id
18 | >>name="viewBackgroundResId" format="reference"//背景资源id
19 | >>name="textHint" format="string"//文本内容
20 | >>name="textSize" format="integer"/>//文本字号
21 | >>name="textColorResId" format="color"//文本字色
22 | >>name="slideThreshold" format="float"//滑动阈值,默认是0.5,当右滑距离不满整个控件宽度的0.5,就会回弹至左边

23 | 24 | ## xml :
25 | 26 | android:id="@+id/slide_to_unlock"
27 | android:layout_width="match_parent"
28 | android:layout_height="50dp"
29 | chuck:viewBackgroundResId="@drawable/shape_round_normal_green"
30 | chuck:slideImageViewWidth="@dimen/slide_width"
31 | chuck:slideImageViewResId="@mipmap/icon_slide"
32 | chuck:slideImageViewResIdAfter="@mipmap/ic_launcher"
33 | chuck:slideThreshold="0.5"
34 | chuck:textSize="6"
35 | chuck:textHint="@string/hint"
36 | chuck:textColorResId="@color/colorWhite"
37 |
38 | 39 | ## MainActivity.java :
40 | ```Java 41 | package com.qdong.slidetounlockdemo; 42 | import android.os.Bundle; 43 | import android.support.v7.app.AppCompatActivity; 44 | import android.view.View; 45 | import android.widget.TextView; 46 | import com.qdong.slide_to_unlock_view.CustomSlideToUnlockView; 47 | 48 | 49 | public class MainActivity extends AppCompatActivity { 50 | 51 | private CustomSlideToUnlockView mCustomSlideToUnlockView; 52 | private TextView tv_text; 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_main); 58 | mCustomSlideToUnlockView= (com.qdong.slide_to_unlock_view.CustomSlideToUnlockView) findViewById(R.id.slide_to_unlock); 59 | tv_text= (TextView) findViewById(R.id.tv_text); 60 | 61 | CustomSlideToUnlockView.CallBack callBack=new CustomSlideToUnlockView.CallBack() { 62 | @Override 63 | public void onSlide(int distance) { 64 | tv_text.setText("slide distance:"+distance); 65 | } 66 | 67 | @Override 68 | public void onUnlocked() { 69 | tv_text.setText("onUnlocked"); 70 | } 71 | }; 72 | mCustomSlideToUnlockView.setmCallBack(callBack); 73 | findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { 74 | @Override 75 | public void onClick(View view) { 76 | mCustomSlideToUnlockView.resetView(); 77 | } 78 | }); 79 | } 80 | } 81 | ``` -------------------------------------------------------------------------------- /SlideToUnlockView/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /SlideToUnlockView/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'maven' 4 | apply plugin: 'com.novoda.bintray-release' 5 | 6 | android { 7 | compileSdkVersion 25 8 | buildToolsVersion "25.0.1" 9 | 10 | defaultConfig { 11 | minSdkVersion 19 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | testCompile 'junit:junit:4.12' 27 | compile 'com.android.support:appcompat-v7:25.1.0' 28 | compile 'com.nineoldandroids:library:2.4.0' 29 | compile 'com.github.florent37:viewanimator:1.0.0@aar' 30 | } 31 | 32 | 33 | 34 | publish { 35 | userOrg = 'linklink' 36 | groupId = 'com.linklink.views' 37 | artifactId = 'slide_to_unlock_view' 38 | version = '1.0.0' 39 | description = 'Slide To Unlock View' 40 | website = 'https://github.com/506954774/AndroidCustomSlideToUnlockView' 41 | } 42 | 43 | 44 | 45 | tasks.withType(JavaCompile) { 46 | options.encoding = "UTF-8" 47 | } 48 | 49 | tasks.withType(Javadoc) { 50 | options.addStringOption('Xdoclint:none', '-quiet') 51 | options.addStringOption('encoding', 'UTF-8') 52 | } -------------------------------------------------------------------------------- /SlideToUnlockView/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\IDE\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /SlideToUnlockView/slidetounlockview.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/androidTest/java/com/qdong/slide_to_unlock_view/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.qdong.slide_to_unlock_view; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/java/com/qdong/slide_to_unlock_view/CustomSlideToUnlockView.java: -------------------------------------------------------------------------------- 1 | package com.qdong.slide_to_unlock_view; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.text.TextUtils; 6 | import android.util.AttributeSet; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.animation.AccelerateInterpolator; 12 | import android.widget.ImageView; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.github.florent37.viewanimator.AnimationListener; 17 | import com.github.florent37.viewanimator.ViewAnimator; 18 | import com.nineoldandroids.view.ViewHelper; 19 | 20 | 21 | /** 22 | * CustomSlideToUnlockView 23 | * 责任人: Chuck 24 | * 修改人: Chuck 25 | * 创建/修改时间: 2017/5/23 16:53 26 | * Copyright : 2014-2016 深圳趣动智能科技有限公司-版权所有 27 | **/ 28 | public class CustomSlideToUnlockView extends RelativeLayout { 29 | 30 | private static final String TAG="CustomSlideToUnlockView"; 31 | private static final long DEAFULT_DURATIN_LONG = 200;//左弹回,动画时长 32 | private static final long DEAFULT_DURATIN_SHORT = 100;//右弹,动画时长 33 | private static final boolean LOG = true;//打印开关 34 | private static int DISTANCE_LIMIT = 600;//滑动阈值 35 | private static float THRESHOLD = 0.5F;//滑动阈值比例:默认是0.5,即滑动超过父容器宽度的一半再松手就会触发 36 | protected Context mContext; 37 | private ImageView iv_slide;//滑块 38 | private TextView tv_hint;//提示文本 39 | private RelativeLayout rl_slide;//滑动view 40 | private RelativeLayout rl_root;//父容器 41 | private boolean mIsUnLocked;//已经滑到最右边,将不再响应touch事件 42 | private CallBack mCallBack;//回调 43 | 44 | 45 | private int slideImageViewWidth;//滑块宽度 46 | private int slideImageViewResId;//滑块资源 47 | private int slideImageViewResIdAfter;//滑动到右边时,滑块资源id 48 | private int viewBackgroundResId;//root 背景 49 | private String textHint;//文本 50 | private int textSize;//单位是sp,只拿数值 51 | private int textColorResId;//颜色,@color 52 | 53 | 54 | public CustomSlideToUnlockView(Context mContext) { 55 | super(mContext); 56 | this.mContext = mContext; 57 | initView(); 58 | } 59 | 60 | public CustomSlideToUnlockView(Context mContext, AttributeSet attrs) { 61 | super(mContext, attrs); 62 | this.mContext = mContext; 63 | TypedArray mTypedArray = mContext.obtainStyledAttributes(attrs, 64 | R.styleable.SlideToUnlockView); 65 | init(mTypedArray); 66 | initView(); 67 | } 68 | 69 | public CustomSlideToUnlockView(Context mContext, AttributeSet attrs, int defStyleAttr) { 70 | super(mContext, attrs, defStyleAttr); 71 | this.mContext = mContext; 72 | 73 | TypedArray mTypedArray = mContext.obtainStyledAttributes(attrs, 74 | R.styleable.SlideToUnlockView); 75 | init(mTypedArray); 76 | 77 | initView(); 78 | 79 | } 80 | 81 | /** 82 | * @method name:init 83 | * @des:获取自定义属性 84 | * @param :[mTypedArray] 85 | * @return type:void 86 | * @date 创建时间:2017/5/24 87 | * @author Chuck 88 | **/ 89 | private void init(TypedArray mTypedArray) { 90 | 91 | slideImageViewWidth= (int) mTypedArray.getDimension(R.styleable.SlideToUnlockView_slideImageViewWidth, DensityUtil.dp2px(getContext(), 50)); 92 | slideImageViewResId= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_slideImageViewResId, -1); 93 | slideImageViewResIdAfter= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_slideImageViewResIdAfter, -1); 94 | viewBackgroundResId= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_viewBackgroundResId, -1); 95 | textHint=mTypedArray.getString(R.styleable.SlideToUnlockView_textHint); 96 | textSize=mTypedArray.getInteger(R.styleable.SlideToUnlockView_textSize, 7); 97 | textColorResId= mTypedArray.getColor(R.styleable.SlideToUnlockView_textColorResId, getResources().getColor(android.R.color.white)); 98 | THRESHOLD=mTypedArray.getFloat(R.styleable.SlideToUnlockView_slideThreshold, 0.5f); 99 | 100 | mTypedArray.recycle(); 101 | } 102 | 103 | 104 | private int mActionDownX, mLastX, mSlidedDistance; 105 | 106 | 107 | /** 108 | * 初始化界面布局 109 | */ 110 | protected void initView() { 111 | 112 | LayoutInflater.from(mContext).inflate(R.layout.layout_view_slide_to_unlock, 113 | this, true); 114 | 115 | rl_root = (RelativeLayout) findViewById(R.id.rl_root); 116 | rl_slide = (RelativeLayout) findViewById(R.id.rl_slide); 117 | iv_slide = (ImageView) findViewById(R.id.iv_slide); 118 | tv_hint = (TextView) findViewById(R.id.tv_hint); 119 | 120 | LayoutParams params= (LayoutParams) iv_slide .getLayoutParams(); 121 | //获取当前控件的布局对象 122 | params.width= slideImageViewWidth;//设置当前控件布局的高度 123 | iv_slide.setLayoutParams(params);//将设置好的布局参数应用到控件中 124 | 125 | setImageDefault(); 126 | if(viewBackgroundResId>0){ 127 | rl_slide.setBackgroundResource(viewBackgroundResId);//rootView设置背景 128 | } 129 | 130 | MarginLayoutParams tvParams = (MarginLayoutParams) tv_hint.getLayoutParams(); 131 | tvParams.setMargins(0, 0, slideImageViewWidth, 0);//textview的marginRight设置为和滑块的宽度一致 132 | tv_hint.setLayoutParams(tvParams); 133 | tv_hint.setTextSize(DensityUtil.sp2px(getContext(), textSize)); 134 | tv_hint.setTextColor(textColorResId); 135 | tv_hint.setText(TextUtils.isEmpty(textHint)? mContext.getString(R.string.hint):textHint); 136 | 137 | //添加滑动监听 138 | rl_slide.setOnTouchListener(new OnTouchListener() { 139 | @Override 140 | public boolean onTouch(View v, MotionEvent event) { 141 | 142 | DISTANCE_LIMIT= (int) (CustomSlideToUnlockView.this.getWidth()*THRESHOLD);//默认阈值是控件宽度的一半 143 | 144 | switch (event.getAction()) { 145 | 146 | case MotionEvent.ACTION_DOWN://按下时记录纵坐标 147 | 148 | if(mIsUnLocked){//滑块已经在最右边则不处理touch 149 | return false; 150 | } 151 | 152 | mLastX = (int) event.getRawX();//最后一个action时x值 153 | mActionDownX = (int) event.getRawX();//按下的瞬间x 154 | logI(TAG, mLastX + "X,=============================ACTION_DOWN"); 155 | break; 156 | 157 | case MotionEvent.ACTION_MOVE://上滑才处理,如果用户一开始就下滑,则过掉不处理 158 | 159 | logI(TAG, "=============================ACTION_MOVE"); 160 | logI(TAG, "event.getRawX()============================="+event.getRawX()); 161 | 162 | int dX = (int) event.getRawX() - mLastX; 163 | logI(TAG, "dX============================="+dX); 164 | 165 | mSlidedDistance = (int) event.getRawX() - mActionDownX; 166 | logI(TAG, "mSlidedDistance============================="+ mSlidedDistance); 167 | 168 | final MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams(); 169 | int left = params.leftMargin; 170 | int top = params.topMargin; 171 | int right = params.rightMargin; 172 | int bottom = params.bottomMargin; 173 | 174 | logI(TAG, "left:"+left+",top:"+top+",right:"+right+",bottom"+bottom); 175 | 176 | int leftNew = left + dX; 177 | int rightNew =right - dX; 178 | 179 | if (mSlidedDistance > 0) {//直接通过margin实现滑动 180 | params.setMargins(leftNew, top, rightNew, bottom); 181 | logI(TAG, leftNew + "=============================MOVE"); 182 | v.setLayoutParams(params); 183 | resetTextViewAlpha(mSlidedDistance); 184 | 185 | //回调 186 | if(mCallBack!=null){ 187 | mCallBack.onSlide(mSlidedDistance); 188 | } 189 | mLastX = (int) event.getRawX(); 190 | } else { 191 | return true; 192 | } 193 | 194 | break; 195 | 196 | 197 | case MotionEvent.ACTION_UP: 198 | logI(TAG, "MotionEvent.ACTION_UP,之前移动的偏移值:" + ViewHelper.getTranslationY(v)); 199 | if (Math.abs(mSlidedDistance) > DISTANCE_LIMIT) { 200 | scrollToRight(v);//右边 201 | } else { 202 | scrollToLeft(v);//左边 203 | } 204 | break; 205 | 206 | 207 | case MotionEvent.ACTION_CANCEL: 208 | // try { 209 | // if (vTracker != null) { 210 | // vTracker.recycle(); 211 | // vTracker = null; 212 | // } 213 | // vTracker.recycle(); 214 | // } catch (Exception e) { 215 | // e.printStackTrace(); 216 | // } 217 | 218 | break; 219 | 220 | } 221 | 222 | 223 | return true; 224 | } 225 | }); 226 | 227 | 228 | 229 | } 230 | 231 | 232 | private void logI(String tag,String content){ 233 | if(LOG){ 234 | Log.i(tag,content); 235 | } 236 | } 237 | 238 | /** 239 | * @method name:resetTextViewAlpha 240 | * @des: 重置提示文本的透明度 241 | * @param :[mSlidedDistance] 242 | * @return type:void 243 | * @date 创建时间:2017/5/24 244 | * @author Chuck 245 | **/ 246 | private void resetTextViewAlpha(int distance) { 247 | 248 | if(Math.abs(distance)>=Math.abs(DISTANCE_LIMIT)){ 249 | tv_hint.setAlpha(0.0f); 250 | } 251 | else{ 252 | tv_hint.setAlpha(1.0f-Math.abs(distance)*1.0f/Math.abs(DISTANCE_LIMIT)); 253 | } 254 | } 255 | 256 | 257 | /** 258 | * @method name:scrollToLeft 259 | * @des: 滑动未到阈值时松开手指,弹回到最左边 260 | * @param :[v] 261 | * @return type:void 262 | * @date 创建时间:2017/5/24 263 | * @author Chuck 264 | **/ 265 | private void scrollToLeft(final View v) { 266 | 267 | 268 | final MarginLayoutParams params1 = (MarginLayoutParams) v.getLayoutParams(); 269 | logI(TAG, "scrollToLeft,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v)); 270 | logI(TAG, "scrollToLeft,params1.leftMargin:" + params1.leftMargin); 271 | logI(TAG, "scrollToLeft, params1.rightMargin:" + params1.rightMargin); 272 | 273 | 274 | ViewAnimator 275 | .animate( rl_slide) 276 | .translationX(ViewHelper.getTranslationX(v), -params1.leftMargin) 277 | .interpolator(new AccelerateInterpolator()) 278 | .duration(DEAFULT_DURATIN_LONG) 279 | .onStop(new AnimationListener.Stop() { 280 | @Override 281 | public void onStop() { 282 | MarginLayoutParams para = (MarginLayoutParams) v.getLayoutParams(); 283 | logI(TAG, "scrollToLeft动画结束para.leftMargin:" + para.leftMargin); 284 | logI(TAG, "scrollToLeft动画结束para.rightMargin:" + para.rightMargin); 285 | logI(TAG, "scrollToLeft动画结束,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v)); 286 | mSlidedDistance = 0; 287 | tv_hint.setAlpha(1.0f); 288 | mIsUnLocked=false; 289 | if(mCallBack!=null){ 290 | mCallBack.onSlide(mSlidedDistance); 291 | } 292 | setImageDefault(); 293 | } 294 | }) 295 | .start(); 296 | } 297 | 298 | 299 | /** 300 | * @method name:scrollToRight 301 | * @des:滑动到右边,并触发回调 302 | * @param :[v] 303 | * @return type:void 304 | * @date 创建时间:2017/5/24 305 | * @author Chuck 306 | **/ 307 | private void scrollToRight(final View v) { 308 | 309 | 310 | final MarginLayoutParams params1 = (MarginLayoutParams) v.getLayoutParams(); 311 | logI(TAG, "scrollToRight,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v)); 312 | logI(TAG, "scrollToRight,params1.leftMargin:" + params1.leftMargin); 313 | logI(TAG, "scrollToRight, params1.rightMargin:" + params1.rightMargin); 314 | 315 | //移动到最右端 移动的距离是 父容器宽度-leftMargin 316 | ViewAnimator 317 | .animate( rl_slide) 318 | //.translationX(ViewHelper.getTranslationX(v), ViewHelper.getTranslationX(v)+100) 319 | .translationX(ViewHelper.getTranslationX(v), ( rl_slide.getWidth() - params1.leftMargin-slideImageViewWidth)) 320 | //.translationX(params1.leftMargin, ( rl_slide.getWidth() - params1.leftMargin-100)) 321 | .interpolator(new AccelerateInterpolator()) 322 | .duration(DEAFULT_DURATIN_SHORT) 323 | .onStop(new AnimationListener.Stop() { 324 | @Override 325 | public void onStop() { 326 | MarginLayoutParams para = (MarginLayoutParams) v.getLayoutParams(); 327 | logI(TAG, "scrollToRight动画结束para.leftMargin:" + para.leftMargin); 328 | logI(TAG, "scrollToRight动画结束para.rightMargin:" + para.rightMargin); 329 | logI(TAG, "scrollToRight动画结束,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v)); 330 | mSlidedDistance = 0; 331 | tv_hint.setAlpha(0.0f); 332 | mIsUnLocked=true; 333 | 334 | if(slideImageViewResIdAfter>0){ 335 | iv_slide.setImageResource(slideImageViewResIdAfter);//滑块imagview设置资源 336 | } 337 | 338 | //回调 339 | if(mCallBack!=null){ 340 | mCallBack.onUnlocked(); 341 | } 342 | } 343 | }) 344 | .start(); 345 | 346 | 347 | } 348 | 349 | 350 | public void resetView(){ 351 | mIsUnLocked=false; 352 | setImageDefault(); 353 | scrollToLeft(rl_slide); 354 | } 355 | 356 | private void setImageDefault() { 357 | /** 358 | * @method name:setImageDefault 359 | * @des: 设置默认图片 360 | * @param :[] 361 | * @return type:void 362 | * @date 创建时间:2017/5/25 363 | * @author Chuck 364 | **/ 365 | 366 | if(slideImageViewResId>0){ 367 | iv_slide.setImageResource(slideImageViewResId);//滑块imagview设置资源 368 | } 369 | } 370 | 371 | public interface CallBack{ 372 | void onSlide(int distance);//右滑距离回调 373 | void onUnlocked();//滑动到了右边,事件回调 374 | } 375 | 376 | 377 | public CallBack getmCallBack() { 378 | return mCallBack; 379 | } 380 | 381 | public void setmCallBack(CallBack mCallBack) { 382 | this.mCallBack = mCallBack; 383 | } 384 | } 385 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/java/com/qdong/slide_to_unlock_view/DensityUtil.java: -------------------------------------------------------------------------------- 1 | package com.qdong.slide_to_unlock_view; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.util.TypedValue; 6 | import android.view.WindowManager; 7 | 8 | public class DensityUtil { 9 | 10 | @Deprecated 11 | public static int dip2px(Context paramContext, float paramFloat) { 12 | return (int) (0.5F + paramFloat 13 | * paramContext.getResources().getDisplayMetrics().density); 14 | } 15 | 16 | @Deprecated 17 | public static int px2dip(Context context, float paramFloat) { 18 | return (int) (0.5F + paramFloat 19 | / context.getResources().getDisplayMetrics().density); 20 | } 21 | 22 | @Deprecated 23 | public static int sp2px(Context context, float spValue) { 24 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 25 | return (int) (spValue * fontScale + 0.5f); 26 | } 27 | 28 | @Deprecated 29 | public static int px2sp(Context context, float value) { 30 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 31 | return (int) (value / fontScale + 0.5f); 32 | } 33 | 34 | public static int dip2px(float density, float value) { 35 | return (int) (0.5F + value * density); 36 | } 37 | 38 | public static int px2dip(float density, float value) { 39 | return (int) (0.5F + value / density); 40 | } 41 | 42 | public static int sp2px(float scaledDensity, float value) { 43 | return (int) (0.5F + value * scaledDensity); 44 | } 45 | 46 | public static int px2sp(float fontScale /** scaledDensity */ 47 | , float value) { 48 | return (int) (value / fontScale + 0.5f); 49 | 50 | 51 | } 52 | 53 | public static final int getStatusHeighByDensity(Context context) { 54 | int h = 38; 55 | int density = context.getResources().getDisplayMetrics().densityDpi; 56 | 57 | switch (density) { 58 | case 120: 59 | h = 19; 60 | break; 61 | case 160: 62 | h = 25; 63 | break; 64 | case 240: 65 | h = 38; 66 | break; 67 | case 320: 68 | h = 50; 69 | break; 70 | case 400: 71 | h = 63; 72 | break; 73 | case 480: 74 | h = 75; 75 | break; 76 | default: 77 | break; 78 | } 79 | 80 | return h; 81 | } 82 | 83 | private static int displayWidth, displayHeight; 84 | 85 | private static void initDisplay(Context context) { 86 | DisplayMetrics dm = new DisplayMetrics(); 87 | ((WindowManager) context.getApplicationContext().getSystemService( 88 | Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm); 89 | 90 | displayWidth = dm.widthPixels; 91 | 92 | displayHeight = dm.heightPixels; 93 | } 94 | 95 | 96 | public static final int getDisplayWidth(Context context) { 97 | if (displayWidth == 0) { 98 | initDisplay(context); 99 | } 100 | return displayWidth; 101 | } 102 | 103 | 104 | public static final int getDisplayHeight(Context context) { 105 | if (displayHeight == 0) { 106 | initDisplay(context); 107 | } 108 | return displayHeight; 109 | } 110 | 111 | public static int dp2px(Context context, int dp) { 112 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,context.getResources().getDisplayMetrics()); 113 | } 114 | 115 | public static int dp2px(Context context, float dp) { 116 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,context.getResources().getDisplayMetrics()); 117 | } 118 | 119 | public static int px2dp(Context context, int px) { 120 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px,context.getResources().getDisplayMetrics()); 121 | } 122 | 123 | public static int px2sp(Context context, int px) { 124 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, px,context.getResources().getDisplayMetrics()); 125 | } 126 | 127 | public static int getScreenWidth(Context context) 128 | { 129 | WindowManager wm = (WindowManager) context 130 | .getSystemService(Context.WINDOW_SERVICE ); 131 | DisplayMetrics outMetrics = new DisplayMetrics(); 132 | wm.getDefaultDisplay().getMetrics( outMetrics); 133 | return outMetrics .widthPixels ; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/res/drawable/shape_round_normal_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/res/layout/layout_view_slide_to_unlock.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 15 | 16 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506954774/AndroidCustomSlideToUnlockView/6eb1bf618c51dac7371656bfa36e35c443661ecc/SlideToUnlockView/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/res/mipmap-xhdpi/icon_slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506954774/AndroidCustomSlideToUnlockView/6eb1bf618c51dac7371656bfa36e35c443661ecc/SlideToUnlockView/src/main/res/mipmap-xhdpi/icon_slide.png -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SlideToUnlockView 3 | 滑动解锁 4 | 5 | 6 | -------------------------------------------------------------------------------- /SlideToUnlockView/src/test/java/com/qdong/slide_to_unlock_view/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.qdong.slide_to_unlock_view; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/506954774/AndroidCustomSlideToUnlockView/6eb1bf618c51dac7371656bfa36e35c443661ecc/app-debug.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | repositories { 4 | flatDir { 5 | dir 'libs' 6 | } 7 | maven { url "https://jitpack.io" } 8 | } 9 | 10 | android { 11 | compileSdkVersion 25 12 | buildToolsVersion "25.0.1" 13 | 14 | defaultConfig { 15 | applicationId "com.qdong.slidetounlockdemo" 16 | minSdkVersion 19 17 | targetSdkVersion 25 18 | versionCode 1 19 | versionName "1.0" 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | } 28 | 29 | dependencies { 30 | compile fileTree(include: ['*.jar'], dir: 'libs') 31 | testCompile 'junit:junit:4.12' 32 | compile 'com.android.support:appcompat-v7:25.1.0' 33 | compile 'com.nineoldandroids:library:2.4.0' 34 | compile 'com.github.florent37:viewanimator:1.0.0@aar' 35 | //compile project(':slidetounlockview') 36 | compile 'com.linklink.views:slide_to_unlock_view:1.0.0' 37 | } 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\IDE\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/qdong/slidetounlockdemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.qdong.slidetounlockdemo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/qdong/slidetounlockdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.qdong.slidetounlockdemo; 2 | import android.os.Bundle; 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | import com.qdong.slide_to_unlock_view.CustomSlideToUnlockView; 7 | 8 | 9 | public class MainActivity extends AppCompatActivity { 10 | 11 | private CustomSlideToUnlockView mCustomSlideToUnlockView; 12 | private TextView tv_text; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | mCustomSlideToUnlockView= (com.qdong.slide_to_unlock_view.CustomSlideToUnlockView) findViewById(R.id.slide_to_unlock); 19 | tv_text= (TextView) findViewById(R.id.tv_text); 20 | 21 | CustomSlideToUnlockView.CallBack callBack=new CustomSlideToUnlockView.CallBack() { 22 | @Override 23 | public void onSlide(int distance) { 24 | tv_text.setText("slide distance:"+distance); 25 | } 26 | 27 | @Override 28 | public void onUnlocked() { 29 | tv_text.setText("onUnlocked"); 30 | } 31 | }; 32 | mCustomSlideToUnlockView.setmCallBack(callBack); 33 | findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View view) { 36 | mCustomSlideToUnlockView.resetView(); 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_round_normal_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 24 | 37 | 38 | 39 | 40 | 41 |