├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable-xxhdpi
│ │ │ └── bg.png
│ │ ├── 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
│ │ ├── drawable
│ │ │ ├── icon_default_rect.9.png
│ │ │ └── ic_launcher_background.xml
│ │ ├── values
│ │ │ ├── styles.xml
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ └── strings.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ └── anomaly_image_header.xml
│ │ └── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── administrator
│ │ └── anomalyimage
│ │ └── MainActivity.java
├── build.gradle
└── proguard-rules.pro
├── library
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ └── values
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── colors.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── library
│ │ ├── proxy
│ │ ├── IShape.java
│ │ ├── ShapeInvocationHandler.java
│ │ └── ShapeProxy.java
│ │ ├── factory
│ │ ├── ShapeFactory.java
│ │ └── DynamicProxyShapeFactory.java
│ │ ├── shape
│ │ ├── BaseShape.java
│ │ ├── QuadrangleShape.java
│ │ └── TriangleShape.java
│ │ └── ShapeImageView.java
├── build.gradle
└── proguard-rules.pro
├── settings.gradle
├── device.gif
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── README.md
├── .idea
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
└── misc.xml
├── android
└── graphics
│ └── drawable
│ └── shapes
│ └── annotations.xml
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------
/device.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/device.gif
--------------------------------------------------------------------------------
/library/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 14dp
3 |
4 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | library
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/drawable-xxhdpi/bg.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_default_rect.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/drawable/icon_default_rect.9.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wochiqingcai/AnomalyImage/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AnomalyImage
2 | Android 基于自定义Shape设置ShapeDrawable实现三角形、四边形、多边形或其他形状的ImageView按钮,具有蒙层点击蒙层消失效果。
3 |
4 | 
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/graphics/drawable/shapes/annotations.xml:
--------------------------------------------------------------------------------
1 |
2 | -
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #aa000000
5 | #ffffff
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Sep 20 17:17: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.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 5dp
4 | 10dp
5 |
6 | 53dp
7 |
8 |
--------------------------------------------------------------------------------
/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/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AnomalyImage
3 |
4 | - 飞行射击
5 | - 体育棋牌
6 | - 休闲益智
7 | - 模拟经营
8 | - 赛车竞速
9 | - 角色冒险
10 | - 动作格斗
11 | - 策略战棋
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | }
29 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.example.administrator.anomalyimage"
7 | minSdkVersion 15
8 | targetSdkVersion 26
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 | compile project(':library')
23 | }
24 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/proxy/IShape.java:
--------------------------------------------------------------------------------
1 | package com.example.library.proxy;
2 |
3 | import android.graphics.Rect;
4 | import android.graphics.drawable.shapes.Shape;
5 |
6 | import com.example.library.shape.TriangleShape;
7 |
8 | /**
9 | * Created by lizw on 2018/9/20.
10 | */
11 |
12 | public interface IShape {
13 | boolean chackIn(float x, float y);
14 | void setText(String text);
15 | String getText();
16 | boolean checkMattePaint();
17 | void setMatte(boolean isMatte);
18 | boolean getMatte();
19 | void setRect(Rect rect);
20 | Shape getShape();
21 | void setTriangleType(TriangleShape.TriangleType triangleType);
22 | void setRotate(boolean rotate, int mDegrees);
23 | void setScale(float scale);
24 | }
25 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/proxy/ShapeInvocationHandler.java:
--------------------------------------------------------------------------------
1 | package com.example.library.proxy;
2 |
3 |
4 |
5 | import java.lang.reflect.InvocationHandler;
6 | import java.lang.reflect.Method;
7 | import java.lang.reflect.Proxy;
8 |
9 | /**
10 | * Created by lizw on 2019/3/14.
11 | */
12 | public class ShapeInvocationHandler implements InvocationHandler {
13 | IShape iShape;
14 | public ShapeInvocationHandler(IShape iShape){
15 | this.iShape=iShape;
16 | }
17 | public IShape getIshapeProxy(){
18 | return (IShape)Proxy.newProxyInstance(iShape.getClass().getClassLoader(), iShape.getClass().getInterfaces(),this);
19 | }
20 | @Override
21 | public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
22 | return method.invoke(iShape,objects);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/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/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/proxy/ShapeProxy.java:
--------------------------------------------------------------------------------
1 | package com.example.library.proxy;
2 |
3 | import android.graphics.Rect;
4 | import android.graphics.drawable.shapes.Shape;
5 |
6 | import com.example.library.shape.BaseShape;
7 | import com.example.library.shape.TriangleShape;
8 |
9 |
10 | /**
11 | * Created by lizw on 2019/2/23.
12 | */
13 | public class ShapeProxy implements IShape {
14 | private IShape iShape;
15 | public void init(BaseShape iShape){
16 | this.iShape=iShape;
17 | }
18 |
19 | @Override
20 | public boolean chackIn(float x, float y) {
21 | return iShape.chackIn(x,y);
22 | }
23 |
24 | @Override
25 | public void setText(String text) {
26 | iShape.setText(text);
27 | }
28 |
29 | @Override
30 | public String getText() {
31 | return iShape.getText();
32 | }
33 |
34 | @Override
35 | public boolean checkMattePaint() {
36 | return iShape.checkMattePaint();
37 | }
38 |
39 | @Override
40 | public void setMatte(boolean isMatte) {
41 | iShape.setMatte(isMatte);
42 | }
43 |
44 | @Override
45 | public boolean getMatte() {
46 | return iShape.getMatte();
47 | }
48 |
49 | @Override
50 | public void setRect(Rect rect) {
51 | iShape.setRect(rect);
52 | }
53 |
54 | @Override
55 | public Shape getShape() {
56 | return iShape.getShape();
57 | }
58 |
59 | @Override
60 | public void setTriangleType(TriangleShape.TriangleType triangleType) {
61 | iShape.setTriangleType(triangleType);
62 | }
63 |
64 | @Override
65 | public void setRotate(boolean rotate, int mDegrees) {
66 | iShape.setRotate(rotate,mDegrees);
67 | }
68 |
69 | @Override
70 | public void setScale(float scale) {
71 | iShape.setScale(scale);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/.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 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Android API 21 Platform
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/factory/ShapeFactory.java:
--------------------------------------------------------------------------------
1 | package com.example.library.factory;
2 |
3 | import android.content.Context;
4 |
5 | import com.example.library.proxy.IShape;
6 | import com.example.library.proxy.ShapeProxy;
7 | import com.example.library.shape.QuadrangleShape;
8 | import com.example.library.shape.TriangleShape;
9 |
10 | /**
11 | * 静态代理工厂
12 | * Created by lizw on 2018/9/21.
13 | */
14 |
15 | public class ShapeFactory {
16 | public static IShape getShape(int index, String text, Context context) {
17 | return getShape(index,text,context,0f);
18 | }
19 | public static IShape getShape(int index, String text, Context context,float scale) {
20 | ShapeProxy shapeProxy = new ShapeProxy();
21 | switch (index) {
22 | case 0://右下第一个,第一象限,正45度文字
23 | shapeProxy.init(new TriangleShape(context));
24 | shapeProxy.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_FIRST_QUADRANT);
25 | shapeProxy.setRotate(true,45);
26 | break;
27 | case 1://右上第一个,第三象限,
28 | shapeProxy.init(new TriangleShape(context));
29 | shapeProxy.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_THIRD_QUADRANT);
30 | break;
31 | case 2://正方形
32 | shapeProxy.init(new QuadrangleShape(context));
33 | shapeProxy.setScale(0);
34 | break;
35 | case 3://平行四边形
36 | shapeProxy.init(new QuadrangleShape(context));
37 | shapeProxy.setScale(scale);
38 | break;
39 | case 4://第二象限,文字倾斜
40 | shapeProxy.init(new TriangleShape(context));
41 | shapeProxy.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_SECOND_QUADRANT);
42 | shapeProxy.setRotate(true,-45);
43 | break;
44 | case 5://第二、三象限
45 | shapeProxy.init(new TriangleShape(context));
46 | shapeProxy.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_SECOND_THIRD_QUADRANT);
47 | break;
48 | case 6://第二象限
49 | shapeProxy.init(new TriangleShape(context));
50 | shapeProxy.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_SECOND_QUADRANT);
51 | break;
52 | case 7://第四象限
53 | shapeProxy.init(new TriangleShape(context));
54 | shapeProxy.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_FOURTH_QUADRANT);
55 | break;
56 | default:
57 | break;
58 | }
59 | if(shapeProxy!=null)
60 | shapeProxy.setText(text);
61 | return shapeProxy;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/factory/DynamicProxyShapeFactory.java:
--------------------------------------------------------------------------------
1 | package com.example.library.factory;
2 |
3 | import android.content.Context;
4 |
5 | import com.example.library.proxy.IShape;
6 | import com.example.library.proxy.ShapeInvocationHandler;
7 | import com.example.library.shape.QuadrangleShape;
8 | import com.example.library.shape.TriangleShape;
9 |
10 |
11 | /**
12 | * Created by lizw on 2019/3/14.
13 | */
14 | public class DynamicProxyShapeFactory {
15 | public static IShape getShape(int index, String text, Context context) {
16 | return getShape(index,text,context,0f);
17 | }
18 | public static IShape getShape(int index, String text, Context context,float scale) {
19 | IShape iShape = null;
20 | switch (index) {
21 | case 0://右下第一个,第一象限,正45度文字
22 | iShape= new ShapeInvocationHandler(new TriangleShape(context)).getIshapeProxy();
23 | iShape.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_FIRST_QUADRANT);
24 | iShape.setRotate(true,45);
25 | break;
26 | case 1://右上第一个,第三象限,
27 | iShape= new ShapeInvocationHandler(new TriangleShape(context)).getIshapeProxy();
28 | iShape.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_THIRD_QUADRANT);
29 | break;
30 | case 2://正方形
31 | iShape= new ShapeInvocationHandler(new QuadrangleShape(context)).getIshapeProxy();
32 | iShape.setScale(0);
33 | break;
34 | case 3://平行四边形
35 | iShape= new ShapeInvocationHandler(new QuadrangleShape(context)).getIshapeProxy();
36 | iShape.setScale(scale);
37 | break;
38 | case 4://第二象限,文字倾斜
39 | iShape= new ShapeInvocationHandler(new TriangleShape(context)).getIshapeProxy();
40 | iShape.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_SECOND_QUADRANT);
41 | iShape.setRotate(true,-45);
42 | break;
43 | case 5://第二、三象限
44 | iShape= new ShapeInvocationHandler(new TriangleShape(context)).getIshapeProxy();
45 | iShape.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_SECOND_THIRD_QUADRANT);
46 | break;
47 | case 6://第二象限
48 | iShape= new ShapeInvocationHandler(new TriangleShape(context)).getIshapeProxy();
49 | iShape.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_SECOND_QUADRANT);
50 | break;
51 | case 7://第四象限
52 | iShape= new ShapeInvocationHandler(new TriangleShape(context)).getIshapeProxy();
53 | iShape.setTriangleType(TriangleShape.TriangleType.TRIANGLE_TYPE_FOURTH_QUADRANT);
54 | break;
55 | default:
56 | break;
57 | }
58 | if(iShape!=null)
59 | iShape.setText(text);
60 | return iShape;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/shape/BaseShape.java:
--------------------------------------------------------------------------------
1 | package com.example.library.shape;
2 |
3 |
4 | import android.content.Context;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.shapes.Shape;
9 | import android.text.TextUtils;
10 |
11 | import com.example.library.R;
12 | import com.example.library.proxy.IShape;
13 |
14 | public abstract class BaseShape extends Shape implements IShape {
15 | protected Path path=new Path();
16 | protected Paint textPaint=new Paint();
17 | protected Paint mattePaint;
18 | protected String text;
19 | protected Rect textRect=new Rect();
20 | protected Rect rect=new Rect();
21 | protected int offset;
22 | protected float scale = -1f;
23 | protected Context context;
24 | protected boolean needMatte = true;//点击隐藏显示蒙层开关
25 | protected boolean rotate = false;//文字是否倾斜
26 | protected int mDegrees;//文字倾斜角度
27 | public BaseShape(Context context){
28 | initView(context);
29 | }
30 | public void initView(Context context) {
31 | this.context = context;
32 | textPaint.setColor(context.getResources().getColor(R.color.paint_text_color));
33 | textPaint.setAntiAlias(true);
34 | textPaint.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.shape_text_size));
35 | textPaint.setFakeBoldText(true);
36 | textRect.set(textRect.centerX(), textRect.centerY() - 30, textRect.centerX() + textRect.width(), textRect.centerY() + textRect.height());
37 | mattePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
38 | mattePaint.setColor(context.getResources().getColor(R.color.paint_matte_color));
39 | mattePaint.setStyle(Paint.Style.FILL);
40 | }
41 |
42 | public void setMatte(boolean needMatte) {
43 | this.needMatte = needMatte;
44 | }
45 |
46 | public boolean getMatte() {
47 | return this.needMatte;
48 | }
49 |
50 | public String getText() {
51 | return text;
52 | }
53 | //关闭蒙层
54 | public void closeMette() {
55 | mattePaint=null;
56 | }
57 | public void setText(String text) {
58 | this.text = text;
59 | if (!TextUtils.isEmpty(text))
60 | textPaint.getTextBounds(this.text, 0, this.text.length(), textRect);
61 | }
62 |
63 | @Override
64 | public boolean checkMattePaint() {
65 | return mattePaint!=null;
66 | }
67 | public void setRect(Rect rect) {
68 | this.rect = rect;
69 | }
70 |
71 | public boolean isRotate() {
72 | return rotate;
73 | }
74 |
75 | public void setRotate(boolean rotate, int mDegrees) {
76 | this.rotate = rotate;
77 | this.mDegrees = mDegrees;
78 | }
79 |
80 | public void setOffset(int offset) {
81 | this.offset = offset;
82 | }
83 |
84 | public void setScale(float scale) {
85 | this.scale = scale;
86 | }
87 |
88 | @Override
89 | public Shape getShape() {
90 | return this;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/shape/QuadrangleShape.java:
--------------------------------------------------------------------------------
1 | package com.example.library.shape;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.text.TextUtils;
7 |
8 | import com.example.library.proxy.IShape;
9 |
10 | /**
11 | * Created by lizw on 2018/4/19.
12 | */
13 |
14 |
15 | public class QuadrangleShape extends BaseShape implements IShape {
16 | public QuadrangleShape(Context context){
17 | super(context);
18 | }
19 | @Override
20 | public void draw(Canvas canvas, Paint paint) {
21 | if (rect == null || rect.width() <= 0 || rect.height() <= 0) {
22 | return;
23 | }
24 | if (scale > 0.0f && scale < 1.0f) {
25 | offset = (int) (scale * rect.width());
26 | path.reset();
27 | path.moveTo(offset, rect.left);
28 | path.lineTo(rect.left, rect.bottom);
29 | path.lineTo(rect.right - offset, rect.bottom);
30 | path.lineTo(rect.right, 0);
31 | } else if (scale > -1.0f && scale < 0.0f) {
32 | offset = (int) (-scale * rect.width());
33 | path.reset();
34 | path.moveTo(0, 0);
35 | path.lineTo(offset, rect.bottom);
36 | path.lineTo(rect.right, rect.bottom);
37 | path.lineTo(rect.right - offset, 0);
38 | } else {
39 | path.reset();
40 | path.moveTo(offset, rect.left);
41 | path.lineTo(rect.left, rect.bottom);
42 | path.lineTo(rect.right - offset, rect.bottom);
43 | path.lineTo(rect.right, 0);
44 | }
45 | canvas.drawPath(path, paint);
46 | //蒙层
47 | if (needMatte&&mattePaint!=null)
48 | canvas.drawPath(path, mattePaint);
49 |
50 | //文字
51 | if (!TextUtils.isEmpty(this.text)) {
52 | int x = (rect.width() / 2) - textRect.centerX();
53 | int y = (rect.height() / 2) - textRect.centerY();
54 | canvas.drawText(this.text, x, y, this.textPaint);
55 | }
56 | }
57 |
58 | public boolean chackIn(float x, float y) {
59 | if (scale > 0.0f && scale < 1.0f) {
60 | //TODO 正平行四边形
61 | return true;
62 | } else if (scale > -1.0f && scale < 0.0f) {
63 | float offset = (-scale * rect.width());
64 | if (x >= 0 && x < offset && (x / y) >= (offset / (float) rect.height())) {
65 | if (y >= rect.top && y <= rect.bottom)
66 | return true;
67 | } else if (x >= offset && x <= (rect.right - offset)) {
68 | if (y >= rect.top && y <= rect.bottom)
69 | return true;
70 | } else if (x > rect.right - offset && x <= rect.right && ((x - (rect.right - offset)) / y) <= (offset / (float) rect.height())) {
71 | if (y >= rect.top && y <= rect.bottom)
72 | return true;
73 | }
74 | } else if (scale == 0) {
75 | if (x <= rect.right && x >= rect.left && y <= rect.bottom && y >= rect.top)
76 | return true;
77 | }
78 | return false;
79 | }
80 |
81 |
82 | @Override
83 | public void setTriangleType(TriangleShape.TriangleType triangleType) {
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/anomaly_image_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
16 |
25 |
34 |
42 |
51 |
60 |
70 |
78 |
79 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/ShapeImageView.java:
--------------------------------------------------------------------------------
1 | package com.example.library;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Bitmap.Config;
7 | import android.graphics.BitmapShader;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.graphics.Rect;
12 | import android.graphics.Shader.TileMode;
13 | import android.graphics.drawable.Drawable;
14 | import android.graphics.drawable.ShapeDrawable;
15 | import android.util.AttributeSet;
16 | import android.view.MotionEvent;
17 | import android.view.View;
18 | import android.widget.ImageView;
19 |
20 | import com.example.library.proxy.IShape;
21 |
22 | public class ShapeImageView extends ImageView {
23 | public static final String TAG = "ShapeImageView";
24 | private ShapeDrawable mShapeDrawable;
25 | private IShape mShape;
26 | private boolean mIsShape;
27 | private boolean mRebuildShape;
28 | private OnShapeImageClickListener onShapeImageClickListener;
29 |
30 | public ShapeImageView(Context context) {
31 | this(context, null);
32 | }
33 |
34 | public ShapeImageView(Context context, AttributeSet attrs) {
35 | this(context, attrs, 0);
36 | }
37 |
38 | public ShapeImageView(Context context, AttributeSet attrs, int defStyle) {
39 | super(context, attrs, defStyle);
40 | }
41 |
42 | //设置shape
43 | public void setShap(IShape shape) {
44 | mShape = shape;
45 | mIsShape = true;
46 | mRebuildShape = true;
47 | }
48 | //设置文字给shape
49 | public void setShapeText(String text) {
50 | if(mShape!=null) {
51 | mShape.setText(text);
52 | }
53 | }
54 |
55 | @Override
56 | public boolean onTouchEvent(MotionEvent event) {
57 | if(mShape==null) {
58 | return super.onTouchEvent(event);
59 | }
60 | switch (event.getAction()) {
61 | case MotionEvent.ACTION_DOWN:
62 | // Toast.makeText(this.getContext(),"down",Toast.LENGTH_SHORT).show();
63 | if(mShape.chackIn(event.getX(),event.getY())) {
64 | if(mShape.checkMattePaint()) {
65 | mShape.setMatte(false);
66 | invalidate();
67 | }
68 | return true;
69 | }
70 | break;
71 | case MotionEvent.ACTION_UP:
72 | if(mShape.chackIn(event.getX(),event.getY())&&onShapeImageClickListener!=null) {
73 | onShapeImageClickListener.onClickListener(this,getText());
74 | }
75 | if(!mShape.getMatte()&&mShape.checkMattePaint()) {
76 | mShape.setMatte(true);
77 | invalidate();
78 | }
79 | return true;
80 | case MotionEvent.ACTION_CANCEL:
81 | if(!mShape.getMatte()&&mShape.checkMattePaint()) {
82 | mShape.setMatte(true);
83 | invalidate();
84 | }
85 | return true;
86 |
87 | }
88 | return super.onTouchEvent(event);
89 | }
90 |
91 | @SuppressLint("DrawAllocation")
92 | @Override
93 | protected void onDraw(Canvas canvas) {
94 |
95 | if (mIsShape) {
96 | //获取ImageView的drawble,当调用过setShape方法时,走下面的流程
97 | Drawable oldDrawable = getDrawable();
98 | if (oldDrawable == null || mShape == null) {
99 | return;
100 | }
101 |
102 | Rect bounds = oldDrawable.getBounds();
103 |
104 | if (bounds == null || bounds.width() == 0 || bounds.height() == 0) {
105 | return;
106 | }
107 | if (mShapeDrawable == null) {
108 | mShapeDrawable = new ShapeDrawable();
109 | }
110 | //设置shapedrawable的bounds
111 | mShapeDrawable.setBounds(bounds);
112 |
113 | if (mRebuildShape) {
114 | mRebuildShape = false;
115 | //获取bitmap
116 | Bitmap bm = drawableToBitmap(oldDrawable);
117 | if (bm == null) {
118 | return;
119 | }
120 | //创建一个bitmapshader,shapedrawable设置这个位图渲染
121 | BitmapShader bitmapShader = new BitmapShader(bm,
122 | TileMode.CLAMP, TileMode.CLAMP);
123 | mShapeDrawable.getPaint().setFlags(Paint.ANTI_ALIAS_FLAG);
124 | mShapeDrawable.getPaint().setStyle(Paint.Style.FILL);
125 | mShapeDrawable.getPaint().setShader(bitmapShader);
126 | mShapeDrawable.setShape(mShape.getShape());
127 | }
128 | mShape.setRect(bounds);
129 | int paddingTop = getPaddingTop();
130 | int paddingLeft = getPaddingLeft();
131 |
132 | //将mShapeDrawable画在canvas
133 | if (paddingTop == 0 && paddingLeft == 0) {
134 | mShapeDrawable.draw(canvas);
135 | } else {
136 | int saveCount = canvas.getSaveCount();
137 | canvas.save();
138 |
139 | canvas.translate(paddingLeft, paddingTop);
140 | mShapeDrawable.draw(canvas);
141 | canvas.restoreToCount(saveCount);
142 | }
143 | } else {
144 | super.onDraw(canvas);
145 | }
146 |
147 | }
148 |
149 | //此方法用于创建一个bitmap
150 | public static Bitmap drawableToBitmap(Drawable drawable) {
151 | if (drawable == null || drawable.getBounds() == null) {
152 | return null;
153 | }
154 | Bitmap bitmap;
155 | int width = drawable.getBounds().width();
156 | int height = drawable.getBounds().height();
157 | try {
158 | bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
159 | Canvas canvas = new Canvas(bitmap);
160 | drawable.draw(canvas);
161 | } catch (IllegalArgumentException e) {
162 | e.printStackTrace();
163 | bitmap = null;
164 | }
165 | return bitmap;
166 | }
167 | public void setOnShapeImageClickListener(OnShapeImageClickListener onShapeImageClickListener) {
168 | this.onShapeImageClickListener=onShapeImageClickListener;
169 | }
170 |
171 | public String getText() {
172 | return mShape==null?"":mShape.getText();
173 | }
174 |
175 | public interface OnShapeImageClickListener{
176 | void onClickListener(View view,String text);
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/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/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/java/com/example/administrator/anomalyimage/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.administrator.anomalyimage;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.text.TextUtils;
6 | import android.view.View;
7 | import android.widget.LinearLayout;
8 | import android.widget.RelativeLayout;
9 | import android.widget.Toast;
10 |
11 | import com.example.library.factory.DynamicProxyShapeFactory;
12 | import com.example.library.factory.ShapeFactory;
13 | import com.example.library.ShapeImageView;
14 |
15 | public class MainActivity extends Activity {
16 | private HeaderViewHolder headerViewHolder;
17 | int topClassifyWidth;
18 | private String[] classifyNames;
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main);
23 | View headerView=findViewById(R.id.include_anomaly__image_header);
24 | headerViewHolder=new HeaderViewHolder(headerView);
25 | int screenWidth=getResources().getDisplayMetrics().widthPixels;
26 | topClassifyWidth=(screenWidth-getResources().getDimensionPixelSize(R.dimen.classify_top_cut_size))/5;
27 | int margin=getResources().getDimensionPixelSize(R.dimen.size_10_dip);
28 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams
29 | (LinearLayout.LayoutParams.MATCH_PARENT, topClassifyWidth*2+margin/2);
30 | layoutParams.setMargins(margin,margin,margin,margin);
31 | headerView.setLayoutParams(layoutParams);
32 | classifyNames = getResources().getStringArray(R.array.tingwan_home_classify_name);
33 | initHeaderView();
34 | }
35 |
36 | /**
37 | * 设置大小、形状、点击事件
38 | */
39 | private void initHeaderView() {
40 | int margin=getResources().getDimensionPixelSize(R.dimen.size_5_dip);
41 | setTopClassifySize(headerViewHolder.sivFirstQuadrantRotate,topClassifyWidth);
42 | headerViewHolder.sivFirstQuadrantRotate.setShap(DynamicProxyShapeFactory.getShape(0,classifyNames[0],this.getApplicationContext()));
43 | setTopClassifySize(headerViewHolder.sivThirdQuadrant,topClassifyWidth*2-margin);
44 | headerViewHolder.sivThirdQuadrant.setShap(DynamicProxyShapeFactory.getShape(1,classifyNames[1],this.getApplicationContext()));
45 | setTopClassifySize(headerViewHolder.sivSquare,topClassifyWidth);
46 | headerViewHolder.sivSquare.setShap(DynamicProxyShapeFactory.getShape(2,classifyNames[2],this.getApplicationContext()));
47 | setTopClassifySize(headerViewHolder.sivParallelogram,topClassifyWidth*2+margin,topClassifyWidth-margin);
48 | headerViewHolder.sivParallelogram.setShap(DynamicProxyShapeFactory.getShape(3,classifyNames[3],this.getApplicationContext(),-(((float) topClassifyWidth-margin)/(topClassifyWidth*2+margin))));
49 | setTopClassifySize(headerViewHolder.sivSecondQuadrantRotate,topClassifyWidth);
50 | headerViewHolder.sivSecondQuadrantRotate.setShap(DynamicProxyShapeFactory.getShape(4,classifyNames[4],this.getApplicationContext()));
51 | setTopClassifySize(headerViewHolder.sivSecondThirdQuadrant,topClassifyWidth*2);
52 | headerViewHolder.sivSecondThirdQuadrant.setShap(DynamicProxyShapeFactory.getShape(5,classifyNames[5],this.getApplicationContext()));
53 | setTopClassifySize(headerViewHolder.sivSecondQuadrant,topClassifyWidth*2-margin);
54 | headerViewHolder.sivSecondQuadrant.setShap(DynamicProxyShapeFactory.getShape(6,classifyNames[6],this.getApplicationContext()));
55 | setTopClassifySize(headerViewHolder.sivFourthQuadrant,topClassifyWidth*2-margin);
56 | headerViewHolder.sivFourthQuadrant.setShap(DynamicProxyShapeFactory.getShape(7,classifyNames[7],this.getApplicationContext()));
57 |
58 | initEvent();
59 | }
60 |
61 | private void initEvent() {
62 | headerViewHolder.sivFirstQuadrantRotate.setOnShapeImageClickListener(onShapeImageClickListener);
63 | headerViewHolder.sivThirdQuadrant.setOnShapeImageClickListener(onShapeImageClickListener);
64 | headerViewHolder.sivSquare.setOnShapeImageClickListener(onShapeImageClickListener);
65 | headerViewHolder.sivParallelogram.setOnShapeImageClickListener(onShapeImageClickListener);
66 | headerViewHolder.sivSecondQuadrantRotate.setOnShapeImageClickListener(onShapeImageClickListener);
67 | headerViewHolder.sivSecondThirdQuadrant.setOnShapeImageClickListener(onShapeImageClickListener);
68 | headerViewHolder.sivSecondQuadrant.setOnShapeImageClickListener(onShapeImageClickListener);
69 | headerViewHolder.sivFourthQuadrant.setOnShapeImageClickListener(onShapeImageClickListener);
70 | }
71 |
72 | private void setTopClassifySize(ShapeImageView view,int size) {
73 | setTopClassifySize(view,size,size);
74 | }
75 | private void setTopClassifySize(ShapeImageView view,int width,int height) {
76 | RelativeLayout.LayoutParams lpFirstQuadrantRotate= (RelativeLayout.LayoutParams) view.getLayoutParams();
77 | lpFirstQuadrantRotate.width=width;
78 | lpFirstQuadrantRotate.height=height;
79 | view.setLayoutParams(lpFirstQuadrantRotate);
80 | }
81 |
82 |
83 | public ShapeImageView.OnShapeImageClickListener onShapeImageClickListener=new ShapeImageView.OnShapeImageClickListener() {
84 | @Override
85 | public void onClickListener(View view, String tag) {
86 | if(!TextUtils.isEmpty(tag)) {
87 | Toast.makeText(MainActivity.this,tag,Toast.LENGTH_SHORT).show();
88 | }
89 | }
90 | };
91 |
92 | public static class HeaderViewHolder {
93 | ShapeImageView sivFirstQuadrantRotate;
94 | ShapeImageView sivThirdQuadrant;
95 | ShapeImageView sivSquare;
96 | ShapeImageView sivParallelogram;
97 | ShapeImageView sivSecondQuadrantRotate;
98 | ShapeImageView sivSecondThirdQuadrant;
99 | ShapeImageView sivSecondQuadrant;
100 | ShapeImageView sivFourthQuadrant;
101 |
102 | public HeaderViewHolder(View view) {
103 | sivFirstQuadrantRotate=view.findViewById(R.id.siv_first_quadrant_rotate);
104 | sivThirdQuadrant=view.findViewById(R.id.siv_third_quadrant);
105 | sivSquare=view.findViewById(R.id.siv_square);
106 | sivParallelogram=view.findViewById(R.id.siv_parallelogram);
107 | sivSecondQuadrantRotate=view.findViewById(R.id.siv_second_quadrant_rotate);
108 | sivSecondThirdQuadrant=view.findViewById(R.id.siv_second_third_quadrant);
109 | sivSecondQuadrant=view.findViewById(R.id.siv_second_quadrant);
110 | sivFourthQuadrant=view.findViewById(R.id.siv_fourth_quadrant);
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/library/src/main/java/com/example/library/shape/TriangleShape.java:
--------------------------------------------------------------------------------
1 | package com.example.library.shape;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.drawable.shapes.Shape;
7 | import android.text.TextUtils;
8 |
9 | import com.example.library.proxy.IShape;
10 |
11 | /**
12 | * Created by lizw on 2018/4/10.
13 | */
14 |
15 | public class TriangleShape extends BaseShape implements IShape {
16 | protected TriangleShape.TriangleType triangleType=TriangleShape.TriangleType.TRIANGLE_TYPE_FIRST_QUADRANT;//三角形类型
17 | public enum TriangleType {
18 | TRIANGLE_TYPE_FIRST_QUADRANT, TRIANGLE_TYPE_SECOND_QUADRANT, TRIANGLE_TYPE_THIRD_QUADRANT, TRIANGLE_TYPE_SECOND_THIRD_QUADRANT, TRIANGLE_TYPE_FOURTH_QUADRANT
19 | }
20 | public TriangleShape(Context context){
21 | super(context);
22 | }
23 | @Override
24 | public void draw(Canvas canvas, Paint paint) {
25 | if (rect == null || rect.width() <= 0 || rect.height() <= 0) {
26 | return;
27 | }
28 | int x = 0, y = 0;
29 | path.reset();
30 | switch (triangleType) {
31 | case TRIANGLE_TYPE_FIRST_QUADRANT:
32 | path.moveTo(rect.left, rect.top);
33 | path.lineTo(rect.left, rect.bottom);
34 | path.lineTo(rect.right, rect.bottom);
35 | if (rotate) {
36 | x = (rect.width() * 1 / 2 - textRect.height() * 2 / 3) - textRect.centerX();
37 | y = (rect.height() * 1 / 2 + textRect.height() * 2 / 3) - textRect.centerY();
38 | } else {
39 | x = (rect.width() * 2 / 3) - textRect.centerX();
40 | y = (rect.height() * 2 / 3) - textRect.centerY();
41 | }
42 | break;
43 | case TRIANGLE_TYPE_SECOND_QUADRANT:
44 | path.moveTo(rect.left, rect.bottom);
45 | path.lineTo(rect.right, rect.bottom);
46 | path.lineTo(rect.right, rect.top);
47 | if (rotate) {
48 | x = (rect.width() * 1 / 2 + textRect.height() * 2 / 3) - textRect.centerX();
49 | y = (rect.height() * 1 / 2 + textRect.height() * 2 / 3) - textRect.centerY();
50 | } else {
51 | x = (rect.width() * 3 / 4) - textRect.centerX();
52 | y = (rect.height() * 3 / 4) - textRect.centerY();
53 | }
54 | break;
55 | case TRIANGLE_TYPE_THIRD_QUADRANT:
56 | path.moveTo(rect.left, rect.top);
57 | path.lineTo(rect.right, rect.top);
58 | path.lineTo(rect.right, rect.bottom);
59 | x = (rect.width() * 3 / 4) - textRect.centerX();
60 | y = (rect.height() / 3) - textRect.centerY();
61 | break;
62 | case TRIANGLE_TYPE_FOURTH_QUADRANT:
63 | path.moveTo(rect.left, rect.top);
64 | path.lineTo(rect.left, rect.bottom);
65 | path.lineTo(rect.right, rect.top);
66 | x = (rect.width() / 4) - textRect.centerX();
67 | y = (rect.height() / 4) - textRect.centerY();
68 | break;
69 | case TRIANGLE_TYPE_SECOND_THIRD_QUADRANT:
70 | path.moveTo(rect.left, rect.top);
71 | path.lineTo(rect.left, rect.bottom);
72 | path.lineTo(rect.right / 2, rect.bottom / 2);
73 | x = (rect.width() / 5) - textRect.centerX();
74 | y = (rect.height() / 2) - textRect.centerY();
75 | break;
76 | }
77 |
78 | drawPath(canvas, paint);
79 |
80 | //文字
81 | if (!TextUtils.isEmpty(this.text)) {
82 | if (rotate) {
83 | switch (triangleType) {
84 | case TRIANGLE_TYPE_FIRST_QUADRANT:
85 | canvas.rotate(mDegrees, rect.width() / 2 - textRect.height() * 2 / 3, rect.height() / 2 + textRect.height() * 2 / 3);
86 | break;
87 | case TRIANGLE_TYPE_SECOND_QUADRANT:
88 | canvas.rotate(mDegrees, rect.width() / 2 + textRect.height() * 2 / 3, rect.height() / 2 + textRect.height() * 2 / 3);
89 | break;
90 | default:
91 | canvas.rotate(mDegrees, rect.width() / 2 - textRect.height() * 2 / 3, rect.height() / 2 + textRect.height() * 2 / 3);
92 | break;
93 | }
94 |
95 | }
96 | canvas.drawText(this.text, x, y, this.textPaint);
97 | }
98 | }
99 |
100 | private void drawPath(Canvas canvas, Paint paint) {
101 | canvas.drawPath(path, paint);
102 | //蒙层
103 | if (needMatte&&mattePaint!=null)
104 | canvas.drawPath(path, mattePaint);
105 | }
106 |
107 | @Override
108 | public boolean chackIn(float x, float y) {
109 | switch (triangleType) {
110 | case TRIANGLE_TYPE_FOURTH_QUADRANT:
111 | if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom && (y / ((float) rect.width() - x)) <= ((float) rect.height() / (float) rect.width())) {
112 | return true;
113 | }
114 | break;
115 | case TRIANGLE_TYPE_SECOND_QUADRANT:
116 | if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom && (y / ((float) rect.width() - x)) >= ((float) rect.height() / (float) rect.width())) {
117 | return true;
118 | }
119 | break;
120 | case TRIANGLE_TYPE_THIRD_QUADRANT:
121 | if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom && (x / y) >= ((float) rect.width() / (float) rect.height())) {
122 | return true;
123 | }
124 | break;
125 | case TRIANGLE_TYPE_FIRST_QUADRANT:
126 | if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom && (x / y) <= ((float) rect.width() / (float) rect.height())) {
127 | return true;
128 | }
129 | break;
130 | case TRIANGLE_TYPE_SECOND_THIRD_QUADRANT:
131 | if (x >= rect.left && x <= rect.right / 2 && y >= rect.top && y <= rect.bottom) {
132 | if (y <= rect.right / 2 && (x / y) <= ((float) rect.width() / (float) rect.height())) {
133 | return true;
134 | } else if (y > rect.right / 2 && (y / ((float) rect.width() - x)) <= ((float) rect.height() / (float) rect.width())) {
135 | return true;
136 | }
137 | }
138 | break;
139 | }
140 |
141 | return false;
142 | }
143 |
144 | public void setTriangleType(TriangleShape.TriangleType triangleType) {
145 | this.triangleType = triangleType;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------