├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── attrs.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── asdf
│ │ │ └── myapplication
│ │ │ ├── MainActivity.java
│ │ │ └── scaning
│ │ │ ├── CalibrationView.java
│ │ │ ├── OutCircleView.java
│ │ │ ├── InnerCircleView.java
│ │ │ ├── GradientCircleView.java
│ │ │ └── ScanView.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── asdf
│ │ │ └── myapplication
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── asdf
│ │ └── myapplication
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── 1.png
├── 2.png
├── 3.png
├── 扫描动画
├── .idea
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── 2017-04-01_14_15_52.mp4_1491027949.gif
├── README.md
├── .gitignore
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/1.png
--------------------------------------------------------------------------------
/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/2.png
--------------------------------------------------------------------------------
/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/3.png
--------------------------------------------------------------------------------
/扫描动画:
--------------------------------------------------------------------------------
1 | # Zxing-Scan-Anim
2 | Zxing Scan Anim 一个扫描动画,用于学习动画和view
3 | 一个view
4 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Zxing_Scan_Anim
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/2017-04-01_14_15_52.mp4_1491027949.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/2017-04-01_14_15_52.mp4_1491027949.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youxin11544/Zxing-Scan-Anim/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 09 10:30:57 CST 2016
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/asdf/myapplication/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication;
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() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 二维码扫描用 扫描动画
2 | 还是一句话思路很重要,对自定义view,以及动画有个一定认识,不要的可以提出来共同进步
3 | # xml布局的配置
4 | 
5 | # 各种属性,不够的自己添加
6 | 
7 | # 还有一些属性没有下载attrs中,直接在view中去改,有需要的自己写attrs
8 | 
9 | # 整体动画效果
10 | 
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #bab30b
4 | #303F9F
5 |
6 |
7 | #4Dbab30b
8 |
9 | #000000
10 | #E6000000
11 | #B3000000
12 | #80000000
13 | #66000000
14 | #4D000000
15 | #33000000
16 | #00000000
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/libraries
2 | .DS_Store
3 |
4 | # Built application files
5 | *.apk
6 | *.ap_
7 |
8 | # Files for the ART/Dalvik VM
9 | *.dex
10 |
11 | # Java class files
12 | *.class
13 |
14 | # Generated files
15 | bin/
16 | gen/
17 | out/
18 |
19 | # Gradle files
20 | .gradle/
21 | build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | # Intellij
39 | *.iml
40 | .idea/workspace.xml
41 |
42 | # Keystore files
43 | *.jks
44 |
45 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/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 C:\Android_studio\android-sdk-windows/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/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/asdf/myapplication/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication;
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 | * Instrumentation 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() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.asdf.myapplication", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.0"
6 | defaultConfig {
7 | applicationId "com.asdf.myapplication"
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.0.0'
28 | testCompile 'junit:junit:4.12'
29 | }
30 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 1.8
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/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 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/asdf/myapplication/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication;
2 |
3 | import android.animation.Animator;
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.asdf.myapplication.scaning.ScanView;
10 |
11 | public class MainActivity extends AppCompatActivity {
12 | private ScanView scanView;
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 | scanView = (ScanView) findViewById(R.id.scanview);
18 | findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
19 | @Override
20 | public void onClick(View v) {
21 | scanView.startScanAnim();
22 | }
23 | });
24 | findViewById(R.id.scaning).setOnClickListener(new View.OnClickListener() {
25 | @Override
26 | public void onClick(View v) {
27 | scanView.startScanMatchingAnim();
28 | }
29 | });
30 | findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View v) {
33 | scanView.startScanEndAnim(new Animator.AnimatorListener() {
34 | @Override
35 | public void onAnimationStart(Animator animation) {
36 | Toast.makeText(MainActivity.this,"结束动画开始",Toast.LENGTH_LONG).show();
37 | }
38 |
39 | @Override
40 | public void onAnimationEnd(Animator animation) {
41 | Toast.makeText(MainActivity.this,"结束动画结束",Toast.LENGTH_LONG).show();
42 | }
43 |
44 | @Override
45 | public void onAnimationCancel(Animator animation) {
46 |
47 | }
48 |
49 | @Override
50 | public void onAnimationRepeat(Animator animation) {
51 |
52 | }
53 | });
54 | }
55 | });
56 | findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | scanView.resetView();
60 | }
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/asdf/myapplication/scaning/CalibrationView.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication.scaning;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.util.AttributeSet;
7 | import android.util.TypedValue;
8 | import android.view.View;
9 |
10 | /**
11 | * 刻度尺 view
12 | */
13 | public class CalibrationView extends View {
14 | private Context mContext;
15 | int mWidth;
16 | int mHeight;
17 | private int line_color = 0xFF9faba1;//线的颜色
18 | private float width_longer = 2f;//长刻度宽度
19 | private float width_shorter = 2f;//短刻度宽度
20 | private float length_longer = 50;//长刻度长度
21 | private float length_shorter = 30;//短刻度长度
22 | private float radius_size = 200;//整个圆弧的半径
23 | private int calibrationLineCount = 90;//圆圈数量
24 | public float getRadius_size() {
25 | return radius_size;
26 | }
27 |
28 | public void setRadius_size(float radius_size) {
29 | this.radius_size = radius_size;
30 | invalidate();
31 | }
32 | public CalibrationView(Context context) {
33 | this(context, null, 0);
34 | }
35 | public CalibrationView(Context context, AttributeSet attrs) {
36 | this(context, attrs, 0);
37 | }
38 | public CalibrationView(Context context, AttributeSet attrs, int defStyleAttr) {
39 | super(context, attrs, defStyleAttr);
40 | mContext = context;
41 | length_longer = dp2px(context, 8f);
42 | length_shorter = dp2px(context, 5f);
43 | }
44 | @Override
45 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
46 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
47 | mHeight = mWidth = Math.min(getMeasuredWidth(), getMeasuredWidth());
48 | // radius_size = mHeight/2-length_longer;//相当于默认从 view的顶部开始
49 | // 高度和宽度一样
50 | heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY);
51 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
52 | }
53 | @Override
54 | protected void onDraw(Canvas canvas) {
55 | // 获取宽高参数
56 | mHeight = mWidth = Math.min(getWidth(), getHeight());
57 | drawCalibration(canvas);
58 | }
59 | private void drawCalibration(Canvas canvas) {
60 | // 画刻度
61 | Paint painDegree = new Paint();
62 | painDegree.setColor(line_color);
63 | painDegree.setAntiAlias(true);
64 | for (int i = 0; i < calibrationLineCount; i++) {
65 | float startY = 0;
66 | if (i % (calibrationLineCount/3) == 0) {
67 | painDegree.setStrokeWidth(width_longer);
68 | startY = mHeight/2- radius_size-length_longer;
69 | } else {
70 | painDegree.setStrokeWidth(width_shorter);
71 | startY = mHeight/2- radius_size - length_shorter;
72 | }
73 | float startX = mWidth / 2;
74 | float stopX = mWidth / 2;
75 | float stopY = mHeight/2- radius_size;
76 | canvas.drawLine(startX, startY, stopX, stopY, painDegree);
77 | canvas.rotate(360 / calibrationLineCount, mWidth / 2, mHeight / 2);
78 | }
79 | }
80 | /**
81 | * dp转px
82 | */
83 | public int dp2px(Context context, float dpVal){
84 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
85 | dpVal, context.getResources().getDisplayMetrics());
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
16 |
22 |
23 |
27 |
28 |
31 |
32 |
35 |
36 |
39 |
40 |
43 |
44 |
53 |
54 |
55 |
59 |
60 |
68 |
69 |
76 |
77 |
84 |
85 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/asdf/myapplication/scaning/OutCircleView.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication.scaning;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.RectF;
8 | import android.util.AttributeSet;
9 | import android.util.TypedValue;
10 | import android.view.View;
11 |
12 | /**
13 | * 外圈 view
14 | */
15 |
16 | public class OutCircleView extends View {
17 | private Context mContext;
18 | int mWidth;
19 | int mHeight;
20 | private float line_width = 2f;//线宽
21 | private int line_color = 0xFFb1bdaf;//线的颜色
22 | private int triangle_color = 0xFFb1bdaf;//线的颜色
23 | private float triangle_width = 12.0f;//等边三角形的边宽
24 | private float round_circle_radius_size = 3;//原点的大小
25 | private float radius_size = 200;//整个圆弧的半径
26 |
27 | public float getRadius_size() {
28 | return radius_size;
29 | }
30 |
31 | public void setRadius_size(float radius_size) {
32 | this.radius_size = radius_size;
33 | invalidate();
34 | }
35 |
36 | public OutCircleView(Context context) {
37 | this(context, null, 0);
38 | }
39 | public OutCircleView(Context context, AttributeSet attrs) {
40 | this(context, attrs, 0);
41 | }
42 | public OutCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | mContext = context;
45 | }
46 | @Override
47 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
48 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
49 | // Children are just made to fill our space.
50 | mHeight = mWidth = Math.min(getMeasuredWidth(), getMeasuredWidth());
51 | // radius_size= (mHeight/2)-round_circle_radius_size-2;//默认的圆比view一样大
52 | // 高度和宽度一样
53 | heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY);
54 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
55 |
56 | }
57 | @Override
58 | protected void onDraw(Canvas canvas) {
59 | // 获取宽高参数
60 | mHeight = mWidth = Math.min(getWidth(), getHeight());
61 | for (int i = 0; i < 3; i++) {
62 | drawTriangle(canvas);
63 | canvas.rotate(360/3, mWidth / 2, mHeight / 2);
64 | }
65 | }
66 |
67 | /**画圆弧 画三角形*/
68 | private void drawTriangle(Canvas canvas) {
69 | //***********配置画笔*************/
70 | Paint paint = new Paint(); //采用默认设置创建一个画笔
71 | paint.setAntiAlias(true);//使用抗锯齿功能
72 | paint.setColor(line_color); //设置画笔的颜色为绿色
73 | paint.setStyle(Paint.Style.STROKE);//设置画笔类型为STROKE类型(
74 | paint.setStrokeWidth(line_width);
75 | float cx = mWidth / 2;
76 | float cy = (mWidth / 2)-radius_size;
77 | canvas.drawCircle(cx, cy , round_circle_radius_size, paint);
78 | /***********绘制圆弧*************/
79 | RectF rectf_head = new RectF(
80 | cy * 1,
81 | cy * 1,
82 | getMeasuredWidth() - cy * 1,
83 | getMeasuredHeight() - cy * 1);//确定外切矩形范围
84 | canvas.drawArc(rectf_head, -90, 60, false, paint);//绘制圆弧,不含圆心
85 | canvas.rotate(60, mWidth / 2, mHeight / 2);
86 | canvas.drawCircle(cx, cy , round_circle_radius_size, paint);
87 | canvas.rotate(30, mWidth / 2, mHeight / 2);
88 | Paint p = new Paint();
89 | p.setColor(triangle_color);
90 | Path path = new Path();
91 | float x1 = (mWidth / 2);
92 | float y1 = (float) ((triangle_width/2.0f)*Math.sqrt(3)) + ( (mWidth / 2)-radius_size ) ;
93 | float x2 = (mWidth / 2) + (triangle_width/2.0f);
94 | float y2 = 0 + ( (mWidth / 2)-radius_size ) ;
95 | float x3 = (mWidth / 2) - (triangle_width/2.0f);
96 | float y3 = + ( (mWidth / 2)-radius_size ) ;
97 | path.moveTo(x1,y1);// 此点为多边形的起点
98 | path.lineTo(x2,y2);
99 | path.lineTo(x3,y3);
100 | path.close(); // 使这些点构成封闭的多边形
101 | canvas.drawPath(path, p);
102 | canvas.rotate(-90, mWidth / 2, mHeight / 2);
103 | }
104 | /**
105 | * dp转px
106 | */
107 | public int dp2px(Context context, float dpVal){
108 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
109 | dpVal, context.getResources().getDisplayMetrics());
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/java/com/asdf/myapplication/scaning/InnerCircleView.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication.scaning;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Paint;
8 | import android.graphics.PorterDuff;
9 | import android.graphics.PorterDuffXfermode;
10 | import android.graphics.RectF;
11 | import android.util.AttributeSet;
12 | import android.view.View;
13 | import android.view.animation.LinearInterpolator;
14 |
15 | public class InnerCircleView extends View {
16 | Paint mPaint;
17 | Context mContext;
18 | int rectColor = 0x66bab30b;
19 | int circleColor = 0xFFbab30b;//这个颜色暂时没用
20 | int mWith;
21 | int mHeight;
22 | private float radius_size = 200;//整个圆弧的半径
23 | private float rect_width = 2*radius_size;//截取矩形的宽度
24 | private float rect_height = 25;//截取矩形的高度
25 | int bitmap_width = (int) (2*radius_size);//画布大小
26 | int bitmap_height = (int) (2*radius_size);
27 | private float rect_offset = 0;//截取矩形的偏移量
28 | public float getRadius_size() {
29 | return radius_size;
30 | }
31 |
32 | public void setRadius_size(float radius_size) {
33 | this.radius_size = radius_size;
34 | invalidate();
35 | }
36 | public InnerCircleView(Context context) {
37 | super(context);
38 | init(context);
39 | }
40 |
41 | public InnerCircleView(Context context, AttributeSet attrs) {
42 | super(context, attrs);
43 | init(context);
44 | }
45 |
46 | public InnerCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
47 | super(context, attrs, defStyleAttr);
48 | init(context);
49 | }
50 | @Override
51 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
52 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
53 | mWith = mHeight = Math.min(getMeasuredWidth(), getMeasuredWidth());
54 | // radius_size = mHeight/2-length_longer;//相当于默认从 view的顶部开始
55 | // 高度和宽度一样
56 | heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWith, MeasureSpec.EXACTLY);
57 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
58 | }
59 |
60 |
61 | private void init(Context context) {
62 | mContext = context;
63 | mPaint = new Paint();
64 | mPaint.setStyle(Paint.Style.FILL);
65 | mPaint.setAntiAlias(true);
66 | initTransitionAnimation();
67 |
68 | }
69 |
70 | private Bitmap drawRectBm() {
71 | // int a = 0xFFbab30b;
72 | // int b = 0x4D000000;
73 | //参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点,最后参数为平铺方式,这里设置为镜像.
74 | // LinearGradient lg=new LinearGradient(
75 | // 0,
76 | // (bitmap_height-rect_height)/2+rect_offset,
77 | // 0,
78 | // bitmap_height/2+rect_height/2+rect_offset,
79 | // a,
80 | // b,
81 | // Shader.TileMode.CLAMP);
82 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
83 | paint.setStyle(Paint.Style.FILL);
84 | paint.setAntiAlias(true);
85 | paint.setColor(rectColor);
86 | // paint.setShader(lg);
87 | Bitmap bm = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
88 | Canvas cavas = new Canvas(bm);
89 | cavas.drawRect(
90 | new RectF(
91 | 0,
92 | (bitmap_height-rect_height)/2+rect_offset,
93 | rect_width,
94 | bitmap_height/2+rect_height/2+rect_offset),
95 | paint);
96 | return bm;
97 | }
98 |
99 | private Bitmap drawCircleBm() {
100 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
101 | paint.setColor(circleColor);
102 | paint.setStyle(Paint.Style.FILL);
103 | paint.setAntiAlias(true);
104 | Bitmap bm = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
105 | Canvas cavas = new Canvas(bm);
106 | cavas.drawCircle(bitmap_width/2, bitmap_height/2, radius_size, paint);
107 | return bm;
108 | }
109 |
110 | @Override
111 | protected void onDraw(Canvas canvas) {
112 | int sc = canvas.saveLayer(0, 0, mWith, mHeight, null, Canvas.MATRIX_SAVE_FLAG |
113 | Canvas.CLIP_SAVE_FLAG |
114 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
115 | Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
116 | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
117 | int y = (mWith-bitmap_width)/2;
118 | int x = (mHeight-bitmap_height)/2;
119 | PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN;
120 | mPaint.setXfermode(null);
121 | canvas.drawBitmap(drawCircleBm(), x, y, mPaint);
122 | mPaint.setXfermode(new PorterDuffXfermode(mode));
123 | canvas.drawBitmap(drawRectBm(), x, y, mPaint);
124 | mPaint.setXfermode(null);
125 | // 还原画布
126 | canvas.restoreToCount(sc);
127 | }
128 | private ValueAnimator transitionAnimator;
129 | public void startScanAnim() {
130 | if (transitionAnimator != null) {
131 | if (!transitionAnimator.isRunning()) {
132 | transitionAnimator.start();
133 | }
134 | }
135 |
136 | }
137 |
138 | public void stopScanAnim() {
139 | if (transitionAnimator != null) {
140 | if (transitionAnimator.isRunning()) {
141 | transitionAnimator.cancel();
142 | }
143 | }
144 |
145 | }
146 | private static final long ROTATING_ANIMATION_DURATION = 1500L;//动画1圈时间
147 | /**
148 | * 初始化动画
149 | */
150 | public void initTransitionAnimation() {
151 | transitionAnimator = ValueAnimator.ofFloat(-170,170);
152 | transitionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
153 | @Override
154 | public void onAnimationUpdate(ValueAnimator animation) {
155 | rect_offset = (float) animation.getAnimatedValue();
156 | invalidate();
157 | }
158 | });
159 | transitionAnimator.setDuration(ROTATING_ANIMATION_DURATION);
160 | transitionAnimator.setRepeatMode(ValueAnimator.REVERSE);
161 | transitionAnimator.setRepeatCount(10000);
162 | transitionAnimator.setInterpolator(new LinearInterpolator());
163 | }
164 |
165 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/asdf/myapplication/scaning/GradientCircleView.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication.scaning;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.LinearGradient;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.graphics.Shader;
11 | import android.util.AttributeSet;
12 | import android.util.TypedValue;
13 | import android.view.View;
14 | import android.view.animation.LinearInterpolator;
15 |
16 | /**
17 | * Created by chanwan on 2017/3/20 0020.
18 | */
19 |
20 | public class GradientCircleView extends View {
21 | private Context mContext;
22 | int mWidth;
23 | int mHeight;
24 | private float round_circle_radius_size = 2.5f;//圆圈的半径大小
25 | private float center_circle_radius_size = 200;//中
26 | // 心圆的半径的大小
27 | private ValueAnimator rotateAnimator;
28 | private float rotateAngle;
29 | private static final long ROTATING_ANIMATION_DURATION = 8 * 1000L;//动画1圈时间
30 | float gradient_circle_width = 80;//环形的宽度
31 | /*百分比*/
32 | private int percent = 50;
33 | /*渐变圆周颜色数组*/
34 | private int[] gradientColorArray = new int[]{Color.parseColor("#8002e2ea"),
35 | Color.parseColor("#6602e2ea"),
36 | Color.parseColor("#4D02e2ea"),
37 | Color.parseColor("#3302e2ea"),
38 | Color.parseColor("#00000000")};
39 | private int roundDotCount = 90;//圆圈数量
40 |
41 | public float getCenter_circle_radius_size() {
42 | return center_circle_radius_size;
43 | }
44 |
45 | public void setCenter_circle_radius_size(float center_circle_radius_size) {
46 | this.center_circle_radius_size = center_circle_radius_size;
47 | invalidate();
48 | }
49 |
50 | public GradientCircleView(Context context) {
51 | this(context, null, 0);
52 | }
53 |
54 | public GradientCircleView(Context context, AttributeSet attrs) {
55 | this(context, attrs, 0);
56 | }
57 |
58 | public GradientCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
59 | super(context, attrs, defStyleAttr);
60 | gradient_circle_width = dp2px(context, 12f);
61 | mContext = context;
62 | initRotatingAnimation();
63 | }
64 |
65 | @Override
66 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
67 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
68 | // Children are just made to fill our space.
69 | mHeight = mWidth = Math.min(getMeasuredWidth(), getMeasuredWidth());
70 | // center_circle_radius_size = mHeight / 2 - gradient_circle_width / 2;//相当于默认从 view的顶部开始
71 | // 高度和宽度一样
72 | heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY);
73 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
74 |
75 | }
76 |
77 | @Override
78 | protected void onDraw(Canvas canvas) {
79 | // 获取宽高参数
80 | mHeight = mWidth = Math.min(getWidth(), getHeight());
81 | canvas.save();
82 | canvas.rotate(rotateAngle, mWidth / 2, mHeight / 2);
83 | drawRoundDot(canvas);
84 | canvas.restore();
85 | canvas.save();
86 | canvas.rotate(-rotateAngle, mWidth / 2, mHeight / 2);
87 | drawGradientCircle(canvas);
88 | }
89 |
90 | /**
91 | * 绘制圆点
92 | */
93 | private void drawRoundDot(Canvas canvas) {
94 | Paint paintPointer = new Paint();
95 | paintPointer.setAntiAlias(true);
96 | paintPointer.setStyle(Paint.Style.FILL);
97 | float average = (1.0f) / (roundDotCount * 1.0f);
98 | for (int i = 0; i < roundDotCount; i++) {
99 | // 画圆心 73,172,102
100 | float alphaScale = 0.7f;//渐变系数
101 | float alpha = (i * 1.0f) * average*alphaScale;
102 | int mColor = Color.argb((int) (0 + 255 * alpha), 2, 226, 234);//圆圈颜色 2,226,234
103 | paintPointer.setColor(mColor);
104 | float cx = mWidth / 2;
105 | float cy = (mWidth / 2) - center_circle_radius_size;
106 | canvas.drawCircle(cx, cy, round_circle_radius_size, paintPointer);
107 | canvas.rotate(360 / roundDotCount, mWidth / 2, mHeight / 2);
108 | }
109 | }
110 |
111 | /**
112 | * 绘制颜色渐变圆环
113 | */
114 | private void drawGradientCircle(Canvas canvas) {
115 | Paint gradientCirclePaint = new Paint();
116 | gradientCirclePaint.setStyle(Paint.Style.STROKE);
117 | gradientCirclePaint.setAntiAlias(true);
118 | gradientCirclePaint.setStrokeWidth(gradient_circle_width);
119 |
120 | float circlePadding = (mWidth / 2) - center_circle_radius_size;
121 |
122 | LinearGradient linearGradient = new LinearGradient(
123 | 0,
124 | 0,
125 | 0,
126 | getMeasuredHeight() - circlePadding,
127 | gradientColorArray, null, Shader.TileMode.CLAMP);
128 | gradientCirclePaint.setShader(linearGradient);
129 |
130 | canvas.drawArc(
131 | new RectF(circlePadding * 1,
132 | circlePadding * 1,
133 | getMeasuredWidth() - circlePadding * 1,
134 | getMeasuredHeight() - circlePadding * 1),
135 | -90, (float) (percent / 100.0) * 360, false, gradientCirclePaint);
136 | }
137 |
138 | public void startScanAnim() {
139 | if (rotateAnimator != null) {
140 | if (!rotateAnimator.isRunning()) {
141 | rotateAnimator.start();
142 | }
143 | }
144 |
145 | }
146 |
147 | public void stopScanAnim() {
148 | if (rotateAnimator != null) {
149 | if (rotateAnimator.isRunning()) {
150 | rotateAnimator.cancel();
151 | }
152 | }
153 |
154 | }
155 |
156 | /**
157 | * 初始化动画
158 | */
159 | public void initRotatingAnimation() {
160 | rotateAnimator = ValueAnimator.ofFloat(0.0f, 360f * 1);
161 | rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
162 | @Override
163 | public void onAnimationUpdate(ValueAnimator animation) {
164 | rotateAngle = (float) animation.getAnimatedValue();
165 | invalidate();
166 | }
167 | });
168 | rotateAnimator.setDuration(ROTATING_ANIMATION_DURATION);
169 | rotateAnimator.setRepeatMode(ValueAnimator.RESTART);
170 | rotateAnimator.setRepeatCount(10000);
171 | rotateAnimator.setInterpolator(new LinearInterpolator());
172 | }
173 |
174 | /**
175 | * dp转px
176 | */
177 | public int dp2px(Context context, float dpVal) {
178 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
179 | dpVal, context.getResources().getDisplayMetrics());
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/app/src/main/java/com/asdf/myapplication/scaning/ScanView.java:
--------------------------------------------------------------------------------
1 | package com.asdf.myapplication.scaning;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ObjectAnimator;
6 | import android.animation.ValueAnimator;
7 | import android.content.Context;
8 | import android.content.res.TypedArray;
9 | import android.util.AttributeSet;
10 | import android.util.TypedValue;
11 | import android.view.Gravity;
12 | import android.view.View;
13 | import android.view.animation.AccelerateDecelerateInterpolator;
14 | import android.widget.FrameLayout;
15 |
16 | import com.asdf.myapplication.R;
17 |
18 | /**
19 | * Created by chengwan on 2017/3/20.
20 | */
21 |
22 | public class ScanView extends FrameLayout {
23 | private Context mContext;
24 | private float GradientCircleView_width;
25 | private float CalibrationView_width;
26 | private float CalibrationView_hight;
27 | private float GradientCircleView_hight;
28 | private float OutCircleView_width;
29 | private float OutCircleView_hight;
30 | private CalibrationView mCalibrationView;
31 | private GradientCircleView mGradientCircleView;
32 | private OutCircleView mOutCircleView;
33 | private float CalibrationView_radius_size;
34 | private float GradientCircleView_center_circle_radius_size;
35 | private float OutCircleView_radius_size;
36 | private float InnerCircleView_width;
37 | private float InnerCircleView_hight;
38 | private float InnerCircleView_radius_size;
39 | private InnerCircleView mInnerCircleView;
40 | private AnimatorSet animatorSetEnd;
41 | private AnimatorSet animatorSetMatching;
42 | private AnimatorSet animatorSetStart;
43 |
44 | public ScanView(Context context) {
45 | super(context);
46 | mContext = context;
47 | }
48 |
49 | public ScanView(Context context, AttributeSet attrs) {
50 | super(context, attrs);
51 | mContext = context;
52 | initView(attrs);
53 | }
54 |
55 | public ScanView(Context context, AttributeSet attrs, int defStyleAttr) {
56 | super(context, attrs, defStyleAttr);
57 | mContext = context;
58 | initView(attrs);
59 | }
60 |
61 | private void initView(AttributeSet attrs) {
62 | TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.scanview);
63 | InnerCircleView_width = ta.getDimension(R.styleable.scanview_InnerCircleView_width, -1);
64 | InnerCircleView_hight = ta.getDimension(R.styleable.scanview_InnerCircleView_hight, -1);
65 | InnerCircleView_radius_size = ta.getDimension(R.styleable.scanview_InnerCircleView_radius_size, dp2px(50));
66 |
67 |
68 | CalibrationView_width = ta.getDimension(R.styleable.scanview_CalibrationView_width, -1);
69 | CalibrationView_hight = ta.getDimension(R.styleable.scanview_CalibrationView_hight, -1);
70 | CalibrationView_radius_size = ta.getDimension(R.styleable.scanview_CalibrationView_radius_size, dp2px(51));
71 |
72 | GradientCircleView_width = ta.getDimension(R.styleable.scanview_GradientCircleView_width, -1);
73 | GradientCircleView_hight = ta.getDimension(R.styleable.scanview_GradientCircleView_hight, -1);
74 | GradientCircleView_center_circle_radius_size = ta.getDimension(R.styleable.scanview_GradientCircleView_center_circle_radius_size, dp2px(58.5f));
75 |
76 | OutCircleView_width = ta.getDimension(R.styleable.scanview_OutCircleView_width, -1);
77 | OutCircleView_hight = ta.getDimension(R.styleable.scanview_OutCircleView_hight, -1);
78 | OutCircleView_radius_size = ta.getDimension(R.styleable.scanview_OutCircleView_radius_size, dp2px(65));
79 |
80 | ta.recycle();
81 |
82 | LayoutParams CalibrationView_params = new LayoutParams((int) CalibrationView_width, (int) CalibrationView_hight);
83 | LayoutParams InnerCircleView_params = new LayoutParams((int) InnerCircleView_width, (int) InnerCircleView_hight);
84 | LayoutParams GradientCircleView_params = new LayoutParams((int) GradientCircleView_width, (int) GradientCircleView_hight);
85 | LayoutParams OutCircleView_params = new LayoutParams((int) OutCircleView_width, (int) OutCircleView_hight);
86 |
87 | InnerCircleView_params.gravity = Gravity.CENTER;
88 | CalibrationView_params.gravity = Gravity.CENTER;
89 | GradientCircleView_params.gravity = Gravity.CENTER;
90 | OutCircleView_params.gravity = Gravity.CENTER;
91 |
92 | mInnerCircleView = new InnerCircleView(mContext);
93 | mCalibrationView = new CalibrationView(mContext);
94 | mGradientCircleView = new GradientCircleView(mContext);
95 | mOutCircleView = new OutCircleView(mContext);
96 |
97 |
98 | this.addView(mInnerCircleView, InnerCircleView_params);
99 | this.addView(mCalibrationView, CalibrationView_params);
100 | this.addView(mGradientCircleView, GradientCircleView_params);
101 | this.addView(mOutCircleView, OutCircleView_params);
102 |
103 |
104 | if (InnerCircleView_radius_size != -1) {
105 | mInnerCircleView.setRadius_size(InnerCircleView_radius_size);
106 | }
107 | if (CalibrationView_radius_size != -1) {
108 | mCalibrationView.setRadius_size(CalibrationView_radius_size);
109 | }
110 | if (GradientCircleView_center_circle_radius_size != -1) {
111 | mGradientCircleView.setCenter_circle_radius_size(GradientCircleView_center_circle_radius_size);
112 | }
113 | if (OutCircleView_radius_size != -1) {
114 | mOutCircleView.setRadius_size(OutCircleView_radius_size);
115 | }
116 |
117 | }
118 |
119 | /**
120 | * 开始扫描动画
121 | */
122 | public void startScanAnim() {
123 | startScanAnim(null);
124 | }
125 | public void startScanAnim(Animator.AnimatorListener listener) {
126 | mInnerCircleView.setVisibility(View.VISIBLE);
127 | mInnerCircleView.startScanAnim();
128 | mGradientCircleView.startScanAnim();
129 | animatorSetStart = new AnimatorSet();
130 | //开始是60度左右旋转
131 | animatorSetStart.playTogether(
132 | creatRotatingAnimation(mCalibrationView, 60),
133 | creatRotatingAnimation(mOutCircleView, -60));
134 | animatorSetStart.setDuration(2 * 1000);
135 | if (listener != null) animatorSetStart.addListener(listener);
136 | animatorSetStart.start();
137 | }
138 |
139 | /**
140 | * 匹配中动画
141 | */
142 | public void startScanMatchingAnim() {
143 | startScanMatchingAnim(null);
144 | }
145 | public void startScanMatchingAnim(Animator.AnimatorListener listener) {
146 | mInnerCircleView.stopScanAnim();
147 | mInnerCircleView.setVisibility(View.GONE);
148 | mGradientCircleView.startScanAnim();
149 | animatorSetMatching = new AnimatorSet();
150 | animatorSetMatching.playTogether(
151 | createScalAnimation(mCalibrationView, CalibrationView_radius_size, OutCircleView_radius_size, OutCircleView_radius_size - dp2px(4f)),//放大到外圆大小后缩小
152 | createScalAnimation(mOutCircleView, OutCircleView_radius_size, CalibrationView_radius_size)
153 | );
154 | animatorSetMatching.setDuration(2 * 1000);
155 | if (listener != null) animatorSetMatching.addListener(listener);
156 | animatorSetMatching.start();
157 | }
158 |
159 | /**
160 | * 扫描结束动画
161 | */
162 | public void startScanEndAnim() {
163 | startScanEndAnim(null);
164 | }
165 | public void startScanEndAnim(Animator.AnimatorListener listener) {
166 | mGradientCircleView.startScanAnim();
167 | animatorSetEnd = new AnimatorSet();
168 | animatorSetEnd.playTogether(
169 | createScalAnimation(mGradientCircleView, "center_circle_radius_size", GradientCircleView_center_circle_radius_size, GradientCircleView_center_circle_radius_size / 2),
170 | createScalAnimation(mCalibrationView, CalibrationView_radius_size, getMeasuredHeight() / 2),
171 | createScalAnimation(mOutCircleView, OutCircleView_radius_size, getMeasuredHeight() / 2),
172 | createAlphaAnimation(mGradientCircleView),
173 | createAlphaAnimation(mCalibrationView),
174 | createAlphaAnimation(mOutCircleView)
175 |
176 | );
177 | animatorSetEnd.setDuration(2 * 1000);
178 | if (listener != null) animatorSetEnd.addListener(listener);
179 | animatorSetEnd.start();
180 | }
181 |
182 | public void resetView() {
183 | try {
184 | clearAllAnim();
185 | mInnerCircleView.setRadius_size(InnerCircleView_radius_size);
186 | mCalibrationView.setRadius_size(CalibrationView_radius_size);
187 | mGradientCircleView.setCenter_circle_radius_size(GradientCircleView_center_circle_radius_size);
188 | mOutCircleView.setRadius_size(OutCircleView_radius_size);
189 | mInnerCircleView.setAlpha(1);
190 | mCalibrationView.setAlpha(1);
191 | mGradientCircleView.setAlpha(1);
192 | mOutCircleView.setAlpha(1);
193 | } catch (Exception e) {
194 | e.printStackTrace();
195 | }
196 | }
197 |
198 | /**
199 | * 清除所有动画
200 | */
201 | public void clearAllAnim() {
202 | try {
203 | mInnerCircleView.stopScanAnim();
204 | mGradientCircleView.stopScanAnim();
205 | if (animatorSetEnd != null) animatorSetEnd.cancel();
206 | if (animatorSetMatching != null) animatorSetMatching.cancel();
207 | if (animatorSetStart != null) animatorSetStart.cancel();
208 | } catch (Exception e) {
209 | e.printStackTrace();
210 | }
211 | }
212 |
213 | public ObjectAnimator creatRotatingAnimation(View view, float values) {
214 | ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(view, "rotation", 0F, values);//360度旋转
215 | rotateAnimator.setRepeatMode(ValueAnimator.REVERSE);
216 | rotateAnimator.setRepeatCount(1000);
217 | rotateAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
218 | return rotateAnimator;
219 | }
220 |
221 | public ObjectAnimator createScalAnimation(View view, String propertyName, float... values) {
222 | ObjectAnimator mObjectAnimator = ObjectAnimator.ofFloat(view, propertyName, values);
223 | mObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
224 | return mObjectAnimator;
225 | }
226 |
227 | public ObjectAnimator createAlphaAnimation(View view) {
228 | ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1, 0);
229 | animator.setInterpolator(new AccelerateDecelerateInterpolator());
230 | return animator;
231 | }
232 |
233 | public ObjectAnimator createScalAnimation(View view, float... values) {
234 | return createScalAnimation(view, "radius_size", values);
235 | }
236 |
237 | /**
238 | * dp转px
239 | */
240 | public int dp2px(float dpVal) {
241 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
242 | dpVal, mContext.getResources().getDisplayMetrics());
243 | }
244 | }
245 |
--------------------------------------------------------------------------------