├── .github └── workflows │ └── android.yml ├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhpan │ │ └── ovallockview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zhpan │ │ │ └── ovallockview │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zhpan │ └── ovallockview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── new.gif └── yanshi.gif ├── lockview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhpan │ │ └── lockview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zhpan │ │ │ └── lockview │ │ │ ├── LockView.java │ │ │ ├── enums │ │ │ └── LockOption.java │ │ │ ├── listener │ │ │ └── OnLockOperateListener.java │ │ │ ├── utils │ │ │ └── LockViewUtils.java │ │ │ └── view │ │ │ ├── CircleView.java │ │ │ └── CircleWaveView.java │ └── res │ │ ├── drawable-xxhdpi │ │ ├── slide_lock.png │ │ └── slide_unlock.png │ │ ├── drawable-xxxhdpi │ │ ├── slide_lock.png │ │ └── slide_unlock.png │ │ ├── drawable │ │ ├── slide_lock.png │ │ └── slide_unlock.png │ │ ├── layout │ │ └── layout_oval_lock.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── zhpan │ └── lockview │ └── ExampleUnitTest.java └── settings.gradle /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - main 9 | jobs: 10 | my_job: 11 | name: deploy to staging 12 | runs-on: ubuntu-18.04 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OvalLockView 2 | 动画效果 3 | 4 | ![这里写图片描述](https://github.com/zhpanvip/OvalLockView/blob/master/image/new.gif) 5 | 6 | 使用方法: 7 | 1.添加依赖 8 | ``` 9 | compile 'com.zhpan.lockview:lockview:1.1.8' 10 | ``` 11 | 12 | 2.布局文件添加 13 | ``` 14 | 19 | ``` 20 | 3.设置操作的监听事件 21 | ``` 22 | mLockView.setOnLockOperateListener(new OnLockOperateListener() { 23 | @Override 24 | public void onLockPrepared() {// 准备上锁 25 | 26 | } 27 | 28 | @Override 29 | public void onUnLockPrepared() {// 准备开锁 30 | 31 | } 32 | 33 | @Override 34 | public void onLockStart() {// 开始上锁 35 | 36 | } 37 | 38 | @Override 39 | public void onUnlockStart() {// 开始开锁 40 | 41 | } 42 | 43 | @Override 44 | public void onNotPrepared() {// 上下滑动距离未达到准备上锁或者准备开锁状态而释放 45 | 46 | } 47 | }); 48 | ``` 49 | 4.开放接口 50 | ``` 51 | // 设置蓝牙是否连接 52 | mLockView.setBluetoothConnect(false); 53 | // 设置上锁状态 54 | mLockView.setLockState(isLock); 55 | // 设置View是否可以滑动 56 | mLockView.setCanSlide(true) 57 | // 设置滑动阻尼大小 58 | mLockView.setDamping(1.7) 59 | // 设置View中心文字 60 | mLockView.setText("已上锁"); 61 | // 设置中心大圆的颜色 62 | mLockView.setCircleColor 63 | // 开启心跳动画 64 | mLockView.startWave(); 65 | // 停止心跳动画 66 | mLockView.stopWave(); 67 | // 是否正在搜索/连接蓝牙 68 | mLockView.connecting(true); 69 | 70 | // 点击事件监听(只有在未连接蓝牙时有效) 71 | mLockView.setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | 75 | } 76 | }); 77 | ``` 78 | 79 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.zhpan.ovallockview" 7 | minSdkVersion 19 8 | targetSdkVersion 25 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'com.android.support:appcompat-v7:26.1.0' 24 | testImplementation 'junit:junit:4.12' 25 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 26 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 27 | implementation project(':lockview') 28 | // compile 'com.zhpan.lockview:lockview:1.1.0' 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zhpan/ovallockview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.ovallockview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zhpan.ovallockview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhpan/ovallockview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.ovallockview; 2 | 3 | import android.os.Handler; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Toast; 8 | 9 | import com.zhpan.lockview.listener.OnLockOperateListener; 10 | import com.zhpan.lockview.LockView; 11 | 12 | 13 | public class MainActivity extends AppCompatActivity implements OnLockOperateListener, View.OnClickListener { 14 | private LockView mLockView; 15 | private static final Handler mHandler = new Handler(); 16 | private final Runnable mLockRunnable = new Runnable() { 17 | @Override 18 | public void run() { 19 | // 设置为上锁状态 20 | changeLockState(true); 21 | } 22 | }; 23 | 24 | private final Runnable mUnlockRunnable = new Runnable() { 25 | @Override 26 | public void run() { 27 | // 设置为未上锁状态 28 | changeLockState(false); 29 | 30 | } 31 | }; 32 | private boolean isOperating; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_main); 38 | mLockView = findViewById(R.id.lock_view); 39 | // 初始化时设置蓝牙未连接,此时可以点击,但不能滑动 40 | mLockView.setBluetoothConnect(false); 41 | // 添加滑动事件监听 42 | mLockView.setOnLockOperateListener(this); 43 | // 设置点击事件监听 44 | mLockView.setOnClickListener(this); 45 | // 设置滑动阻尼大小 46 | mLockView.setDamping(2); 47 | mLockView.setText("下滑开锁","上滑上锁"); 48 | mLockView.setTextSize(14); 49 | mLockView.setCenterTextSize(18); 50 | mLockView.setConnectingText("正在连接"); 51 | // mLockView.setDeviceFrozen("已冻结"); 52 | // 设置上锁状态 53 | /* if (mLockView.isLock()) { 54 | mLockView.setText("已上锁"); 55 | } else { 56 | mLockView.setText("未上锁"); 57 | }*/ 58 | mLockView.setNoNetData(true,"未连接"); 59 | } 60 | 61 | private void changeLockState(boolean isLock) { 62 | isOperating = false; 63 | mLockView.stopWave(); 64 | mLockView.setLockState(isLock); 65 | if (isLock) 66 | mLockView.setText("已上锁"); 67 | else 68 | mLockView.setText("未上锁"); 69 | } 70 | 71 | @Override 72 | public void onLockPrepared() { 73 | mLockView.setText("释放上锁"); 74 | } 75 | 76 | @Override 77 | public void onUnLockPrepared() { 78 | mLockView.setText("释放开锁"); 79 | } 80 | 81 | @Override 82 | public void onLockStart() { 83 | if (isOperating) { 84 | Toast.makeText(this, "正在操作,请稍后再试", Toast.LENGTH_SHORT).show(); 85 | return; 86 | } 87 | isOperating = true; 88 | mLockView.setText("正在上锁"); 89 | mLockView.startWave(); 90 | mHandler.postDelayed(mLockRunnable, 3000); 91 | } 92 | 93 | @Override 94 | public void onUnlockStart() { 95 | if (isOperating) { 96 | Toast.makeText(this, "正在操作,请稍后再试", Toast.LENGTH_SHORT).show(); 97 | return; 98 | } 99 | isOperating = true; 100 | mLockView.startWave(); 101 | mLockView.setText("正在开锁"); 102 | mHandler.postDelayed(mUnlockRunnable, 3000); 103 | } 104 | 105 | @Override 106 | public void onNotPrepared() { 107 | if (mLockView.isLock()) { 108 | mLockView.setText("已上锁"); 109 | } else { 110 | mLockView.setText("未上锁"); 111 | } 112 | } 113 | 114 | @Override 115 | public void onClick(View v) { 116 | mLockView.connecting(true); 117 | mHandler.postDelayed(new Runnable() { 118 | @Override 119 | public void run() { 120 | mLockView.connecting(false); 121 | // 设置蓝牙已连接 122 | mLockView.setBluetoothConnect(true); 123 | // mLockView.setDeviceFrozen("已冻结"); 124 | } 125 | }, 2000); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | OvalLockView 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/zhpan/ovallockview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.ovallockview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.4' 11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 12 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | maven { url "https://jitpack.io" } 24 | maven { 25 | url "https://dl.bintray.com/zhpanvip/LockView" //这个要添加,只要更改junwen成你的用户名即可 26 | } 27 | } 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Aug 29 20:55:43 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /image/new.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/image/new.gif -------------------------------------------------------------------------------- /image/yanshi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/image/yanshi.gif -------------------------------------------------------------------------------- /lockview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /lockview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'com.jfrog.bintray' 4 | 5 | // 这个version是区分library版本的,因此当我们需要更新library时记得修改这个version 6 | version = "1.1.8" 7 | android { 8 | compileSdkVersion 26 9 | 10 | defaultConfig { 11 | minSdkVersion 19 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | compileOnly 'com.android.support:appcompat-v7:26.1.0' 32 | testImplementation 'junit:junit:4.12' 33 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 34 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 35 | } 36 | 37 | def siteUrl = 'https://github.com/zhpanvip/OvalLockView' // 项目的主页 38 | def gitUrl = 'https://github.com/zhpanvip/OvalLockView.git' // Git仓库的url 39 | group = "com.zhpan.lockview" // Maven Group ID for the artifact,一般填你唯一的包名 40 | install { 41 | repositories.mavenInstaller { 42 | // This generates POM.xml with proper parameters 43 | pom { 44 | project { 45 | packaging 'aar' 46 | // Add your description here 47 | description 'An android Lock View' 48 | name 'LockView' //项目描述 49 | url siteUrl 50 | // Set your license 51 | licenses { 52 | license { 53 | name 'The Apache Software License, Version 2.0' 54 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 55 | } 56 | } 57 | developers { 58 | developer { // 开发者信息 59 | id 'zhpan' 60 | name 'zhangpan' 61 | email 'zhpanvip@outlook.com' 62 | } 63 | } 64 | scm { 65 | connection gitUrl 66 | developerConnection gitUrl 67 | url siteUrl 68 | } 69 | } 70 | } 71 | } 72 | } 73 | task sourcesJar(type: Jar) { 74 | from android.sourceSets.main.java.srcDirs 75 | classifier = 'sources' 76 | } 77 | task javadoc(type: Javadoc) { 78 | failOnError false 79 | } 80 | 81 | task javadocJar(type: Jar, dependsOn: javadoc) { 82 | classifier = 'javadoc' 83 | from javadoc.destinationDir 84 | } 85 | artifacts { 86 | archives javadocJar 87 | archives sourcesJar 88 | } 89 | Properties properties = new Properties() 90 | // 加载本地配置 91 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 92 | bintray { 93 | user = properties.getProperty("bintray.user") 94 | key = properties.getProperty("bintray.apikey") 95 | configurations = ['archives'] 96 | pkg { 97 | repo = "LockView" //发布到Bintray的那个仓库里,默认账户有四个库,我们这里上传到maven库 98 | name = "lockview" //发布到Bintray上的项目名字 99 | websiteUrl = siteUrl 100 | vcsUrl = gitUrl 101 | licenses = ["Apache-2.0"] 102 | publish = true 103 | } 104 | } 105 | 106 | //提交命令:gradlew bintrayUpload 107 | -------------------------------------------------------------------------------- /lockview/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /lockview/src/androidTest/java/com/zhpan/lockview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zhpan.lockview.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lockview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /lockview/src/main/java/com/zhpan/lockview/LockView.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | import android.view.ViewConfiguration; 9 | import android.widget.FrameLayout; 10 | import android.widget.ImageView; 11 | import android.widget.LinearLayout; 12 | import android.widget.Scroller; 13 | import android.widget.TextView; 14 | 15 | import com.zhpan.lockview.enums.LockOption; 16 | import com.zhpan.lockview.listener.OnLockOperateListener; 17 | import com.zhpan.lockview.utils.LockViewUtils; 18 | import com.zhpan.lockview.view.CircleWaveView; 19 | 20 | import static android.view.MotionEvent.ACTION_DOWN; 21 | import static android.view.MotionEvent.ACTION_UP; 22 | import static com.zhpan.lockview.enums.LockOption.LOCK; 23 | import static com.zhpan.lockview.enums.LockOption.UNLOCK; 24 | 25 | /** 26 | * Created by zhpan on 2018/5/26. 27 | * Description: 自定义开关锁控件 28 | */ 29 | public class LockView extends FrameLayout { 30 | private CircleWaveView mCircleWaveView; 31 | private ImageView mIvUnlock; 32 | private TextView mTvLock; 33 | private TextView mTvUnlock; 34 | private Scroller mScroller; 35 | private int mLastY; 36 | private int mTouchSlop; 37 | private LockOption mLockOption; 38 | private boolean canSlide = true; 39 | private LinearLayout mProgressBar; 40 | // 阻尼系数 41 | private double damping = 2.0; 42 | // 小圆圆心到大圆圆心距离 43 | private int distance; 44 | private int border; 45 | private OnLockOperateListener mOnLockOperateListener; 46 | private static final Handler mHandler = new Handler(); 47 | private final Runnable mRunnable = new Runnable() { 48 | @Override 49 | public void run() { 50 | mCircleWaveView.startWave(); 51 | } 52 | }; 53 | private TextView mTvConnection; 54 | private boolean isFrozen; 55 | 56 | public LockView(Context context) { 57 | this(context, null); 58 | } 59 | 60 | public LockView(Context context, AttributeSet attrs) { 61 | this(context, attrs, 0); 62 | } 63 | 64 | public LockView(Context context, AttributeSet attrs, int defStyleAttr) { 65 | super(context, attrs, defStyleAttr); 66 | init(context, attrs); 67 | } 68 | 69 | private void init(Context context, AttributeSet attrs) { 70 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 71 | View view = View.inflate(context, R.layout.layout_oval_lock, this); 72 | mCircleWaveView = view.findViewById(R.id.circle_wave_view); 73 | mIvUnlock = view.findViewById(R.id.green_cv); 74 | distance = ((LayoutParams) mIvUnlock.getLayoutParams()).topMargin; 75 | mProgressBar = view.findViewById(R.id.ll_progress); 76 | mTvConnection = view.findViewById(R.id.tv_connecting); 77 | mTvLock = view.findViewById(R.id.tv_lock); 78 | mTvUnlock = view.findViewById(R.id.tv_unlock); 79 | mScroller = mCircleWaveView.getScroller(); 80 | mCircleWaveView.setOnClickListener(new OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | } 84 | }); 85 | } 86 | 87 | @Override 88 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 89 | View view = getChildAt(0); 90 | view.layout(0, 0, getMeasuredWidth(), getMeasuredHeight()); 91 | } 92 | 93 | @Override 94 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 95 | super.onSizeChanged(w, h, oldw, oldh); 96 | } 97 | 98 | @Override 99 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 100 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 101 | border = getSlideBorder(); 102 | } 103 | 104 | // 可上下滑动的最大距离; 105 | private int getSlideBorder() { 106 | return (distance - mCircleWaveView.getRadius() + mIvUnlock.getHeight() / 2) + 107 | LockViewUtils.dp2px(25); 108 | } 109 | 110 | @Override 111 | public boolean onInterceptTouchEvent(MotionEvent ev) { 112 | boolean intercepted = true; 113 | int y = (int) ev.getY(); 114 | switch (ev.getAction()) { 115 | case ACTION_DOWN: 116 | intercepted = false; 117 | if (!mScroller.isFinished()) { 118 | mScroller.abortAnimation(); 119 | } 120 | break; 121 | case MotionEvent.ACTION_MOVE: 122 | if (Math.abs(y - mLastY) > mTouchSlop) { 123 | intercepted = true; 124 | } 125 | break; 126 | case MotionEvent.ACTION_UP: 127 | intercepted = false; 128 | break; 129 | } 130 | mLastY = y; 131 | return intercepted; 132 | } 133 | 134 | @Override 135 | public boolean onTouchEvent(MotionEvent event) { 136 | int y = (int) event.getY(); 137 | int scrollY = mCircleWaveView.getScrollY(); 138 | switch (event.getAction()) { 139 | case ACTION_DOWN: 140 | if (!mScroller.isFinished()) { 141 | mScroller.abortAnimation(); 142 | } 143 | break; 144 | case MotionEvent.ACTION_MOVE: 145 | if (!canSlide || isFrozen) { 146 | return super.onTouchEvent(event); 147 | } 148 | onActionMove(scrollY, y); 149 | break; 150 | case MotionEvent.ACTION_UP: 151 | onActionUp(scrollY); 152 | break; 153 | } 154 | mLastY = y; 155 | return super.onTouchEvent(event); 156 | } 157 | 158 | private void onActionUp(int scrollY) { 159 | mCircleWaveView.setUnLockPrePared(false); 160 | mCircleWaveView.setLockPrepared(false); 161 | if (Math.abs(scrollY) > (distance - mCircleWaveView.getRadius() + mIvUnlock.getHeight() / 2) && mLockOption != null) { 162 | switch (mLockOption) { 163 | case LOCK: 164 | if (mOnLockOperateListener != null) 165 | mOnLockOperateListener.onLockStart(); 166 | break; 167 | case UNLOCK: 168 | if (mOnLockOperateListener != null) 169 | mOnLockOperateListener.onUnlockStart(); 170 | break; 171 | default: 172 | break; 173 | } 174 | } 175 | mCircleWaveView.smoothScroll(0, 0); 176 | } 177 | 178 | private void onActionMove(int scrollY, int y) { 179 | if (mCircleWaveView.getScrollY() > mTouchSlop) { 180 | mLockOption = LOCK; 181 | } else if (mCircleWaveView.getScrollY() < -mTouchSlop) { 182 | mLockOption = UNLOCK; 183 | } 184 | if (Math.abs(scrollY) > (distance - mCircleWaveView.getRadius() + mIvUnlock.getHeight() / 2)) { 185 | if (mLockOption != null) { 186 | switch (mLockOption) { 187 | case LOCK: 188 | if (mOnLockOperateListener != null) 189 | mOnLockOperateListener.onLockPrepared(); 190 | mCircleWaveView.setLockPrepared(true); 191 | break; 192 | case UNLOCK: 193 | if (mOnLockOperateListener != null) 194 | mOnLockOperateListener.onUnLockPrepared(); 195 | mCircleWaveView.setUnLockPrePared(true); 196 | break; 197 | default: 198 | break; 199 | } 200 | } 201 | } else { 202 | mCircleWaveView.setUnLockPrePared(false); 203 | mCircleWaveView.setLockPrepared(false); 204 | mOnLockOperateListener.onNotPrepared(); 205 | } 206 | int deltaY = (int) ((mLastY - y) / damping); 207 | // 当前上下滑动的距离 208 | int slideHeight = deltaY + mCircleWaveView.getScrollY(); 209 | if (slideHeight > border) { 210 | mCircleWaveView.scrollTo(0, border); 211 | } else if (slideHeight + border < 0) { 212 | mCircleWaveView.scrollTo(0, -border); 213 | } 214 | mCircleWaveView.scrollBy(0, deltaY); 215 | } 216 | 217 | private long timestamp = 0; 218 | 219 | @Override 220 | public boolean dispatchTouchEvent(MotionEvent ev) { 221 | if (!canSlide) 222 | switch (ev.getAction()) { 223 | case ACTION_DOWN: 224 | timestamp = System.currentTimeMillis(); 225 | break; 226 | case ACTION_UP: 227 | if (System.currentTimeMillis() - timestamp < 500) { 228 | performClick(); 229 | return true; 230 | } 231 | break; 232 | } 233 | return super.dispatchTouchEvent(ev); 234 | } 235 | 236 | public void startWave() { 237 | mHandler.postDelayed(mRunnable, 300); 238 | } 239 | 240 | public void stopWave() { 241 | mHandler.removeCallbacks(mRunnable); 242 | mCircleWaveView.stopWave(); 243 | } 244 | 245 | 246 | /** 247 | * 是否能够开门 248 | */ 249 | public void setLock(boolean lock) { 250 | mCircleWaveView.setLock(lock); 251 | } 252 | 253 | /** 254 | * @return 是否上锁 255 | */ 256 | public boolean isLock() { 257 | return mCircleWaveView.isLock(); 258 | } 259 | 260 | /** 261 | * 设置上锁状态 262 | * 263 | * @param lock true:设置为上锁状态;false:设置为开锁状态 264 | */ 265 | public void setLockState(boolean lock) { 266 | isFrozen = false; 267 | mCircleWaveView.changeLockState(lock); 268 | setLock(lock); 269 | } 270 | 271 | /** 272 | * 设置中心文字 273 | */ 274 | public void setText(String text) { 275 | mCircleWaveView.setText(text); 276 | } 277 | 278 | /** 279 | * 设置中心文字大小 280 | */ 281 | public void setTextSize(int textSize) { 282 | mTvUnlock.setTextSize(textSize); 283 | mTvLock.setTextSize(textSize); 284 | invalidate(); 285 | } 286 | 287 | /** 288 | * 设置中心文字 289 | * 290 | * @param unlockText 开锁时文字 291 | * @param lockText 上锁时文字 292 | */ 293 | public void setText(String unlockText, String lockText) { 294 | mTvUnlock.setText(unlockText); 295 | mTvLock.setText(lockText); 296 | invalidate(); 297 | } 298 | 299 | /** 300 | * 设置中心文字颜色 301 | * 302 | * @param unlockColor 开锁状态时颜色 303 | * @param lockColor 开锁状态时颜色 304 | */ 305 | public void setTextColor(int unlockColor, int lockColor) { 306 | mTvUnlock.setTextColor(unlockColor); 307 | mTvLock.setTextColor(lockColor); 308 | } 309 | 310 | 311 | public void showText(boolean showText) { 312 | if (showText) { 313 | mTvLock.setVisibility(VISIBLE); 314 | mTvUnlock.setVisibility(VISIBLE); 315 | } else { 316 | mTvLock.setVisibility(INVISIBLE); 317 | mTvUnlock.setVisibility(INVISIBLE); 318 | } 319 | invalidate(); 320 | } 321 | 322 | /** 323 | * @param canSlide 是否可以滑动 324 | */ 325 | public void setCanSlide(boolean canSlide) { 326 | this.canSlide = canSlide; 327 | } 328 | 329 | /** 330 | * 设置滑动阻尼 331 | */ 332 | public void setDamping(double damping) { 333 | this.damping = damping; 334 | } 335 | 336 | public void setBluetoothConnect(boolean isConnect, String text) { 337 | mCircleWaveView.setBluetoothConnect(isConnect); 338 | mCircleWaveView.setText(text); 339 | setCanSlide(isConnect); 340 | } 341 | 342 | public void setBluetoothConnect(boolean isConnect) { 343 | mCircleWaveView.setBluetoothConnect(isConnect); 344 | setCanSlide(isConnect); 345 | } 346 | 347 | public void setNoNetData(boolean isNoData) { 348 | mCircleWaveView.setNoNetData(isNoData); 349 | } 350 | 351 | public void setNoNetData(boolean isNoData, String text) { 352 | mCircleWaveView.setNoNetData(isNoData, text); 353 | } 354 | 355 | public void connecting(boolean isConnecting) { 356 | mCircleWaveView.setConnecting(isConnecting); 357 | if (isConnecting) { 358 | mProgressBar.setVisibility(VISIBLE); 359 | setCanSlide(false); 360 | } else { 361 | mProgressBar.setVisibility(GONE); 362 | } 363 | } 364 | 365 | public boolean isConnecting() { 366 | return mCircleWaveView.isConnecting(); 367 | } 368 | 369 | public void setCircleColor(int color) { 370 | mCircleWaveView.setCircleColor(color); 371 | } 372 | 373 | public void setCenterTextSize(float textSize) { 374 | mCircleWaveView.setTextSize(textSize); 375 | } 376 | 377 | public void setOnLockOperateListener(OnLockOperateListener onLockOperateListener) { 378 | mOnLockOperateListener = onLockOperateListener; 379 | } 380 | 381 | public void setConnectingText(String text) { 382 | mTvConnection.setText(text); 383 | } 384 | 385 | public void setDeviceFrozen(String frozen) { 386 | connecting(false); 387 | setBluetoothConnect(true); 388 | setLockState(true); 389 | isFrozen = true; 390 | setText(frozen); 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /lockview/src/main/java/com/zhpan/lockview/enums/LockOption.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview.enums; 2 | 3 | /** 4 | * @author zhangpan 5 | * @date 2020/10/23 6 | */ 7 | public enum LockOption { 8 | LOCK, UNLOCK 9 | } 10 | -------------------------------------------------------------------------------- /lockview/src/main/java/com/zhpan/lockview/listener/OnLockOperateListener.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview.listener; 2 | 3 | public interface OnLockOperateListener { 4 | // 上锁就绪 5 | void onLockPrepared(); 6 | // 开锁就绪 7 | void onUnLockPrepared(); 8 | // 开始上锁 9 | void onLockStart(); 10 | // 开始开锁 11 | void onUnlockStart(); 12 | // 未就绪 13 | void onNotPrepared(); 14 | } 15 | -------------------------------------------------------------------------------- /lockview/src/main/java/com/zhpan/lockview/utils/LockViewUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview.utils; 2 | 3 | import android.content.res.Resources; 4 | 5 | /** 6 | * dp px转换 7 | */ 8 | public class LockViewUtils { 9 | 10 | public static int dp2px(float dpValue) { 11 | return (int) (0.5F + dpValue * Resources.getSystem().getDisplayMetrics().density); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lockview/src/main/java/com/zhpan/lockview/view/CircleView.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview.view; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.Rect; 8 | import android.text.TextUtils; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | import com.zhpan.lockview.R; 13 | import com.zhpan.lockview.utils.LockViewUtils; 14 | 15 | 16 | /** 17 | * Created by zhpan on 2017/5/31. 18 | * Description: 自定义圆 19 | */ 20 | 21 | public class CircleView extends View { 22 | private int circleColor; 23 | private int mTextColor; 24 | private int mWidth; 25 | private int mHeight; 26 | private int mRadius; 27 | private String mText; 28 | private float mTextSize; 29 | // 圆心坐标 30 | private float mPieCenterX; 31 | private float mPieCenterY; 32 | private Paint mPaint; 33 | private Rect bounds; 34 | private boolean isConnecting; 35 | 36 | public CircleView(Context context) { 37 | this(context, null); 38 | } 39 | 40 | 41 | public CircleView(Context context, AttributeSet attrs) { 42 | this(context, attrs, 0); 43 | } 44 | 45 | public CircleView(Context context, AttributeSet attrs, int defStyleAttr) { 46 | super(context, attrs, defStyleAttr); 47 | if (attrs != null) { 48 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView); 49 | circleColor = typedArray.getColor(R.styleable.CircleView_circle_color, context.getResources().getColor(R.color.red)); 50 | mTextColor = typedArray.getColor(R.styleable.CircleView_text_color, context.getResources().getColor(R.color.white)); 51 | mTextSize = typedArray.getDimension(R.styleable.CircleView_text_size, LockViewUtils.dp2px(16)); 52 | mText = typedArray.getString(R.styleable.CircleView_text_str); 53 | typedArray.recycle(); 54 | } 55 | init(context); 56 | } 57 | 58 | private void init(Context context) { 59 | mPaint = new Paint(); 60 | mPaint.setStyle(Paint.Style.FILL); 61 | mPaint.setAntiAlias(true); 62 | bounds = new Rect(); 63 | } 64 | 65 | @Override 66 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 67 | super.onSizeChanged(w, h, oldw, oldh); 68 | mHeight = getHeight(); 69 | mWidth = getWidth(); 70 | } 71 | 72 | @Override 73 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 74 | super.onLayout(changed, left, top, right, bottom); 75 | mRadius = Math.min(mHeight, mWidth) / 2 ; 76 | mPieCenterX = mWidth / 2; 77 | mPieCenterY = mHeight / 2; 78 | } 79 | 80 | @Override 81 | protected void onDraw(Canvas canvas) { 82 | super.onDraw(canvas); 83 | mPaint.setColor(circleColor); 84 | canvas.drawCircle(mPieCenterX, mPieCenterY, mRadius, mPaint); 85 | drawText(canvas); 86 | } 87 | 88 | /** 89 | * 画圆中的文字 90 | */ 91 | private void drawText(Canvas canvas) { 92 | if (TextUtils.isEmpty(mText)||isConnecting) return; 93 | mPaint.getTextBounds(mText, 0, mText.length(), bounds); 94 | mPaint.setColor(mTextColor); 95 | mPaint.setTextSize(mTextSize); 96 | mPaint.setTextAlign(Paint.Align.CENTER); 97 | Paint.FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt(); 98 | int baseline = (getMeasuredHeight() - fontMetricsInt.bottom + fontMetricsInt.top) / 2 - fontMetricsInt.top; 99 | canvas.drawText(mText, mPieCenterX, baseline, mPaint); 100 | } 101 | 102 | 103 | 104 | public String getText() { 105 | return mText; 106 | } 107 | 108 | public void setText(String text) { 109 | this.mText = text; 110 | invalidate(); 111 | } 112 | 113 | public int getRadius() { 114 | return mRadius; 115 | } 116 | 117 | public void setRadius(int radius){ 118 | mRadius=radius; 119 | invalidate(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /lockview/src/main/java/com/zhpan/lockview/view/CircleWaveView.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview.view; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | import android.content.Context; 6 | import android.content.res.TypedArray; 7 | import android.graphics.Canvas; 8 | import android.graphics.Paint; 9 | import android.graphics.Rect; 10 | import android.support.annotation.ColorRes; 11 | import android.text.TextUtils; 12 | import android.util.AttributeSet; 13 | import android.view.View; 14 | import android.widget.Scroller; 15 | 16 | import com.zhpan.lockview.R; 17 | import com.zhpan.lockview.utils.LockViewUtils; 18 | 19 | 20 | /** 21 | * Created by zhpan on 2018/5/26. 22 | * Description: 自定义圆 23 | */ 24 | 25 | public class CircleWaveView extends View { 26 | private int circleColor; 27 | private int mTextColor; 28 | private int mWidth; 29 | private int mHeight; 30 | private String mText = "未知状态"; 31 | private float mTextSize; 32 | private Scroller mScroller; 33 | // 圆心坐标 34 | private float mPieCenterX; 35 | private float mPieCenterY; 36 | private Paint mPaint; 37 | private Paint mPaintText; 38 | private Rect bounds; 39 | 40 | private boolean isLock = true; 41 | private ValueAnimator animator; 42 | private int waveDelta; 43 | private int transformDelta; 44 | private boolean transforming; 45 | private Context mContext; 46 | private boolean isLockPrepared; 47 | private boolean isUnLockPrePared; 48 | private boolean isBluetoothConnect; 49 | private boolean isConnecting; 50 | private int radius; 51 | // private Bitmap arrowUp; 52 | // private Bitmap arrowDown; 53 | private int dp13; 54 | private boolean isNoNetData; 55 | 56 | private String mConnectStatus; 57 | 58 | public CircleWaveView(Context context) { 59 | this(context, null); 60 | } 61 | 62 | 63 | public CircleWaveView(Context context, AttributeSet attrs) { 64 | this(context, attrs, 0); 65 | } 66 | 67 | public CircleWaveView(Context context, AttributeSet attrs, int defStyleAttr) { 68 | super(context, attrs, defStyleAttr); 69 | if (attrs != null) { 70 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleWaveView); 71 | circleColor = typedArray.getColor(R.styleable.CircleWaveView_wave_color, context.getResources().getColor(R.color.red)); 72 | mTextColor = typedArray.getColor(R.styleable.CircleWaveView_wave_text_color, context.getResources().getColor(R.color.white)); 73 | mTextSize = typedArray.getDimension(R.styleable.CircleWaveView_wave_text_size, LockViewUtils.dp2px(16)); 74 | mText = typedArray.getString(R.styleable.CircleWaveView_wave_text_str); 75 | typedArray.recycle(); 76 | } 77 | init(context); 78 | } 79 | 80 | private void init(Context context) { 81 | mContext = context; 82 | mPaint = new Paint(); 83 | mPaint.setStyle(Paint.Style.FILL); 84 | mPaint.setAntiAlias(true); 85 | mPaint.setColor(circleColor); 86 | mPaintText = new Paint(); 87 | mPaintText.setColor(mTextColor); 88 | mPaintText.setStyle(Paint.Style.FILL); 89 | mPaintText.setTextAlign(Paint.Align.CENTER); 90 | mPaintText.setAntiAlias(true); 91 | dp13 = LockViewUtils.dp2px(13); 92 | mScroller = new Scroller(context); 93 | bounds = new Rect(); 94 | // arrowUp = BitmapFactory.decodeResource(getResources(), 95 | // R.drawable.arrow_up); 96 | // arrowDown = BitmapFactory.decodeResource(getResources(), 97 | // R.drawable.arrow_down); 98 | } 99 | 100 | @Override 101 | protected void onFinishInflate() { 102 | super.onFinishInflate(); 103 | } 104 | 105 | @Override 106 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 107 | super.onSizeChanged(w, h, oldw, oldh); 108 | mHeight = getHeight(); 109 | mWidth = getWidth(); 110 | } 111 | 112 | @Override 113 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 114 | super.onLayout(changed, left, top, right, bottom); 115 | mPieCenterX = mWidth / 2; 116 | mPieCenterY = mHeight / 2; 117 | } 118 | 119 | @Override 120 | protected void onDraw(Canvas canvas) { 121 | super.onDraw(canvas); 122 | drawCircle(canvas); 123 | drawText(canvas); 124 | // drawTriangle(canvas); 125 | } 126 | 127 | // 绘制圆中两个三角 128 | private void drawTriangle(Canvas canvas) { 129 | // int left = (mWidth - arrowUp.getWidth()) / 2; 130 | // canvas.drawBitmap(arrowUp, left, mHeight / 2 - radius + dp13, mPaint); 131 | // canvas.drawBitmap(arrowDown, left, mHeight / 2 + radius - dp13 - arrowDown.getHeight(), mPaint); 132 | /*int radius = Math.min(mHeight, mWidth) / 2 - Math.min(mHeight, mWidth) / 8; 133 | mPaintTrangel.setStyle(Paint.Style.FILL); 134 | mPaintTrangel.setShadowLayer(4, 0, 3, Color.GRAY); 135 | // 三角形顶点到圆边的距离 136 | int h0 = DensityUtils.dp2px(mContext, 10); 137 | // 三角形高 138 | int h1 = DensityUtils.dp2px(mContext, 12); 139 | // 三角形底边长 140 | int w = DensityUtils.dp2px(mContext, 14); 141 | mPaintTrangel.setColor(getResources().getColor(R.color.transparent_33)); 142 | mPath.moveTo(mWidth / 2, mHeight / 2 - (radius - h0)); 143 | mPath.lineTo(mWidth / 2 - w, mHeight / 2 - (radius - h1 - h0)); 144 | mPath.lineTo(mWidth / 2 + w, mHeight / 2 - (radius - h1 - h0)); 145 | canvas.drawPath(mPath, mPaintTrangel); 146 | mPaintTrangel.setShadowLayer(4, 0, -3, Color.GRAY); 147 | mPath.moveTo(mWidth / 2, mHeight / 2 + (radius - h0)); 148 | mPath.lineTo(mWidth / 2 - w, mHeight / 2 + (radius - h1 - h0)); 149 | mPath.lineTo(mWidth / 2 + w, mHeight / 2 + (radius - h1 - h0)); 150 | canvas.drawPath(mPath, mPaintTrangel);*/ 151 | } 152 | 153 | // 绘制圆 154 | private void drawCircle(Canvas canvas) { 155 | mPaint.setColor(circleColor); 156 | int verticalCenter = getHeight() / 2; 157 | int horizontalCenter = getWidth() / 2; 158 | int mRadius = Math.min(verticalCenter, horizontalCenter) - Math.min(verticalCenter, horizontalCenter) / 5; 159 | radius = Math.min(verticalCenter, horizontalCenter) - Math.min(verticalCenter, horizontalCenter) / 5; 160 | if (transforming) { 161 | mPaint.setColor(getResources().getColor(R.color.green)); 162 | canvas.drawCircle(mPieCenterX, mPieCenterY, mRadius, mPaint); 163 | mRadius = isLock ? transformDelta : mRadius - transformDelta; 164 | mPaint.setColor(getResources().getColor(R.color.red)); 165 | canvas.drawCircle(mPieCenterX, mPieCenterY, mRadius, mPaint); 166 | } else { 167 | mRadius = mRadius - waveDelta; 168 | if (!isBluetoothConnect) { 169 | if (isNoNetData) 170 | mPaint.setColor(getColor(R.color.gray)); 171 | else 172 | mPaint.setColor(isLock ? getColor(R.color.redLight) : getColor(R.color.greenLight)); 173 | } else { 174 | if (isLockPrepared) { 175 | mPaint.setColor(getColor(R.color.redDark)); 176 | } else if (isUnLockPrePared) { 177 | mPaint.setColor(getColor(R.color.greenDark)); 178 | } else { 179 | mPaint.setColor(isLock ? getColor(R.color.red) : getColor(R.color.green)); 180 | } 181 | } 182 | canvas.drawCircle(mPieCenterX, mPieCenterY, mRadius, mPaint); 183 | } 184 | } 185 | 186 | /** 187 | * 画圆中的文字 188 | */ 189 | private void drawText(Canvas canvas) { 190 | if (isConnecting) return; 191 | if (TextUtils.isEmpty(mText)) { 192 | String text = mContext.getResources().getString(R.string.ble_not_connect); 193 | drawCenterText(canvas, text); 194 | return; 195 | } 196 | if (isBluetoothConnect) { 197 | drawCenterText(canvas, mText); 198 | } else if (isNoNetData) { 199 | drawCenterText(canvas, mText); 200 | } else { 201 | if (TextUtils.isEmpty(mConnectStatus)) 202 | mConnectStatus = mContext.getResources().getString(R.string.ble_not_connect); 203 | mPaintText.getTextBounds(mConnectStatus, 0, mConnectStatus.length(), bounds); 204 | mPaintText.setTextSize(mTextSize); 205 | Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt(); 206 | int baseline = (getMeasuredHeight() - fontMetricsInt.bottom + fontMetricsInt.top) / 2 - fontMetricsInt.top; 207 | canvas.drawText(mText, mPieCenterX, baseline - 30, mPaintText); 208 | mPaintText.setTextSize(LockViewUtils.dp2px(12)); 209 | canvas.drawText(mConnectStatus, mPieCenterX, baseline + 30, mPaintText); 210 | } 211 | } 212 | 213 | // 绘制中心文字 214 | private void drawCenterText(Canvas canvas, String text) { 215 | mPaintText.setTextSize(mTextSize); 216 | mPaintText.getTextBounds(text, 0, text.length(), bounds); 217 | Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt(); 218 | int baseline = (getMeasuredHeight() - fontMetricsInt.bottom + fontMetricsInt.top) / 2 - fontMetricsInt.top; 219 | canvas.drawText(text, mPieCenterX, baseline, mPaintText); 220 | } 221 | 222 | public void startWave() { 223 | if (animator != null && animator.isRunning()) 224 | animator.end(); 225 | animator = ValueAnimator.ofFloat(0f, 1f, 0f); 226 | animator.setRepeatCount(ValueAnimator.INFINITE); 227 | animator.setRepeatMode(ValueAnimator.RESTART); 228 | animator.setDuration(600); 229 | 230 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 231 | @Override 232 | public void onAnimationUpdate(ValueAnimator animation) { 233 | int verticalCenter = getHeight() / 2; 234 | int horizontalCenter = getWidth() / 2; 235 | waveDelta = (int) (Math.min(verticalCenter, horizontalCenter) * (float) animation.getAnimatedValue() / 16); 236 | invalidate(); 237 | } 238 | }); 239 | 240 | animator.start(); 241 | } 242 | 243 | public void stopWave() { 244 | if (animator != null && animator.isRunning()) 245 | animator.end(); 246 | } 247 | 248 | public void changeLockState(final boolean lock) { 249 | stopWave(); 250 | if (this.isLock != lock) { 251 | transforming = true; 252 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 0.99f); 253 | valueAnimator.setDuration(500); 254 | valueAnimator.addListener(new Animator.AnimatorListener() { 255 | @Override 256 | public void onAnimationStart(Animator animation) { 257 | 258 | } 259 | 260 | @Override 261 | public void onAnimationEnd(Animator animation) { 262 | transforming = false; 263 | isLock = lock; 264 | invalidate(); 265 | } 266 | 267 | @Override 268 | public void onAnimationCancel(Animator animation) { 269 | transforming = false; 270 | } 271 | 272 | @Override 273 | public void onAnimationRepeat(Animator animation) { 274 | 275 | } 276 | }); 277 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 278 | @Override 279 | public void onAnimationUpdate(ValueAnimator animation) { 280 | int verticalCenter = getHeight() / 2; 281 | int horizontalCenter = getWidth() / 2; 282 | transformDelta = (int) ((Math.min(verticalCenter, horizontalCenter) - Math.min(verticalCenter, horizontalCenter) / 6) 283 | * (float) animation.getAnimatedValue()); 284 | invalidate(); 285 | } 286 | }); 287 | valueAnimator.start(); 288 | } 289 | } 290 | 291 | public String getConnectStatus() { 292 | return mConnectStatus; 293 | } 294 | 295 | public void setConnectStatus(String connectStatus) { 296 | mConnectStatus = connectStatus; 297 | } 298 | 299 | public int getRadius() { 300 | return radius; 301 | } 302 | 303 | public float getTextSize() { 304 | return mTextSize; 305 | } 306 | 307 | public void setTextSize(float textSize) { 308 | mTextSize = LockViewUtils.dp2px(textSize); 309 | invalidate(); 310 | } 311 | 312 | public void setLock(final boolean lock) { 313 | stopWave(); 314 | isLock = lock; 315 | invalidate(); 316 | } 317 | 318 | public boolean isLock() { 319 | return isLock; 320 | } 321 | 322 | 323 | public String getText() { 324 | return mText; 325 | } 326 | 327 | public void setText(String text) { 328 | this.mText = text; 329 | invalidate(); 330 | } 331 | 332 | public boolean isNoNetData() { 333 | return isNoNetData; 334 | } 335 | 336 | public void setNoNetData(boolean noNetData) { 337 | isNoNetData = noNetData; 338 | invalidate(); 339 | } 340 | 341 | public void setNoNetData(boolean noNetData, String text) { 342 | isNoNetData = noNetData; 343 | mText = text; 344 | invalidate(); 345 | } 346 | 347 | public void setCircleColor(int background) { 348 | this.circleColor = background; 349 | invalidate(); 350 | } 351 | 352 | public boolean isBluetoothConnect() { 353 | return isBluetoothConnect; 354 | } 355 | 356 | public void setBluetoothConnect(boolean bluetoothConnect) { 357 | isBluetoothConnect = bluetoothConnect; 358 | invalidate(); 359 | } 360 | 361 | public void smoothScroll(int destX, int destY) { 362 | int scrollY = getScrollY(); 363 | int delta = destY - scrollY; 364 | mScroller.startScroll(destX, scrollY, 0, delta, 400); 365 | invalidate(); 366 | } 367 | 368 | @Override 369 | public void computeScroll() { 370 | if (mScroller.computeScrollOffset()) { 371 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 372 | postInvalidate(); 373 | } 374 | } 375 | 376 | public void setLockPrepared(boolean lockPrepared) { 377 | isLockPrepared = lockPrepared; 378 | invalidate(); 379 | } 380 | 381 | public void setUnLockPrePared(boolean unLockPrePared) { 382 | isUnLockPrePared = unLockPrePared; 383 | invalidate(); 384 | } 385 | 386 | public Scroller getScroller() { 387 | return mScroller; 388 | } 389 | 390 | private int getColor(@ColorRes int color) { 391 | return getResources().getColor(color); 392 | } 393 | 394 | public boolean isConnecting() { 395 | return isConnecting; 396 | } 397 | 398 | public void setConnecting(boolean connecting) { 399 | isConnecting = connecting; 400 | invalidate(); 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /lockview/src/main/res/drawable-xxhdpi/slide_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/lockview/src/main/res/drawable-xxhdpi/slide_lock.png -------------------------------------------------------------------------------- /lockview/src/main/res/drawable-xxhdpi/slide_unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/lockview/src/main/res/drawable-xxhdpi/slide_unlock.png -------------------------------------------------------------------------------- /lockview/src/main/res/drawable-xxxhdpi/slide_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/lockview/src/main/res/drawable-xxxhdpi/slide_lock.png -------------------------------------------------------------------------------- /lockview/src/main/res/drawable-xxxhdpi/slide_unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/lockview/src/main/res/drawable-xxxhdpi/slide_unlock.png -------------------------------------------------------------------------------- /lockview/src/main/res/drawable/slide_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/lockview/src/main/res/drawable/slide_lock.png -------------------------------------------------------------------------------- /lockview/src/main/res/drawable/slide_unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhpanvip/LockView/cc9c4e19b3585d92492d43499a362bf9512b5ea2/lockview/src/main/res/drawable/slide_unlock.png -------------------------------------------------------------------------------- /lockview/src/main/res/layout/layout_oval_lock.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 24 | 25 | 32 | 33 | 40 | 41 | 48 | 49 | 57 | 58 | 64 | 65 | 72 | 78 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /lockview/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 | -------------------------------------------------------------------------------- /lockview/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #F33A3A 8 | #00A34B 9 | #FFFFFF 10 | #9197A0 11 | #F88085 12 | #62C48F 13 | #33ffffff 14 | #00843D 15 | #CE000C 16 | 17 | -------------------------------------------------------------------------------- /lockview/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | -130dp 3 | -110dp 4 | -60dp 5 | -30dp 6 | -20dp 7 | -12dp 8 | -10dp 9 | -8dp 10 | -5dp 11 | -2dp 12 | -1dp 13 | 0dp 14 | 0.1dp 15 | 0.5dp 16 | 1dp 17 | 1.5dp 18 | 2dp 19 | 2.5dp 20 | 3dp 21 | 4dp 22 | 4.50dp 23 | 5dp 24 | 6dp 25 | 7dp 26 | 7.5dp 27 | 8dp 28 | 9dp 29 | 10dp 30 | 11dp 31 | 12dp 32 | 13dp 33 | 14dp 34 | 15dp 35 | 16dp 36 | 17dp 37 | 18dp 38 | 19dp 39 | 20dp 40 | 21dp 41 | 22dp 42 | 23dp 43 | 24dp 44 | 25dp 45 | 26dp 46 | 27dp 47 | 28dp 48 | 29dp 49 | 30dp 50 | 31dp 51 | 32dp 52 | 33dp 53 | 34dp 54 | 35dp 55 | 36dp 56 | 37dp 57 | 38dp 58 | 39dp 59 | 40dp 60 | 41dp 61 | 42dp 62 | 43dp 63 | 44dp 64 | 45dp 65 | 46dp 66 | 47dp 67 | 48dp 68 | 49dp 69 | 50dp 70 | 51dp 71 | 52dp 72 | 53dp 73 | 54dp 74 | 55dp 75 | 56dp 76 | 57dp 77 | 58dp 78 | 59dp 79 | 60dp 80 | 61dp 81 | 62dp 82 | 63dp 83 | 64dp 84 | 65dp 85 | 66dp 86 | 67dp 87 | 68dp 88 | 69dp 89 | 70dp 90 | 71dp 91 | 72dp 92 | 73dp 93 | 74dp 94 | 75dp 95 | 76dp 96 | 77dp 97 | 78dp 98 | 79dp 99 | 80dp 100 | 81dp 101 | 82dp 102 | 83dp 103 | 84dp 104 | 85dp 105 | 86dp 106 | 87dp 107 | 88dp 108 | 89dp 109 | 90dp 110 | 91dp 111 | 92dp 112 | 93dp 113 | 94dp 114 | 95dp 115 | 96dp 116 | 97dp 117 | 98dp 118 | 99dp 119 | 100dp 120 | 101dp 121 | 102dp 122 | 103dp 123 | 104dp 124 | 104.5dp 125 | 105dp 126 | 106dp 127 | 107dp 128 | 108dp 129 | 109dp 130 | 110dp 131 | 111dp 132 | 112dp 133 | 113dp 134 | 114dp 135 | 115dp 136 | 116dp 137 | 117dp 138 | 118dp 139 | 119dp 140 | 120dp 141 | 121dp 142 | 122dp 143 | 123dp 144 | 124dp 145 | 125dp 146 | 126dp 147 | 127dp 148 | 128dp 149 | 129dp 150 | 130dp 151 | 131dp 152 | 132dp 153 | 133dp 154 | 134dp 155 | 134.5dp 156 | 135dp 157 | 136dp 158 | 137dp 159 | 138dp 160 | 139dp 161 | 140dp 162 | 141dp 163 | 142dp 164 | 143dp 165 | 144dp 166 | 145dp 167 | 146dp 168 | 147dp 169 | 148dp 170 | 149dp 171 | 150dp 172 | 151dp 173 | 152dp 174 | 153dp 175 | 154dp 176 | 155dp 177 | 156dp 178 | 157dp 179 | 158dp 180 | 159dp 181 | 160dp 182 | 161dp 183 | 162dp 184 | 163dp 185 | 164dp 186 | 165dp 187 | 166dp 188 | 167dp 189 | 168dp 190 | 169dp 191 | 170dp 192 | 171dp 193 | 172dp 194 | 173dp 195 | 174dp 196 | 175dp 197 | 176dp 198 | 177dp 199 | 178dp 200 | 179dp 201 | 180dp 202 | 181dp 203 | 182dp 204 | 183dp 205 | 184dp 206 | 185dp 207 | 186dp 208 | 187dp 209 | 188dp 210 | 189dp 211 | 190dp 212 | 191dp 213 | 192dp 214 | 193dp 215 | 194dp 216 | 195dp 217 | 196dp 218 | 197dp 219 | 198dp 220 | 199dp 221 | 200dp 222 | 201dp 223 | 202dp 224 | 203dp 225 | 204dp 226 | 205dp 227 | 206dp 228 | 207dp 229 | 208dp 230 | 209dp 231 | 210dp 232 | 211dp 233 | 212dp 234 | 213dp 235 | 214dp 236 | 215dp 237 | 216dp 238 | 217dp 239 | 218dp 240 | 219dp 241 | 220dp 242 | 221dp 243 | 222dp 244 | 223dp 245 | 224dp 246 | 225dp 247 | 226dp 248 | 227dp 249 | 228dp 250 | 229dp 251 | 230dp 252 | 231dp 253 | 232dp 254 | 233dp 255 | 234dp 256 | 235dp 257 | 236dp 258 | 237dp 259 | 238dp 260 | 239dp 261 | 240dp 262 | 241dp 263 | 242dp 264 | 243dp 265 | 244dp 266 | 245dp 267 | 246dp 268 | 247dp 269 | 248dp 270 | 249dp 271 | 250dp 272 | 251dp 273 | 252dp 274 | 253dp 275 | 254dp 276 | 255dp 277 | 256dp 278 | 257dp 279 | 258dp 280 | 259dp 281 | 260dp 282 | 261dp 283 | 262dp 284 | 263dp 285 | 264dp 286 | 265dp 287 | 266dp 288 | 267dp 289 | 268dp 290 | 269dp 291 | 270dp 292 | 271dp 293 | 272dp 294 | 273dp 295 | 274dp 296 | 275dp 297 | 276dp 298 | 277dp 299 | 278dp 300 | 279dp 301 | 280dp 302 | 281dp 303 | 282dp 304 | 283dp 305 | 284dp 306 | 285dp 307 | 286dp 308 | 287dp 309 | 289dp 310 | 290dp 311 | 291dp 312 | 292dp 313 | 293dp 314 | 294dp 315 | 295dp 316 | 296dp 317 | 297dp 318 | 298dp 319 | 299dp 320 | 300dp 321 | 301dp 322 | 302dp 323 | 303dp 324 | 304dp 325 | 305dp 326 | 306dp 327 | 307dp 328 | 308dp 329 | 309dp 330 | 310dp 331 | 311dp 332 | 312dp 333 | 313dp 334 | 314dp 335 | 315dp 336 | 316dp 337 | 317dp 338 | 318dp 339 | 319dp 340 | 320dp 341 | 321dp 342 | 322dp 343 | 323dp 344 | 324dp 345 | 325dp 346 | 326dp 347 | 327dp 348 | 328dp 349 | 329dp 350 | 330dp 351 | 331dp 352 | 332dp 353 | 333dp 354 | 334dp 355 | 335dp 356 | 336dp 357 | 337dp 358 | 338dp 359 | 339dp 360 | 340dp 361 | 341dp 362 | 342dp 363 | 343dp 364 | 344dp 365 | 345dp 366 | 346dp 367 | 347dp 368 | 348dp 369 | 349dp 370 | 350dp 371 | 351dp 372 | 352dp 373 | 353dp 374 | 354dp 375 | 355dp 376 | 356dp 377 | 357dp 378 | 358dp 379 | 359dp 380 | 360dp 381 | 365dp 382 | 370dp 383 | 400dp 384 | 410dp 385 | 422dp 386 | 472dp 387 | 500dp 388 | 600dp 389 | 640dp 390 | 720dp 391 | 392 | 393 | 6sp 394 | 7sp 395 | 8sp 396 | 9sp 397 | 10sp 398 | 11sp 399 | 12sp 400 | 13sp 401 | 14sp 402 | 15sp 403 | 16sp 404 | 17sp 405 | 18sp 406 | 19sp 407 | 20sp 408 | 21sp 409 | 22sp 410 | 23sp 411 | 24sp 412 | 25sp 413 | 26sp 414 | 27sp 415 | 28sp 416 | 30sp 417 | 31sp 418 | 32sp 419 | 33sp 420 | 34sp 421 | 35sp 422 | 36sp 423 | 38sp 424 | 40sp 425 | 42sp 426 | 48sp 427 | 428 | -------------------------------------------------------------------------------- /lockview/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LockView 3 | 设备未连接 4 | 连接中 5 | 6 | -------------------------------------------------------------------------------- /lockview/src/test/java/com/zhpan/lockview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zhpan.lockview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':lockview' 2 | --------------------------------------------------------------------------------