├── .github
├── CONTRIBUTING.md
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── dictionaries
│ └── saulgoodman.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE.md
├── README.md
├── art
├── crop_menu_1.png
├── crop_menu_2.png
├── crop_menu_3.png
├── cropping.png
├── ic_launcher.psd
├── kerad_logo.png
├── slide_menu_left.jpg
├── slide_menu_right.jpg
└── web_hi_res_512.png
├── build.gradle
├── circle.yml
├── code-quality
├── checkstyle.xml
└── custom-lint.xml
├── documentation
├── IMAGE_CROP.md
├── ROUNDED_CORNERS.md
├── THANKS.md
└── TOOLING.md
├── gradle.properties
├── gradle
├── code-quality-android.gradle
├── code-quality.gradle
├── maven-2.gradle
├── maven-deployment.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── projectFilesBackup
└── .idea
│ └── workspace.xml
├── samples
├── build.gradle
├── lint.xml
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── codeforvictory
│ │ └── superimageview
│ │ └── samples
│ │ └── superimageview
│ │ ├── HomeActivity.java
│ │ ├── image_cropping
│ │ ├── ImageCroppingActivity.java
│ │ ├── ImagesPagerAdapter.java
│ │ ├── ImagesRecyclerAdapter.java
│ │ └── NetworkImageCroppingActivity.java
│ │ ├── rounded_corners
│ │ ├── Image.java
│ │ ├── ImageFactory.java
│ │ ├── ImagesRecyclerAdapter.java
│ │ └── RoundedCornerImagesActivity.java
│ │ └── shared
│ │ ├── ImageLocalDataSource.java
│ │ ├── LocalImage.java
│ │ ├── NetworkImage.java
│ │ └── widget
│ │ └── VerticalTransparentItemDecorator.java
│ └── res
│ ├── drawable-xxhdpi
│ ├── ball_horizontal.png
│ └── ball_vertical.png
│ ├── layout
│ ├── activity_home.xml
│ ├── activity_image_cropping.xml
│ ├── activity_images.xml
│ ├── item_local_image.xml
│ ├── item_network_cropped_image.xml
│ └── item_network_rounded_image.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-v19
│ └── styles.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── attrs.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── settings.gradle
├── superimageview-imagecrop
├── CHANGELOG.md
├── build.gradle
├── gradle.properties
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── codeforvictory
│ │ └── android
│ │ └── superimageview
│ │ └── crop
│ │ ├── CropType.java
│ │ ├── CroppedImage.java
│ │ ├── ImageTransformation.java
│ │ └── error
│ │ └── IllegalTransformationType.java
│ └── res
│ └── values
│ └── attrs.xml
├── superimageview-roundedcorners
├── CHANGELOG.md
├── build.gradle
├── gradle.properties
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── codeforvictory
│ │ └── roundedcorners
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── codeforvictory
│ │ │ └── android
│ │ │ └── superimageview
│ │ │ └── roundedcorners
│ │ │ ├── Corner.java
│ │ │ ├── RoundedBitmapViewDrawable.java
│ │ │ ├── RoundedCornerImageViewHook.java
│ │ │ ├── RoundedCornersImage.java
│ │ │ └── RoundedCornerss.java
│ └── res
│ │ └── values
│ │ └── attrs.xml
│ └── test
│ └── java
│ └── com
│ └── codeforvictory
│ └── roundedcorners
│ └── ExampleUnitTest.java
└── superimageview
├── build.gradle
├── gradle.properties
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── codeforvictory
│ └── android
│ └── superimageview
│ ├── Crop.java
│ ├── RoundedCorners.java
│ └── SuperImageView.java
└── res
└── values
└── attrs.xml
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contibuting
2 |
3 | If you would like to contribute code to [**SuperImageView**](github.com/cesards/SuperImageView) you can do so through GitHub by forking the repository and sending a pull request.
4 |
5 | When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also make sure your code compiles by running ./gradlew clean build. Checkstyle failures during compilation indicate errors in your style and can be viewed in files located at */build/report/checkstyle directories.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Issue Template
2 |
3 | Welcome and thank you for reporting an issue and with doing so, improving the library!
4 |
5 | **Important**: Please, before submitting a new issue, verify that your issue hasn't already been reported by
6 | [**searching over all issues**](https://github.com/cesards/SuperImageView/issues).
7 |
8 |
9 | What kind of issue is this?
10 |
11 | - **Help wanted**: If you have questions about how the library works, please, use the `help wanted` [**label**](https://github.com/cesards/SuperImageView/labels) before submitting.
12 |
13 | - **Bug**: If you found a bug, try to spend some time writing a report and a failing test. Bugs with tests get fixed much more easily. [**Here is a good example**](https://gist.github.com/swankjesse/981fcae102f513eb13ed).
14 |
15 | - **Enhancement**: Try to explain what's the problem you are willing to solve. Don't send pull requests with new features' implementations without asking first.
16 |
17 |
18 | ^^^^^ DELETE FROM THIS LINE UP ^^^^^
19 |
20 | ```
21 |
22 | REPLACE THIS LINE WITH YOUR STACKTRACE OR OUTPUT FROM LEAKCANARY
23 |
24 | ```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle
2 | .gradle/
3 | gradlew.bat
4 | build/
5 | local.properties
6 |
7 | # Maven
8 | target
9 | pom.xml.*
10 | release.properties
11 | gen-external-apklibs
12 |
13 | # Eclipse
14 | .classpath
15 | .project
16 | .settings
17 | eclipsebin
18 | proguard/
19 |
20 | # IntelliJ IDEA
21 | *.iml
22 | *.ipl
23 | *.iws
24 | /.idea/*
25 |
26 | !/.idea/vcs.xml
27 | !/.idea/fileTemplates/
28 | !/.idea/inspectionProfiles/
29 | !/.idea/scopes/
30 | !/.idea/codeStyles/
31 | !/.idea/encodings.xml
32 | !/.idea/copyright/
33 | !/.idea/compiler.xml
34 |
35 |
36 |
37 |
38 | idea-classes/
39 | coverage-error.log
40 | ############################## TO CHECK ##############################
41 | #.idea/markdown-navigator/ #
42 | # .idea/tasks.xml #
43 | # .idea/dictionaries # SHOULD THIS BE INCLUDED IN THE FOLDER? #
44 | # /.idea/assetWizardSettings.xml SHOULD THIS BE EXCLUDED ?? #
45 | # /.idea/navEditor.xml SHOULD THIS BE EXCLUDED ?? #
46 | ######################################################################
47 |
48 | # Android Studio
49 | captures/
50 | .navigation/
51 |
52 | # Android
53 | gen
54 | bin
55 | project.properties
56 |
57 | # Finder
58 | .DS_Store
59 |
60 | # Windows
61 | Thumbs.db
62 |
63 | # Logs
64 | *.log
65 |
66 | # Google Services (e.g. APIs or Firebase)
67 | google-services.json
68 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.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 |
--------------------------------------------------------------------------------
/.idea/dictionaries/saulgoodman.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
22 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 César Díez Sánchez - Code For Victory
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
SuperImageView
2 | Extra features for your ImageView provided in a modularized way
3 |
4 |
5 | Documentation for v2 coming this week.
6 |
7 | ---
8 | ---
9 | ---
10 |
11 |
12 | CropImageView
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | An ImageView that supports different kind of cropping rather than the only Android is currently supporting: `centerCrop`
22 |
23 | Using this library, you can crop your desired image by sides described below:
24 |
25 | 
26 |
27 | Development idea borns at the point in [Kerad Games] we needed images cropped by somewhere no matter the image size.
28 |
29 | The original images we had to deal with (we wanted the half size of the ball shown whatever screen size), below
30 |
31 | 
32 | 
33 |
34 | Here are some screenshots what we got thanks to this widget :-)
35 |
36 | 
37 | 
38 | 
39 |
40 | Usage
41 | -----
42 | ### Step 1
43 | ##### Gradle
44 | ```groovy
45 | dependencies {
46 | compile 'com.cesards.android:cropimageview:1.0.2.1'
47 | }
48 | ```
49 | ##### Maven
50 | ```xml
51 |
52 | com.cesards.android
53 | CropImageView
54 | 1.0.2
55 | aar
56 |
57 | ```
58 | ### Step 2
59 | Define in xml:
60 | ```xml
61 |
66 | ```
67 | where `value` can take values
68 | ```xml
69 | topLeft|centerLeft|bottomLeft|topRight|centerRight|bottomRight|centerTop|centerBottom
70 | ```
71 | Or in code:
72 | ```java
73 | final CropImageView cropImageView = new CropImageView(CropActivity.this);
74 | final Resources res = getResources();
75 | cropImageView.setImageDrawable(res.getDrawable(images[position]));
76 | final CropImageView.CropType cropType = imageCrops[position];
77 | cropImageView.setCropType(cropType);
78 | ```
79 | Performance tests (using [Hugo](https://github.com/jakeWharton/hugo))
80 | ---------
81 |
82 | ### Center Crop Sample (ImageView)
83 | ```
84 | V/TestForegroundImageView﹕ ⇢ setFrame(l=0, t=0, r=1080, b=1557)
85 | V/TestForegroundImageView﹕ ⇠ setFrame [0ms] = true
86 | V/TestForegroundImageView﹕ ⇢ setFrame(l=1080, t=0, r=2160, b=1557)
87 | V/TestForegroundImageView﹕ ⇠ setFrame [0ms] = true
88 | V/TestForegroundImageView﹕ ⇢ setFrame(l=0, t=0, r=1080, b=1557)
89 | V/TestForegroundImageView﹕ ⇠ setFrame [0ms] = false
90 | V/TestForegroundImageView﹕ ⇢ setFrame(l=1080, t=0, r=2160, b=1557)
91 | V/TestForegroundImageView﹕ ⇠ setFrame [0ms] = false
92 | V/TestForegroundImageView﹕ ⇢ setFrame(l=0, t=0, r=1080, b=1701)
93 | V/TestForegroundImageView﹕ ⇠ setFrame [0ms] = true
94 | V/TestForegroundImageView﹕ ⇢ setFrame(l=1080, t=0, r=2160, b=1701)
95 | V/TestForegroundImageView﹕ ⇠ setFrame [0ms] = true`
96 | ```
97 |
98 | ### Custom Crop Sample (CropImageView)
99 | ```
100 | V/TestForegroundCropImageView﹕ ⇢ setFrame(l=0, t=0, r=1080, b=1557)
101 | V/TestForegroundCropImageView﹕ ⇠ setFrame [0ms] = true
102 | V/TestForegroundCropImageView﹕ ⇢ setFrame(l=1080, t=0, r=2160, b=1557)
103 | V/TestForegroundCropImageView﹕ ⇠ setFrame [0ms] = true
104 | V/TestForegroundCropImageView﹕ ⇢ setFrame(l=0, t=0, r=1080, b=1557)
105 | V/TestForegroundCropImageView﹕ ⇠ setFrame [0ms] = false
106 | V/TestForegroundCropImageView﹕ ⇢ setFrame(l=1080, t=0, r=2160, b=1557)
107 | V/TestForegroundCropImageView﹕ ⇠ setFrame [0ms] = false
108 | V/TestForegroundCropImageView﹕ ⇢ setFrame(l=0, t=0, r=1080, b=1701)
109 | V/TestForegroundCropImageView﹕ ⇠ setFrame [0ms] = true
110 | V/TestForegroundCropImageView﹕ ⇢ setFrame(l=1080, t=0, r=2160, b=1701)
111 | V/TestForegroundCropImageView﹕ ⇠ setFrame [0ms] = true
112 | ```
113 | Results: code used does not cause overhead in the UI thread.
114 |
115 | ChangeLog
116 | ---------
117 | * __1.0.2.1 (2015-10-22)__
118 | * ImageView crashes in devices with API < 18 due to a `@TargetApi` annotation
119 | * __1.0.2 (2015-10-22)__
120 | * Changed `minSdkVersion` to 7
121 | * Solved a bug related with ImageView and API < 18.
122 | * __1.0.1 (2015-02-17)__
123 | * Changed Samples UI and removed unused resources.
124 | * Added performance tests to Samples.
125 | * Added code styles for contributions.
126 | * Improved CropImageView widget. Removed `onLayout()` overhead. `ImageView` `onLayout()` is empty, so we only need logic in `setFrame()` method.
127 | * __1.0.0 (2015-02-15)__
128 | * Initial release. (`minSdkVersion="14"`).
129 |
130 | Developed By
131 | ------------
132 | * César Díez Sánchez -
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | Who's using it
154 | --------------
155 | * [Golden Manager](https://play.google.com/store/apps/details?id=com.keradgames.goldenmanager)
156 | * [Slipstream Music](https://play.google.com/store/apps/details?id=com.cypher.slipstream&hl=en)
157 | * [Vueling](https://play.google.com/store/apps/details?id=com.mo2o.vueling)
158 | * Does your app use CropImageView? Let me know if you want to be featured in this list :-)
159 |
160 | Do you want to contribute?
161 | --------------------------
162 | I'm pretty sure you there are some awesome hidden features you need in your daily dev life. Just let me know or collaborate to improve this librar
163 |
164 | I'd like to improve this library with your help, there are some new features to implement waiting for you ;)
165 |
166 | If you want to contribute, you should use [my code styles](https://github.com/cesards/CropImageView/blob/master/codestyles_DogmaLabs.xml) available in the root of the project!
167 |
168 |
169 |
170 | License
171 |
172 | __The MIT License (MIT)__
173 |
174 | Copyright (c) 2016 César Díez Sánchez
175 |
176 | Permission is hereby granted, free of charge, to any person obtaining a copy
177 | of this software and associated documentation files (the "Software"), to deal
178 | in the Software without restriction, including without limitation the rights
179 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
180 | copies of the Software, and to permit persons to whom the Software is
181 | furnished to do so, subject to the following conditions:
182 |
183 | The above copyright notice and this permission notice shall be included in all
184 | copies or substantial portions of the Software.
185 |
186 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
189 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
190 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
191 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
192 | SOFTWARE.
193 |
--------------------------------------------------------------------------------
/art/crop_menu_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/crop_menu_1.png
--------------------------------------------------------------------------------
/art/crop_menu_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/crop_menu_2.png
--------------------------------------------------------------------------------
/art/crop_menu_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/crop_menu_3.png
--------------------------------------------------------------------------------
/art/cropping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/cropping.png
--------------------------------------------------------------------------------
/art/ic_launcher.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/ic_launcher.psd
--------------------------------------------------------------------------------
/art/kerad_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/kerad_logo.png
--------------------------------------------------------------------------------
/art/slide_menu_left.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/slide_menu_left.jpg
--------------------------------------------------------------------------------
/art/slide_menu_right.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/slide_menu_right.jpg
--------------------------------------------------------------------------------
/art/web_hi_res_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/art/web_hi_res_512.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // apply plugin: 'com.github.ben-manes.versions'
2 |
3 | buildscript {
4 | ext.versions = [
5 | 'minSdk': 14,
6 | 'compileSdk': 28,
7 | 'errorProne': '2.3.1',
8 | ]
9 |
10 | repositories {
11 | google()
12 | jcenter()
13 | maven { url 'https://plugins.gradle.org/m2/' } // Error Prone Plugin
14 | }
15 |
16 | dependencies {
17 | classpath 'com.android.tools.build:gradle:3.3.0-alpha13'
18 | classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.16'
19 | classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0'
20 | }
21 | }
22 |
23 | subprojects {
24 | group = GROUP
25 | version = VERSION_NAME
26 |
27 | repositories {
28 | google()
29 | jcenter()
30 | }
31 |
32 | apply from: "${rootDir}/gradle/code-quality.gradle"
33 | }
34 |
35 | task clean(type: Delete) {
36 | delete rootProject.buildDir
37 | }
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | ## Customize the test machine
2 | machine:
3 | environment:
4 | _JAVA_OPTIONS: "-Xms512m -Xmx2048m"
5 | GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xms512m -Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"'
6 | ANDROID_HOME: /usr/local/android-sdk-linux
7 |
8 | dependencies:
9 | pre:
10 | - wget "https://services.gradle.org/distributions/gradle-2.10-bin.zip"; unzip gradle-2.10-bin.zip
11 | - echo y | android update sdk --no-ui --all --filter tool,extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository,android-23
12 | - echo y | android update sdk --no-ui --all --filter build-tools-23.0.2
13 |
14 | test:
15 | override:
16 | # When running the apk build, unit tests, lint, checkstyle etc sequentially is slow, so we run them in parallel.
17 | # Using bash case statement, choose which command to run on which node (machine).
18 | - ./gradlew assembleDebug
19 |
20 |
21 |
22 | # - ./gradlew clean assembleDebug test lint
--------------------------------------------------------------------------------
/code-quality/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/code-quality/custom-lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/documentation/IMAGE_CROP.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/documentation/IMAGE_CROP.md
--------------------------------------------------------------------------------
/documentation/ROUNDED_CORNERS.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/documentation/ROUNDED_CORNERS.md
--------------------------------------------------------------------------------
/documentation/THANKS.md:
--------------------------------------------------------------------------------
1 | https://github.com/square/leakcanary
--------------------------------------------------------------------------------
/documentation/TOOLING.md:
--------------------------------------------------------------------------------
1 | # Tooling
2 |
3 | ## Table of contents
4 |
5 | - Gradle Versions Plugin
6 | - Checkstyle
7 | - Lint
8 |
9 |
10 | ## [Gradle Versions Plugin](https://github.com/ben-manes/gradle-versions-plugin)
11 |
12 | This plugin provides a task to determine which dependencies have updates. Additionally, the plugin checks for updates to Gradle itself.
13 |
14 | Run:
15 | ```
16 | ./gradlew dependencyUpdates
17 | ```
18 |
19 | to display a report of the project dependencies that are up-to-date, exceed the latest version found, have upgrades, or failed to be resolved. When a dependency cannot be resolved the exception is logged at the info level.
20 |
21 |
22 | ## Checkstyle
23 |
24 | Execute `./gradlew checkstyle`
25 |
26 |
27 | ## Lint
28 |
29 | - Every module has its correspondant lint.xml files if needed.
30 |
31 | To run lint, you can use:
32 | ```
33 | gradlew lint --profile
34 | ```
35 | or
36 | ```
37 | gradlew lint --profile
38 | ```
39 | this will generate reports under the `/build/reports/lint-results.xml`.
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | GROUP=com.codeforvictory
3 | VERSION_NAME=2.0-RC1
4 | POM_DESCRIPTION=SuperImageView, an ImageView with super powers like rounded corners and different image crops not supported by the original widget.
5 | POM_URL=http://github.com/cesards/SuperImageView
6 | POM_SCM_URL=http://github.com/cesards/SuperImageView
7 | POM_SCM_CONNECTION=scm:git:https://github.com/cesards/SuperImageView.git
8 | POM_SCM_DEV_CONNECTION=scm:git:git@github.com:cesards/SuperImageView.git
9 | POM_LICENCE_NAME=The MIT License (MIT)
10 | POM_LICENCE_URL=https://tldrlegal.com/license/mit-license
11 | POM_LICENCE_DIST=repo
12 | POM_DEVELOPER_ID=com.codeforvictory
13 | POM_DEVELOPER_NAME=Code For Victory
14 |
15 | android.enableJetifier=true
16 | android.useAndroidX=true
17 |
--------------------------------------------------------------------------------
/gradle/code-quality-android.gradle:
--------------------------------------------------------------------------------
1 | android {
2 | lintOptions {
3 | lintConfig file("${project.rootDir}/code-quality/custom-lint.xml")
4 | htmlReport true
5 | abortOnError true
6 | // baseline file("lint-baseline.xml")
7 | // htmlOutput file("lint-report.html")
8 | // warningsAsErrors true
9 | // check[IDs of Issues to run]
10 | }
11 | }
--------------------------------------------------------------------------------
/gradle/code-quality.gradle:
--------------------------------------------------------------------------------
1 | // This should be executed under subprojects {} or allProjects {} functions.
2 |
3 | /**
4 | * Error-prone
5 | */
6 | apply plugin: 'net.ltgt.errorprone'
7 |
8 | configurations.all {
9 | resolutionStrategy {
10 | eachDependency { details ->
11 | // Force all the error-prone dependencies to use the same version.
12 | if (details.requested.group == 'com.google.errorprone' && details.requested.name.startsWith('error_prone_')) {
13 | details.useVersion versions.errorProne
14 | }
15 | }
16 | }
17 | }
18 |
19 | /**
20 | * Checkstyle
21 | */
22 | apply plugin: 'checkstyle'
23 |
24 | checkstyle {
25 | configFile rootProject.file('code-quality/checkstyle.xml')
26 | ignoreFailures false
27 | showViolations true
28 | }
29 |
30 | task checkstyle(type: Checkstyle) {
31 | configFile rootProject.file('code-quality/checkstyle.xml')
32 | source 'src/main/java'
33 | ignoreFailures false
34 | showViolations true
35 | include '**/*.java'
36 |
37 | // reports {
38 | // xml.enabled = true
39 | // }
40 |
41 | classpath = files()
42 | }
43 |
44 | afterEvaluate {
45 | if (project.tasks.getByName("check")) {
46 | check.dependsOn('checkstyle')
47 | }
48 | }
49 |
50 | /**
51 | * Tools dependencies
52 | */
53 | dependencies {
54 | // Error-prone
55 | errorprone "com.google.errorprone:error_prone_core:${versions.errorProne}"
56 | }
57 |
58 | /**
59 | * Useful links:
60 | * - http://errorprone.info/index
61 | * - https://github.com/tbroyer/gradle-errorprone-plugin-v0.0.x
62 | * - https://github.com/tbroyer/gradle-errorprone-plugin
63 | */
--------------------------------------------------------------------------------
/gradle/maven-2.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 |
3 | repositories {
4 | maven {
5 | url "http://internal.repo"
6 | }
7 | }
8 |
9 | group 'com.group.binaries'
10 | version = externalVersion
11 |
12 | publishing {
13 | publications {
14 | mavenJava(MavenPublication) {
15 | from components.java
16 | }
17 | }
18 | repositories {
19 | maven {
20 | group 'com.group.binaries'
21 | version = externalVersion
22 | credentials {
23 | username "admin"
24 | password "password"
25 | }
26 |
27 | if(project.version.endsWith('-SNAPSHOT')) {
28 | // url 'https://oss.sonatype.org/content/repositories/snapshots/'
29 | url "http://example/artifactory/libs-snapshot-local"
30 | } else {
31 | url "http://example/artifactory/libs-release-local"
32 | //"http://internal.repo/libs-snapshot-local"
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/gradle/maven-deployment.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
26 | }
27 |
28 | def getSnapshotRepositoryUrl() {
29 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL : "https://oss.sonatype.org/content/repositories/snapshots/"
30 | }
31 |
32 | def getRepositoryUsername() {
33 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
34 | }
35 |
36 | def getRepositoryPassword() {
37 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
38 | }
39 |
40 | afterEvaluate { project ->
41 | uploadArchives {
42 | repositories {
43 | mavenDeployer {
44 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
45 |
46 | pom.groupId = GROUP
47 | pom.artifactId = POM_ARTIFACT_ID
48 | pom.version = VERSION_NAME
49 |
50 | repository(url: getReleaseRepositoryUrl()) {
51 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
52 | }
53 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
54 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
55 | }
56 |
57 | pom.project {
58 | name POM_NAME
59 | packaging POM_PACKAGING
60 | description POM_DESCRIPTION
61 | url POM_URL
62 |
63 | scm {
64 | url POM_SCM_URL
65 | connection POM_SCM_CONNECTION
66 | developerConnection POM_SCM_DEV_CONNECTION
67 | }
68 |
69 | licenses {
70 | license {
71 | name POM_LICENCE_NAME
72 | url POM_LICENCE_URL
73 | distribution POM_LICENCE_DIST
74 | }
75 | }
76 |
77 | developers {
78 | developer {
79 | id POM_DEVELOPER_ID
80 | name POM_DEVELOPER_NAME
81 | }
82 | }
83 | }
84 | }
85 | }
86 | }
87 |
88 |
89 |
90 |
91 |
92 | signing {
93 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
94 | sign configurations.archives
95 | }
96 |
97 | // task androidJavadocs(type: Javadoc) {
98 | // source = android.sourceSets.main.java.srcDirs
99 | // classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
100 | // }
101 |
102 | // task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
103 | // classifier = 'javadoc'
104 | // from androidJavadocs.destinationDir
105 | // }
106 |
107 | task androidSourcesJar(type: Jar) {
108 | classifier = 'sources'
109 | from android.sourceSets.main.java.sourceFiles
110 | }
111 |
112 | artifacts {
113 | archives androidSourcesJar
114 | // archives androidJavadocsJar
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/samples/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdk
5 |
6 | defaultConfig {
7 | applicationId 'com.codeforvictory.android.superimageview.samples'
8 | minSdkVersion versions.minSdk
9 | targetSdkVersion versions.compileSdk
10 |
11 | versionCode 2000
12 | versionName VERSION_NAME
13 |
14 | testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
15 | }
16 |
17 | // In case we used Java: https://developer.android.com/studio/write/java8-support
18 | compileOptions {
19 | sourceCompatibility JavaVersion.VERSION_1_8
20 | targetCompatibility JavaVersion.VERSION_1_8
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled true
26 | shrinkResources true
27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 |
31 | testOptions {
32 | animationsDisabled = true
33 | }
34 |
35 | // bundle {
36 | // density.enableSplit = true
37 | // abi.enableSplit = true
38 | // language.enableSplit = true
39 | // }
40 |
41 | /** Due to third party libraries. Not good to exclude everytyhing since APK signature v1 is there */
42 | packagingOptions {
43 | exclude 'META-INF/LICENSE'
44 | exclude 'META-INF/LICENSE.txt'
45 | exclude 'META-INF/NOTICE'
46 | exclude 'META-INF/NOTICE.txt'
47 | exclude 'META-INF/*.version'
48 | }
49 | }
50 |
51 | //apply from: rootProject.file('gradle/code-quality-android.gradle')
52 |
53 | dependencies {
54 | implementation project(':superimageview-imagecrop')
55 | implementation project(':superimageview-roundedcorners')
56 | implementation 'androidx.core:core:1.0.0'
57 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
58 | implementation 'com.google.android.material:material:1.0.0'
59 | implementation 'com.github.bumptech.glide:glide:4.8.0'
60 | annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
61 |
62 | testImplementation "junit:junit:4.12"
63 | testImplementation "org.robolectric:robolectric:4.0-alpha-3"
64 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
65 | androidTestImplementation 'androidx.test:rules:1.1.0-alpha4'
66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
67 | }
68 |
--------------------------------------------------------------------------------
/samples/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/samples/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
27 |
28 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/HomeActivity.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 |
6 | import com.codeforvictory.superimageview.samples.superimageview.rounded_corners.RoundedCornerImagesActivity;
7 | import com.codeforvictory.superimageview.samples.superimageview.image_cropping.ImageCroppingActivity;
8 | import com.codeforvictory.superimageview.samples.superimageview.image_cropping.NetworkImageCroppingActivity;
9 |
10 | import androidx.appcompat.app.AppCompatActivity;
11 |
12 | public class HomeActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_home);
18 | findViewById(R.id.image_cropping).setOnClickListener(view ->
19 | startActivity(new Intent(this, ImageCroppingActivity.class))
20 | );
21 | findViewById(R.id.image_cropping_network).setOnClickListener(view ->
22 | startActivity(new Intent(this, NetworkImageCroppingActivity.class))
23 | );
24 | findViewById(R.id.rounded_corners).setOnClickListener(view ->
25 | startActivity(new Intent(this, RoundedCornerImagesActivity.class))
26 | );
27 | // findViewById(R.id.rounded_corners_image_cropping).setOnClickListener(view ->
28 | // startActivity(new Intent(this, RoundedCornerImagesActivity.class))
29 | // );
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/image_cropping/ImageCroppingActivity.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.image_cropping;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.codeforvictory.superimageview.samples.superimageview.R;
6 | import com.codeforvictory.superimageview.samples.superimageview.shared.ImageLocalDataSource;
7 | import androidx.appcompat.app.AppCompatActivity;
8 | import androidx.viewpager.widget.ViewPager;
9 |
10 | public final class ImageCroppingActivity extends AppCompatActivity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_image_cropping);
16 | ((ViewPager) findViewById(R.id.cropped_images)).setAdapter(new ImagesPagerAdapter(ImageLocalDataSource.localImages()));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/image_cropping/ImagesPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.image_cropping;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import android.widget.TextView;
8 |
9 | import com.codeforvictory.android.superimageview.SuperImageView;
10 | import com.codeforvictory.android.superimageview.crop.CropType;
11 | import com.codeforvictory.android.superimageview.crop.CroppedImage;
12 | import com.codeforvictory.superimageview.samples.superimageview.R;
13 | import com.codeforvictory.superimageview.samples.superimageview.shared.LocalImage;
14 |
15 | import java.util.List;
16 | import java.util.Objects;
17 |
18 | import androidx.annotation.NonNull;
19 | import androidx.core.content.ContextCompat;
20 | import androidx.viewpager.widget.PagerAdapter;
21 |
22 | final class ImagesPagerAdapter extends PagerAdapter {
23 |
24 | private final List localImages;
25 |
26 | ImagesPagerAdapter(List localImages) {
27 | this.localImages = localImages;
28 | }
29 |
30 | @NonNull
31 | @Override
32 | public Object instantiateItem(ViewGroup container, int position) {
33 | View view = LayoutInflater.from(container.getContext()).inflate(R.layout.item_local_image, container, false);
34 |
35 | LocalImage localImage = localImages.get(position);
36 |
37 | int cropType = localImage.getCropType();
38 | if (cropType == CropType.NONE) {
39 | ((ImageView) view.findViewById(R.id.image)).setScaleType(ImageView.ScaleType.FIT_CENTER);
40 | ((ImageView) view.findViewById(R.id.image)).setImageDrawable(
41 | ContextCompat.getDrawable(container.getContext(), localImage.getDrawableResource())
42 | );
43 | } else {
44 | SuperImageView superImageView = view.findViewById(R.id.image);
45 | Objects.requireNonNull(superImageView.getFeature(CroppedImage.class)).setCropType(cropType);
46 | superImageView.setImageDrawable(
47 | ContextCompat.getDrawable(container.getContext(), localImage.getDrawableResource())
48 | );
49 | }
50 |
51 | ((TextView) view.findViewById(R.id.crop_type)).setText(localImage.getTitle());
52 |
53 | container.addView(view);
54 | return view;
55 | }
56 |
57 | @Override
58 | public void destroyItem(ViewGroup container, int position, Object object) {
59 | container.removeView((View) object);
60 | }
61 |
62 | @Override
63 | public int getCount() {
64 | return localImages.size();
65 | }
66 |
67 | @Override
68 | public boolean isViewFromObject(View view, Object object) {
69 | return view == object;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/image_cropping/ImagesRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.image_cropping;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import com.bumptech.glide.Glide;
7 | import com.codeforvictory.android.superimageview.SuperImageView;
8 | import com.codeforvictory.android.superimageview.crop.CroppedImage;
9 | import com.codeforvictory.superimageview.samples.superimageview.R;
10 | import com.codeforvictory.superimageview.samples.superimageview.shared.NetworkImage;
11 | import java.util.List;
12 | import java.util.Objects;
13 | import androidx.annotation.NonNull;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | final class ImagesRecyclerAdapter extends RecyclerView.Adapter {
17 |
18 | private final List networkImages;
19 |
20 | ImagesRecyclerAdapter(List networkImages) {
21 | this.networkImages = networkImages;
22 | }
23 |
24 | @NonNull
25 | @Override
26 | public ItemImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
27 | return new ItemImageViewHolder(LayoutInflater.from(
28 | parent.getContext()).inflate(R.layout.item_network_cropped_image, parent, false)
29 | );
30 | }
31 |
32 | @Override
33 | public void onBindViewHolder(@NonNull ItemImageViewHolder holder, int position) {
34 | holder.bind(networkImages.get(position));
35 | }
36 |
37 | @Override
38 | public int getItemCount() {
39 | return networkImages.size();
40 | }
41 |
42 | static final class ItemImageViewHolder extends RecyclerView.ViewHolder {
43 |
44 | private final SuperImageView superImageView;
45 |
46 | ItemImageViewHolder(@NonNull View itemView) {
47 | super(itemView);
48 | this.superImageView = (SuperImageView) itemView;
49 | }
50 |
51 | void bind(NetworkImage networkImage) {
52 | Objects.requireNonNull(superImageView.getFeature(CroppedImage.class)).setCropType(networkImage.cropType());
53 | Glide.with(itemView.getContext()).load(networkImage.imageUrl()).into(superImageView);
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/image_cropping/NetworkImageCroppingActivity.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.image_cropping;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.codeforvictory.superimageview.samples.superimageview.R;
6 | import com.codeforvictory.superimageview.samples.superimageview.shared.ImageLocalDataSource;
7 | import com.codeforvictory.superimageview.samples.superimageview.shared.widget.VerticalTransparentItemDecorator;
8 |
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | public final class NetworkImageCroppingActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_images);
18 | setupViews();
19 | }
20 |
21 | private void setupViews() {
22 | RecyclerView images = findViewById(R.id.images);
23 | images.addItemDecoration(new VerticalTransparentItemDecorator(getResources().getDimensionPixelOffset(R.dimen.activity_horizontal_margin)));
24 | images.setAdapter(new ImagesRecyclerAdapter(ImageLocalDataSource.networkImages()));
25 | }
26 | }
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/rounded_corners/Image.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.rounded_corners;
2 |
3 | import com.codeforvictory.android.superimageview.crop.CropType;
4 |
5 | import androidx.annotation.DrawableRes;
6 |
7 | final class Image {
8 |
9 | @DrawableRes private final int drawableResource;
10 | private final boolean roundedCorners;
11 | @CropType private final int cropType;
12 |
13 | Image(@DrawableRes int drawableResource, boolean roundedCorners, int cropType) {
14 | this.drawableResource = drawableResource;
15 | this.roundedCorners = roundedCorners;
16 | this.cropType = cropType;
17 | }
18 |
19 | public int drawableResource() {
20 | return drawableResource;
21 | }
22 |
23 | public boolean roundedCorners() {
24 | return roundedCorners;
25 | }
26 |
27 | public int cropType() {
28 | return cropType;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/rounded_corners/ImageFactory.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.rounded_corners;
2 |
3 | import com.codeforvictory.android.superimageview.crop.CropType;
4 | import com.codeforvictory.superimageview.samples.superimageview.R;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | public final class ImageFactory {
10 |
11 | private ImageFactory() {
12 | throw new AssertionError("This shouldn't be initialized!");
13 | }
14 |
15 | public static List imagesWithoutRoundedCorners() {
16 | return Arrays.asList(
17 | // new Image(R.drawable.ball_vertical, false, CropType.NONE),
18 | // new Image(R.drawable.ball_horizontal, false, CropType.NONE),
19 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
20 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
21 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
22 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
23 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
24 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
25 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
26 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT),
27 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
28 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
29 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
30 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
31 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
32 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
33 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
34 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT),
35 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
36 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
37 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
38 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
39 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
40 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
41 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
42 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT),
43 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
44 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
45 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
46 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
47 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
48 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
49 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
50 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT)
51 | );
52 | }
53 |
54 | public static List imagesWithRoundedCorners() {
55 | return Arrays.asList(
56 | // new Image(R.drawable.ball_vertical, false, CropType.NONE),
57 | // new Image(R.drawable.ball_horizontal, false, CropType.NONE),
58 | new Image(R.drawable.ball_vertical, true, CropType.TOP),
59 | new Image(R.drawable.ball_vertical, true, CropType.BOTTOM),
60 | new Image(R.drawable.ball_horizontal, true, CropType.TOP_LEFT),
61 | new Image(R.drawable.ball_horizontal, true, CropType.LEFT),
62 | new Image(R.drawable.ball_horizontal, true, CropType.BOTTOM_LEFT),
63 | new Image(R.drawable.ball_horizontal, true, CropType.TOP_RIGHT),
64 | new Image(R.drawable.ball_horizontal, true, CropType.BOTTOM_RIGHT),
65 | new Image(R.drawable.ball_horizontal, true, CropType.RIGHT),
66 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
67 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
68 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
69 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
70 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
71 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
72 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
73 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT),
74 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
75 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
76 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
77 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
78 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
79 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
80 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
81 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT),
82 | new Image(R.drawable.ball_vertical, false, CropType.TOP),
83 | new Image(R.drawable.ball_vertical, false, CropType.BOTTOM),
84 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_LEFT),
85 | new Image(R.drawable.ball_horizontal, false, CropType.LEFT),
86 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_LEFT),
87 | new Image(R.drawable.ball_horizontal, false, CropType.TOP_RIGHT),
88 | new Image(R.drawable.ball_horizontal, false, CropType.BOTTOM_RIGHT),
89 | new Image(R.drawable.ball_horizontal, false, CropType.RIGHT)
90 | );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/rounded_corners/ImagesRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.rounded_corners;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | import com.bumptech.glide.Glide;
8 | import com.codeforvictory.android.superimageview.SuperImageView;
9 | import com.codeforvictory.superimageview.samples.superimageview.R;
10 | import com.codeforvictory.superimageview.samples.superimageview.shared.NetworkImage;
11 | import java.util.List;
12 | import androidx.annotation.NonNull;
13 | import androidx.recyclerview.widget.RecyclerView;
14 |
15 | final class ImagesRecyclerAdapter extends RecyclerView.Adapter {
16 |
17 | private final List networkImages;
18 |
19 | ImagesRecyclerAdapter(List networkImages) {
20 | this.networkImages = networkImages;
21 | }
22 |
23 | @NonNull
24 | @Override
25 | public ItemImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
26 | return new ImagesRecyclerAdapter.ItemImageViewHolder(LayoutInflater.from(
27 | parent.getContext()).inflate(R.layout.item_network_rounded_image, parent, false)
28 | );
29 | }
30 |
31 | @Override
32 | public void onBindViewHolder(@NonNull ItemImageViewHolder holder, int position) {
33 | holder.bind(networkImages.get(position));
34 | }
35 |
36 | @Override
37 | public int getItemCount() {
38 | return networkImages.size();
39 | }
40 |
41 | static final class ItemImageViewHolder extends RecyclerView.ViewHolder {
42 |
43 | private final SuperImageView superImageView;
44 |
45 | ItemImageViewHolder(@NonNull View itemView) {
46 | super(itemView);
47 | this.superImageView = (SuperImageView) itemView;
48 | }
49 |
50 | void bind(NetworkImage networkImage) {
51 | Glide.with(itemView.getContext()).load(networkImage.imageUrl()).into(superImageView);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/rounded_corners/RoundedCornerImagesActivity.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.rounded_corners;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.codeforvictory.superimageview.samples.superimageview.R;
6 | import com.codeforvictory.superimageview.samples.superimageview.shared.ImageLocalDataSource;
7 | import com.codeforvictory.superimageview.samples.superimageview.shared.widget.VerticalTransparentItemDecorator;
8 | import androidx.appcompat.app.AppCompatActivity;
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 | public final class RoundedCornerImagesActivity extends AppCompatActivity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_images);
17 | setupViews();
18 | }
19 |
20 | private void setupViews() {
21 | RecyclerView images = findViewById(R.id.images);
22 | images.addItemDecoration(new VerticalTransparentItemDecorator(getResources().getDimensionPixelOffset(R.dimen.activity_horizontal_margin)));
23 | images.setAdapter(new ImagesRecyclerAdapter(ImageLocalDataSource.networkImages()));
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/shared/ImageLocalDataSource.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.shared;
2 |
3 | import com.codeforvictory.android.superimageview.crop.CropType;
4 | import com.codeforvictory.superimageview.samples.superimageview.R;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | public final class ImageLocalDataSource {
10 |
11 | private ImageLocalDataSource() {
12 | throw new AssertionError("This shouldn't be initialized!");
13 | }
14 |
15 | private static final LocalImage[] localImages = {
16 | new LocalImage(CropType.NONE, "Original horizontal image", R.drawable.ball_horizontal),
17 | new LocalImage(CropType.NONE, "Original vertical image", R.drawable.ball_vertical),
18 | new LocalImage(CropType.TOP_LEFT, "Left Top crop of the horizontal image", R.drawable.ball_horizontal),
19 | new LocalImage(CropType.TOP, "Center Top crop of the vertical image", R.drawable.ball_vertical),
20 | new LocalImage(CropType.TOP_RIGHT, "Right Top crop of the horizontal image", R.drawable.ball_horizontal),
21 | new LocalImage(CropType.LEFT, "Left Center crop of the horizontal image", R.drawable.ball_horizontal),
22 | new LocalImage(CropType.RIGHT, "Right Center crop of the horizontal image", R.drawable.ball_horizontal),
23 | new LocalImage(CropType.BOTTOM_LEFT, "Left Bottom crop of the horizontal image", R.drawable.ball_horizontal),
24 | new LocalImage(CropType.BOTTOM, "Center Bottom crop of the vertical image", R.drawable.ball_vertical),
25 | new LocalImage(CropType.BOTTOM_RIGHT, "Right Bottom crop of the horizontal image", R.drawable.ball_horizontal),
26 | };
27 |
28 | private static final NetworkImage[] networkImages = {
29 | // Provided by https://unsplash.com
30 | new NetworkImage(
31 | CropType.NONE,
32 | "Original image (vertical)",
33 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
34 | ),
35 | new NetworkImage(
36 | CropType.TOP,
37 | "Top crop of the original image",
38 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
39 | ),
40 | new NetworkImage(
41 | CropType.RIGHT,
42 | "Right crop of the original image",
43 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
44 | ),
45 | new NetworkImage(
46 | CropType.BOTTOM,
47 | "Bottom crop of the original image",
48 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
49 | ),
50 | new NetworkImage(
51 | CropType.LEFT,
52 | "Left crop of the original image",
53 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
54 | ),
55 | new NetworkImage(
56 | CropType.TOP_LEFT,
57 | "Top left crop of the original image",
58 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
59 | ),
60 | new NetworkImage(
61 | CropType.TOP_RIGHT,
62 | "Top right crop of the original image",
63 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
64 | ),
65 | new NetworkImage(
66 | CropType.BOTTOM_RIGHT,
67 | "Bottom right crop of the original image",
68 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
69 | ),
70 | new NetworkImage(
71 | CropType.BOTTOM_LEFT,
72 | "Bottom left crop of the original image",
73 | "https://images.unsplash.com/photo-1512061203001-0c4d837c6882?w=600"
74 | ),
75 | new NetworkImage(
76 | CropType.NONE,
77 | "Original image (horizontal)",
78 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
79 | ),
80 | new NetworkImage(
81 | CropType.TOP,
82 | "Top crop of the original image",
83 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
84 | ),
85 | new NetworkImage(
86 | CropType.RIGHT,
87 | "Right crop of the original image",
88 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
89 | ),
90 | new NetworkImage(
91 | CropType.BOTTOM,
92 | "Bottom crop of the original image",
93 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
94 | ),
95 | new NetworkImage(
96 | CropType.LEFT,
97 | "Left crop of the original image",
98 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
99 | ),
100 | new NetworkImage(
101 | CropType.TOP_LEFT,
102 | "Top left crop of the original image",
103 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
104 | ),
105 | new NetworkImage(
106 | CropType.TOP_RIGHT,
107 | "Top right crop of the original image",
108 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
109 | ),
110 | new NetworkImage(
111 | CropType.BOTTOM_RIGHT,
112 | "Bottom right crop of the original image",
113 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
114 | ),
115 | new NetworkImage(
116 | CropType.BOTTOM_LEFT,
117 | "Bottom left crop of the original image",
118 | "https://images.pexels.com/photos/161798/stonehenge-architecture-history-monolith-161798.jpeg?auto=compress&h=400"
119 | ),
120 | };
121 |
122 | public static List localImages() {
123 | return Arrays.asList(localImages);
124 | }
125 |
126 | public static List networkImages() {
127 | return Arrays.asList(networkImages);
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/shared/LocalImage.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.shared;
2 |
3 | import com.codeforvictory.android.superimageview.crop.CropType;
4 |
5 | import androidx.annotation.DrawableRes;
6 |
7 | public final class LocalImage {
8 |
9 | @CropType private final int cropType;
10 | private final String title;
11 | @DrawableRes private final int drawableResource;
12 |
13 | LocalImage(@CropType int cropType, String title, @DrawableRes int drawableResource) {
14 | this.cropType = cropType;
15 | this.title = title;
16 | this.drawableResource = drawableResource;
17 | }
18 |
19 | @CropType
20 | public int getCropType() {
21 | return cropType;
22 | }
23 |
24 | public String getTitle() {
25 | return title;
26 | }
27 |
28 | @DrawableRes
29 | public int getDrawableResource() {
30 | return drawableResource;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/shared/NetworkImage.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.shared;
2 |
3 | import com.codeforvictory.android.superimageview.crop.CropType;
4 |
5 | public final class NetworkImage {
6 |
7 | @CropType private final int cropType;
8 | private final String title;
9 | private final String imageUrl;
10 |
11 | NetworkImage(@CropType int cropType, String title, String imageUrl) {
12 | this.cropType = cropType;
13 | this.title = title;
14 | this.imageUrl = imageUrl;
15 | }
16 |
17 | @CropType
18 | public int cropType() {
19 | return cropType;
20 | }
21 |
22 | public String title() {
23 | return title;
24 | }
25 |
26 | public String imageUrl() {
27 | return imageUrl;
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/samples/src/main/java/com/codeforvictory/superimageview/samples/superimageview/shared/widget/VerticalTransparentItemDecorator.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.superimageview.samples.superimageview.shared.widget;
2 |
3 | import android.graphics.Rect;
4 | import android.view.View;
5 |
6 | import androidx.recyclerview.widget.RecyclerView;
7 |
8 | public final class VerticalTransparentItemDecorator extends RecyclerView.ItemDecoration {
9 |
10 | private int space;
11 |
12 | public VerticalTransparentItemDecorator(int value) {
13 | this.space = value;
14 | }
15 |
16 | @Override
17 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
18 | // Skip first item in the list.
19 | if (parent.getChildAdapterPosition(view) != 0) {
20 | outRect.set(0, space, 0, 0);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ball_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/drawable-xxhdpi/ball_horizontal.png
--------------------------------------------------------------------------------
/samples/src/main/res/drawable-xxhdpi/ball_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/drawable-xxhdpi/ball_vertical.png
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
29 |
30 |
39 |
40 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_image_cropping.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/activity_images.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/item_local_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
26 |
27 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/item_network_cropped_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/samples/src/main/res/layout/item_network_rounded_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/samples/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/samples/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/samples/src/main/res/values-v19/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #AB000000
5 |
6 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 |
5 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SuperImageView Samples
4 | Image Cropping
5 | Image Cropping From Network
6 | Rounded Corners
7 | Rounded Corners with Image Cropping
8 |
9 |
--------------------------------------------------------------------------------
/samples/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':superimageview', ':samples', ':superimageview-imagecrop', ':superimageview-roundedcorners'
2 |
--------------------------------------------------------------------------------
/superimageview-imagecrop/CHANGELOG.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/superimageview-imagecrop/CHANGELOG.md
--------------------------------------------------------------------------------
/superimageview-imagecrop/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | resourcePrefix 'siv_'
5 |
6 | compileSdkVersion versions.compileSdk
7 |
8 | defaultConfig {
9 | minSdkVersion versions.minSdk
10 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // Espresso
11 | }
12 | }
13 |
14 | apply from: rootProject.file('gradle/maven-deployment.gradle')
15 | apply from: rootProject.file('gradle/code-quality-android.gradle')
16 |
17 | dependencies {
18 | implementation 'androidx.annotation:annotation:1.0.0'
19 | implementation 'androidx.appcompat:appcompat:1.0.0'
20 | api project(':superimageview')
21 |
22 | testImplementation 'junit:junit:4.12'
23 | testImplementation 'org.assertj:assertj-core:3.11.1'
24 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
25 | androidTestImplementation 'androidx.test:rules:1.1.0-alpha4'
26 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
27 | }
--------------------------------------------------------------------------------
/superimageview-imagecrop/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=superimageview-imagecrop
2 | POM_NAME=SuperImageView image crop
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/superimageview-imagecrop/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/superimageview-imagecrop/src/main/java/com/codeforvictory/android/superimageview/crop/CropType.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.crop;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import androidx.annotation.IntDef;
7 |
8 | /**
9 | * Options for cropping the bounds of an image to the bounds of the ImageView.
10 | */
11 | @Retention(RetentionPolicy.SOURCE)
12 | @IntDef({
13 | CropType.NONE,
14 | CropType.TOP_LEFT,
15 | CropType.TOP_RIGHT,
16 | CropType.BOTTOM_LEFT,
17 | CropType.BOTTOM_RIGHT,
18 | CropType.LEFT,
19 | CropType.TOP,
20 | CropType.RIGHT,
21 | CropType.BOTTOM,
22 | })
23 | public @interface CropType {
24 | int NONE = -1;
25 | int TOP_LEFT = 0;
26 | int LEFT = 1;
27 | int BOTTOM_LEFT = 2;
28 | int TOP_RIGHT = 3;
29 | int RIGHT = 4;
30 | int BOTTOM_RIGHT = 5;
31 | int TOP = 6;
32 | int BOTTOM = 7;
33 | }
--------------------------------------------------------------------------------
/superimageview-imagecrop/src/main/java/com/codeforvictory/android/superimageview/crop/CroppedImage.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.crop;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 | import android.widget.ImageView;
7 |
8 | import com.codeforvictory.android.superimageview.Crop;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 |
13 | public final class CroppedImage implements Crop {
14 |
15 | @CropType private int cropType = CropType.NONE;
16 | private final ImageTransformation imageTransformation;
17 | private final View view;
18 |
19 | public CroppedImage(View view) {
20 | this.view = view;
21 | imageTransformation = new ImageTransformation(view);
22 | }
23 |
24 | /**
25 | * Set crop type for the {@link ImageView}
26 | *
27 | * @param cropType A {@link CropType} desired scaling mode.
28 | */
29 | public void setCropType(@CropType int cropType) {
30 | if (cropType == this.cropType) {
31 | return;
32 | }
33 |
34 | this.cropType = cropType;
35 | setupScaleType();
36 | }
37 |
38 | /**
39 | * Return the current crop type in use by this ImageView.
40 | *
41 | * @return a {@link CropType} in use by this ImageView
42 | */
43 | @CropType
44 | public int getCropType() {
45 | return cropType;
46 | }
47 |
48 | //
49 | // public void crop(@CropType int cropType) {
50 | // withCropType(cropType);
51 | // cropImageView.requestLayout();
52 | // cropImageView.invalidate();
53 | // }
54 | //
55 | //
56 |
57 | @Override
58 | public void setup(@NonNull Context context, @Nullable AttributeSet attributeSet) {
59 | if (attributeSet == null) {
60 | return;
61 | }
62 |
63 | final TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.siv_ImageCrop);
64 | cropType = a.getInt(R.styleable.siv_SuperImageView_siv_cropImplementation, CropType.NONE);
65 | a.recycle();
66 |
67 | setupScaleType();
68 | }
69 |
70 | @Override
71 | public void onScaleTypeChanged(ImageView.ScaleType scaleType) {
72 | if (scaleType != ImageView.ScaleType.MATRIX) {
73 | cropType = CropType.NONE;
74 | }
75 | }
76 |
77 | @Override
78 | public void onFrameChanged() {
79 | if (!view.isInEditMode() && view.getDrawable() != null && cropType != CropType.NONE) {
80 | imageTransformation.compute(cropType);
81 | }
82 | }
83 |
84 | private void setupScaleType() {
85 | if (cropType != CropType.NONE) {
86 | view.setScaleType(ImageView.ScaleType.MATRIX);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/superimageview-imagecrop/src/main/java/com/codeforvictory/android/superimageview/crop/ImageTransformation.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.crop;
2 |
3 | import android.graphics.Matrix;
4 | import android.graphics.drawable.Drawable;
5 | import android.os.Build;
6 |
7 | import com.codeforvictory.android.superimageview.Crop;
8 | import com.codeforvictory.android.superimageview.crop.error.IllegalTransformationType;
9 |
10 | import androidx.annotation.Nullable;
11 |
12 | final class ImageTransformation {
13 |
14 | private final Crop.View view;
15 | private final CompatMatrix compatMatrix;
16 |
17 | ImageTransformation(Crop.View view) {
18 | this.view = view;
19 |
20 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
21 | compatMatrix = new PreAPI18Matrix(view);
22 | } else {
23 | compatMatrix = new API18Matrix(view);
24 | }
25 | }
26 |
27 | void compute(@CropType int cropType) {
28 | int viewWidth = view.getWidth() - view.getPaddingLeft() - view.getPaddingRight();
29 | int viewHeight = view.getHeight() - view.getPaddingTop() - view.getPaddingBottom();
30 |
31 | if (cropType != CropType.NONE && viewHeight > 0 && viewWidth > 0) {
32 | Matrix matrix = compatMatrix.matrix(cropType);
33 |
34 | Drawable drawable = view.getDrawable();
35 | int drawableWidth = drawable.getIntrinsicWidth();
36 | int drawableHeight = drawable.getIntrinsicHeight();
37 |
38 | float scaleY = (float) viewHeight / (float) drawableHeight;
39 | float scaleX = (float) viewWidth / (float) drawableWidth;
40 | float scale = scaleX > scaleY ? scaleX : scaleY;
41 | matrix.setScale(scale, scale); // Same as doing matrix.reset() and matrix.preScale(...)
42 |
43 | boolean verticalImageMode = scaleX > scaleY;
44 |
45 | float xTranslation = getXTranslation(
46 | cropType,
47 | viewWidth,
48 | drawableWidth * scale,
49 | verticalImageMode
50 | );
51 | float yTranslation = getYTranslation(
52 | cropType,
53 | viewHeight,
54 | drawableHeight * scale,
55 | verticalImageMode
56 | );
57 |
58 | matrix.postTranslate(xTranslation, yTranslation);
59 | view.setImageMatrix(matrix);
60 | }
61 | }
62 |
63 | // FIXME: 9/19/18 fix this case
64 | private float getYTranslation(
65 | @CropType int cropType,
66 | int viewHeight,
67 | float postDrawableHeight,
68 | boolean verticalImageMode
69 | ) {
70 | if (verticalImageMode) {
71 | switch (cropType) {
72 | case CropType.BOTTOM:
73 | case CropType.BOTTOM_LEFT:
74 | case CropType.BOTTOM_RIGHT:
75 | return viewHeight - postDrawableHeight;
76 | case CropType.LEFT:
77 | case CropType.RIGHT:
78 | // View in the middle of the screen
79 | return (viewHeight - postDrawableHeight) / 2f;
80 | case CropType.TOP:
81 | case CropType.TOP_LEFT:
82 | case CropType.NONE:
83 | case CropType.TOP_RIGHT:
84 | return 0f;
85 | default:
86 | throw new IllegalTransformationType("Transformation not supported. Check if the transformation you want to do should be handled by the method getXTranslation()");
87 |
88 | }
89 | }
90 |
91 | // All other cases we don't need to translate
92 | return 0f;
93 | }
94 |
95 | // FIXME: 9/19/18 fix this case
96 | private float getXTranslation(
97 | @CropType int cropType,
98 | int viewWidth,
99 | float postDrawableWidth,
100 | boolean verticalImageMode
101 | ) {
102 | if (!verticalImageMode) {
103 | switch (cropType) {
104 | case CropType.TOP_RIGHT:
105 | case CropType.RIGHT:
106 | case CropType.BOTTOM_RIGHT:
107 | return viewWidth - postDrawableWidth;
108 | case CropType.TOP:
109 | case CropType.BOTTOM:
110 | // View in the middle of the screen
111 | return (viewWidth - postDrawableWidth) / 2f;
112 | case CropType.BOTTOM_LEFT:
113 | case CropType.LEFT:
114 | case CropType.TOP_LEFT:
115 | case CropType.NONE:
116 | return 0f;
117 | default:
118 | throw new IllegalTransformationType("Transformation not supported. Check if the transformation you want to do should be handled by the method getYTranslation()");
119 |
120 | }
121 | }
122 | // All other cases we don't need to translate
123 | return 0f;
124 | }
125 |
126 |
127 | private static final class PreAPI18Matrix extends CompatMatrix {
128 |
129 | @Nullable private Matrix matrix;
130 |
131 | PreAPI18Matrix(Crop.View view) {
132 | super(view);
133 | }
134 |
135 | @Override
136 | Matrix matrix(int cropType) {
137 | if (cropType != CropType.NONE && matrix == null) {
138 | matrix = new Matrix();
139 | }
140 |
141 | return matrix != null ? matrix : view.getImageMatrix();
142 | }
143 | }
144 |
145 | private static final class API18Matrix extends CompatMatrix {
146 |
147 | API18Matrix(Crop.View view) {
148 | super(view);
149 | }
150 |
151 | @Override
152 | Matrix matrix(int cropType) {
153 | return view.getImageMatrix();
154 | }
155 | }
156 |
157 | static abstract class CompatMatrix {
158 |
159 | final Crop.View view;
160 |
161 | CompatMatrix(Crop.View view) {
162 | this.view = view;
163 | }
164 |
165 | abstract Matrix matrix(@CropType int cropType);
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/superimageview-imagecrop/src/main/java/com/codeforvictory/android/superimageview/crop/error/IllegalTransformationType.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.crop.error;
2 |
3 | public final class IllegalTransformationType extends IllegalStateException {
4 |
5 | public IllegalTransformationType(String s) {
6 | super(s);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/superimageview-imagecrop/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/CHANGELOG.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cesards/SuperImageView/9b161d53bc8642604107b5c848d0614af8f00bb6/superimageview-roundedcorners/CHANGELOG.md
--------------------------------------------------------------------------------
/superimageview-roundedcorners/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | resourcePrefix 'siv_'
5 |
6 | compileSdkVersion versions.compileSdk
7 |
8 | defaultConfig {
9 | minSdkVersion versions.minSdk
10 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // Espresso
11 | }
12 | }
13 |
14 | apply from: rootProject.file('gradle/maven-deployment.gradle')
15 | apply from: rootProject.file('gradle/code-quality-android.gradle')
16 |
17 | dependencies {
18 | implementation 'androidx.annotation:annotation:1.0.0'
19 | implementation 'androidx.appcompat:appcompat:1.0.0'
20 | api project(':superimageview')
21 |
22 | testImplementation 'junit:junit:4.12'
23 | testImplementation 'org.assertj:assertj-core:3.11.1'
24 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
25 | androidTestImplementation 'androidx.test:rules:1.1.0-alpha4'
26 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
27 | }
--------------------------------------------------------------------------------
/superimageview-roundedcorners/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=superimageview-roundedcorners
2 | POM_NAME=SuperImageView rounded corners
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/androidTest/java/com/codeforvictory/roundedcorners/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.roundedcorners;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.InstrumentationRegistry;
6 | import androidx.test.runner.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getTargetContext();
24 |
25 | assertEquals("com.codeforvictory.superimageviewroundedcorners.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/java/com/codeforvictory/android/superimageview/roundedcorners/Corner.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.roundedcorners;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import androidx.annotation.IntDef;
7 |
8 | import static com.codeforvictory.android.superimageview.roundedcorners.Corner.NONE;
9 | import static com.codeforvictory.android.superimageview.roundedcorners.Corner.TOP_LEFT;
10 | import static com.codeforvictory.android.superimageview.roundedcorners.Corner.TOP_RIGHT;
11 | import static com.codeforvictory.android.superimageview.roundedcorners.Corner.BOTTOM_LEFT;
12 | import static com.codeforvictory.android.superimageview.roundedcorners.Corner.BOTTOM_RIGHT;
13 |
14 | /**
15 | * Options for cropping the bounds of an image to the bounds of the ImageView.
16 | */
17 | @Retention(RetentionPolicy.SOURCE)
18 | @IntDef({
19 | NONE,
20 | TOP_LEFT,
21 | TOP_RIGHT,
22 | BOTTOM_LEFT,
23 | BOTTOM_RIGHT,
24 | })
25 | public @interface Corner {
26 | int NONE = -1;
27 | int TOP_LEFT = 0;
28 | int TOP_RIGHT = 1;
29 | int BOTTOM_LEFT = 2;
30 | int BOTTOM_RIGHT = 3;
31 | }
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/java/com/codeforvictory/android/superimageview/roundedcorners/RoundedBitmapViewDrawable.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.roundedcorners;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.ColorFilter;
5 | import android.graphics.PixelFormat;
6 | import android.graphics.drawable.Drawable;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 |
11 | /**
12 | * shows a bitmap as if it had rounded corners. based on :
13 | * http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
14 | * easy alternative from support library: RoundedBitmapDrawableFactory.create( ...) ;
15 | */
16 | //public class RoundedBitmapViewDrawable extends RoundedBitmapDrawable {
17 | class RoundedBitmapViewDrawable extends Drawable {
18 |
19 | @Override
20 | public void draw(@NonNull Canvas canvas) {
21 |
22 | }
23 |
24 | @Override
25 | public void setAlpha(int alpha) {
26 |
27 | }
28 |
29 | @Override
30 | public void setColorFilter(@Nullable ColorFilter colorFilter) {
31 |
32 | }
33 |
34 | @Override
35 | public int getOpacity() {
36 | return PixelFormat.TRANSLUCENT;
37 | }
38 |
39 |
40 |
41 |
42 |
43 |
44 | //
45 | // private final BitmapShader bitmapShader;
46 | // private final Paint p;
47 | // private final RectF rect;
48 | // private final float borderRadius;
49 | //
50 | // public RoundedBitmapViewDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
51 | // super(resources, bitmap);
52 | // bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
53 | // final Bitmap b = getBitmap();
54 | // p = getPaint();
55 | // p.setAntiAlias(true);
56 | // p.setShader(bitmapShader);
57 | // final int w = b.getWidth(), h = b.getHeight();
58 | // rect = new RectF(0, 0, w, h);
59 | // this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
60 | // }
61 | //
62 | // @Override
63 | // public void draw(final Canvas canvas) {
64 | // canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
65 | // }
66 | //
67 |
68 |
69 |
70 |
71 | // private static final float DEFAULT_RADIUS = 0f;
72 | //
73 | // private final RectF bounds = new RectF();
74 | // private final RectF drawableRect = new RectF();
75 | // private final RectF bitmapRect = new RectF();
76 | // private final Bitmap bitmap;
77 | // private final Paint bitmapPaint;
78 | // private final int bitmapWidth;
79 | // private final int bitmapHeight;
80 | // private final Matrix shaderMatrix = new Matrix();
81 | // private final RectF squareCornersRect = new RectF();
82 | // private Shader.TileMode tileModeX = Shader.TileMode.CLAMP;
83 | // private Shader.TileMode tileModeY = Shader.TileMode.CLAMP;
84 | // private boolean mRebuildShader = true;
85 | // private float cornerRadius = 0f;
86 | // private final boolean[] cornerRadiusRounded = new boolean[] { true, true, true, true };
87 | // private ImageView.ScaleType scaleType = ImageView.ScaleType.FIT_CENTER;
88 | //
89 | // public RoundedBitmapViewDrawable(Bitmap bitmap) {
90 | // this.bitmap = bitmap;
91 | //
92 | // bitmapWidth = bitmap.getWidth();
93 | // bitmapHeight = bitmap.getHeight();
94 | // bitmapRect.set(0, 0, bitmapWidth, bitmapHeight);
95 | //
96 | // bitmapPaint = new Paint();
97 | // bitmapPaint.setStyle(Paint.Style.FILL);
98 | // bitmapPaint.setAntiAlias(true);
99 | // }
100 | //
101 | // public static Drawable fromDrawable(Drawable drawable) {
102 | // if (drawable != null) {
103 | // if (drawable instanceof RoundedBitmapViewDrawable) {
104 | // // just return if it's already a RoundedBitmapViewDrawable
105 | // return drawable;
106 | // }
107 | //
108 | // // try to get a bitmap from the drawable and
109 | // Bitmap bm = drawableToBitmap(drawable);
110 | // if (bm != null) {
111 | // return new RoundedBitmapViewDrawable(bm);
112 | // }
113 | // }
114 | // return drawable;
115 | // }
116 | //
117 | // public static RoundedBitmapViewDrawable fromBitmap(Bitmap bitmap) {
118 | // if (bitmap != null) {
119 | // return new RoundedBitmapViewDrawable(bitmap);
120 | // } else {
121 | // return null;
122 | // }
123 | // }
124 | //
125 | // public static Bitmap drawableToBitmap(Drawable drawable) {
126 | // if (drawable instanceof BitmapDrawable) {
127 | // return ((BitmapDrawable) drawable).getBitmap();
128 | // }
129 | //
130 | // Bitmap bitmap;
131 | // int width = Math.max(drawable.getIntrinsicWidth(), 2);
132 | // int height = Math.max(drawable.getIntrinsicHeight(), 2);
133 | // try {
134 | // bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
135 | // Canvas canvas = new Canvas(bitmap);
136 | // drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
137 | // drawable.draw(canvas);
138 | // } catch (Exception e) {
139 | // e.printStackTrace();
140 | // Log.w(RoundedBitmapViewDrawable.class.getSimpleName(), "Failed to create bitmap from drawable!");
141 | // bitmap = null;
142 | // }
143 | //
144 | // return bitmap;
145 | // }
146 | //
147 | //
148 | //
149 | // public Bitmap getSourceBitmap() {
150 | // return bitmap;
151 | // }
152 | //
153 | // /**
154 | // * @return the corner radius.
155 | // */
156 | // public float getCornerRadius() {
157 | // return cornerRadius;
158 | // }
159 | //
160 | // /**
161 | // * @param corner the specific corner to get radius of.
162 | // * @return the corner radius of the specified corner.
163 | // */
164 | // public float getCornerRadius(@Corner int corner) {
165 | // return cornerRadiusRounded[corner] ? cornerRadius : 0f;
166 | // }
167 | //
168 | // /**
169 | // * Sets all corners to the specified radius.
170 | // *
171 | // * @param radius the radius.
172 | // * @return the {@link RoundedBitmapViewDrawable} for chaining.
173 | // */
174 | // public RoundedBitmapViewDrawable setCornerRadius(float radius) {
175 | // setCornerRadius(radius, radius, radius, radius);
176 | // return this;
177 | // }
178 | //
179 | // /**
180 | // * Sets the corner radius of one specific corner.
181 | // *
182 | // * @param corner the corner.
183 | // * @param radius the radius.
184 | // * @return the {@link RoundedBitmapViewDrawable} for chaining.
185 | // */
186 | // public RoundedBitmapViewDrawable setCornerRadius(@Corner int corner, float radius) {
187 | // if (radius != 0 && cornerRadius != 0 && cornerRadius != radius) {
188 | // throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
189 | // }
190 | //
191 | // if (radius == 0) {
192 | // if (only(corner, cornerRadiusRounded)) {
193 | // cornerRadius = 0;
194 | // }
195 | // cornerRadiusRounded[corner] = false;
196 | // } else {
197 | // if (cornerRadius == 0) {
198 | // cornerRadius = radius;
199 | // }
200 | // cornerRadiusRounded[corner] = true;
201 | // }
202 | //
203 | // return this;
204 | // }
205 | //
206 | // /**
207 | // * Sets the corner radii of all the corners.
208 | // *
209 | // * @param topLeft top left corner radius.
210 | // * @param topRight top right corner radius
211 | // * @param bottomRight bototm right corner radius.
212 | // * @param bottomLeft bottom left corner radius.
213 | // * @return the {@link RoundedBitmapViewDrawable} for chaining.
214 | // */
215 | // public RoundedBitmapViewDrawable setCornerRadius(
216 | // float topLeft,
217 | // float topRight,
218 | // float bottomRight,
219 | // float bottomLeft
220 | // ) {
221 | // Set radiusSet = new HashSet<>(4);
222 | // radiusSet.add(topLeft);
223 | // radiusSet.add(topRight);
224 | // radiusSet.add(bottomRight);
225 | // radiusSet.add(bottomLeft);
226 | //
227 | // radiusSet.remove(0f);
228 | //
229 | // if (radiusSet.size() > 1) {
230 | // throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
231 | // }
232 | //
233 | // if (!radiusSet.isEmpty()) {
234 | // float radius = radiusSet.iterator().next();
235 | // if (Float.isInfinite(radius) || Float.isNaN(radius) || radius < 0) {
236 | // throw new IllegalArgumentException("Invalid radius value: " + radius);
237 | // }
238 | // cornerRadius = radius;
239 | // } else {
240 | // cornerRadius = 0f;
241 | // }
242 | //
243 | // cornerRadiusRounded[Corner.TOP_LEFT] = topLeft > 0;
244 | // cornerRadiusRounded[Corner.TOP_RIGHT] = topRight > 0;
245 | // cornerRadiusRounded[Corner.BOTTOM_RIGHT] = bottomRight > 0;
246 | // cornerRadiusRounded[Corner.BOTTOM_LEFT] = bottomLeft > 0;
247 | // return this;
248 | // }
249 | //
250 | // public ImageView.ScaleType getScaleType() {
251 | // return scaleType;
252 | // }
253 | //
254 | // public RoundedBitmapViewDrawable setScaleType(ImageView.ScaleType scaleType) {
255 | // if (scaleType == null) {
256 | // scaleType = ImageView.ScaleType.FIT_CENTER;
257 | // }
258 | // if (this.scaleType != scaleType) {
259 | // this.scaleType = scaleType;
260 | // updateShaderMatrix();
261 | // }
262 | // return this;
263 | // }
264 | //
265 | // public Shader.TileMode getTileModeX() {
266 | // return tileModeX;
267 | // }
268 | //
269 | // public RoundedBitmapViewDrawable setTileModeX(Shader.TileMode tileModeX) {
270 | // if (this.tileModeX != tileModeX) {
271 | // this.tileModeX = tileModeX;
272 | // mRebuildShader = true;
273 | // invalidateSelf();
274 | // }
275 | // return this;
276 | // }
277 | //
278 | // public Shader.TileMode getTileModeY() {
279 | // return tileModeY;
280 | // }
281 | //
282 | // public RoundedBitmapViewDrawable setTileModeY(Shader.TileMode tileModeY) {
283 | // if (this.tileModeY != tileModeY) {
284 | // this.tileModeY = tileModeY;
285 | // mRebuildShader = true;
286 | // invalidateSelf();
287 | // }
288 | // return this;
289 | // }
290 | //
291 | // public Bitmap toBitmap() {
292 | // return drawableToBitmap(this);
293 | // }
294 | //
295 | // @Override
296 | // protected void onBoundsChange(@NonNull Rect bounds) {
297 | // super.onBoundsChange(bounds);
298 | //
299 | // bounds.set(bounds);
300 | //
301 | // updateShaderMatrix();
302 | // }
303 | //
304 | // @Override
305 | // public void draw(@NonNull Canvas canvas) {
306 | //
307 | // }
308 | //
309 | // // @Override
310 | //// public void draw(@NonNull Canvas canvas) {
311 | ////// bitmapPaint.setShader(mShader);
312 | ////// canvas.drawRoundRect(drawableRect, cornerRadius, cornerRadius, bitmapPaint);
313 | //// if (mRebuildShader) {
314 | //// BitmapShader bitmapShader = new BitmapShader(bitmap, tileModeX, tileModeY);
315 | //// if (tileModeX == Shader.TileMode.CLAMP && tileModeY == Shader.TileMode.CLAMP) {
316 | //// bitmapShader.setLocalMatrix(shaderMatrix);
317 | //// }
318 | //// bitmapPaint.setShader(bitmapShader);
319 | //// mRebuildShader = false;
320 | //// }
321 | ////
322 | //// if (any(cornerRadiusRounded)) {
323 | //// float radius = cornerRadius;
324 | //// canvas.drawRoundRect(drawableRect, radius, radius, bitmapPaint);
325 | //// redrawBitmapForSquareCorners(canvas);
326 | //// } else {
327 | //// canvas.drawRect(drawableRect, bitmapPaint);
328 | //// }
329 | //// }
330 | //
331 | // @Override
332 | // public int getAlpha() {
333 | // return bitmapPaint.getAlpha();
334 | // }
335 | //
336 | // @Override
337 | // public void setAlpha(int alpha) {
338 | // bitmapPaint.setAlpha(alpha);
339 | // invalidateSelf();
340 | // }
341 | //
342 | // @Override
343 | // public ColorFilter getColorFilter() {
344 | // return bitmapPaint.getColorFilter();
345 | // }
346 | //
347 | // @Override
348 | // public void setColorFilter(ColorFilter cf) {
349 | // bitmapPaint.setColorFilter(cf);
350 | // invalidateSelf();
351 | // }
352 | //
353 | // @Override
354 | // public void setDither(boolean dither) {
355 | // bitmapPaint.setDither(dither);
356 | // invalidateSelf();
357 | // }
358 | //
359 | // @Override
360 | // public void setFilterBitmap(boolean filter) {
361 | // bitmapPaint.setFilterBitmap(filter);
362 | // invalidateSelf();
363 | // }
364 | //
365 | // @Override
366 | // public int getIntrinsicWidth() {
367 | // return bitmapWidth;
368 | // }
369 | //
370 | // @Override
371 | // public int getIntrinsicHeight() {
372 | // return bitmapHeight;
373 | // }
374 | //
375 | // private void updateShaderMatrix() {
376 | // float scale;
377 | // float dx;
378 | // float dy;
379 | //
380 | // switch (scaleType) {
381 | // case CENTER:
382 | // shaderMatrix.reset();
383 | // shaderMatrix.setTranslate(( bitmapWidth * 0.5f + 0.5f), bitmapHeight * 0.5f + 0.5f);
384 | // break;
385 | //
386 | // case CENTER_CROP:
387 | // break;
388 | //
389 | // case CENTER_INSIDE:
390 | // shaderMatrix.reset();
391 | //
392 | // if (bitmapWidth <= bounds.width() && bitmapHeight <= bounds.height()) {
393 | // scale = 1.0f;
394 | // } else {
395 | // scale = Math.min(bounds.width() / (float) bitmapWidth, bounds.height() / (float) bitmapHeight);
396 | // }
397 | //
398 | // dx = (int) ((bounds.width() - bitmapWidth * scale) * 0.5f + 0.5f);
399 | // dy = (int) ((bounds.height() - bitmapHeight * scale) * 0.5f + 0.5f);
400 | //
401 | // shaderMatrix.setScale(scale, scale);
402 | // shaderMatrix.postTranslate(dx, dy);
403 | // break;
404 | //
405 | // default:
406 | // case FIT_CENTER:
407 | // shaderMatrix.setRectToRect(bitmapRect, bounds, Matrix.ScaleToFit.CENTER);
408 | // break;
409 | //
410 | // case FIT_END:
411 | // shaderMatrix.setRectToRect(bitmapRect, bounds, Matrix.ScaleToFit.END);
412 | // break;
413 | //
414 | // case FIT_START:
415 | // shaderMatrix.setRectToRect(bitmapRect, bounds, Matrix.ScaleToFit.START);
416 | // break;
417 | //
418 | // case FIT_XY:
419 | // shaderMatrix.reset();
420 | // break;
421 | // }
422 | //
423 | // mRebuildShader = true;
424 | // }
425 | //
426 | // private void redrawBitmapForSquareCorners(Canvas canvas) {
427 | // if (all(cornerRadiusRounded)) {
428 | // // no square corners
429 | // return;
430 | // }
431 | //
432 | // if (cornerRadius == 0) {
433 | // return; // no round corners
434 | // }
435 | //
436 | // float left = drawableRect.left;
437 | // float top = drawableRect.top;
438 | // float right = left + drawableRect.width();
439 | // float bottom = top + drawableRect.height();
440 | // float radius = cornerRadius;
441 | //
442 | // if (!cornerRadiusRounded[Corner.TOP_LEFT]) {
443 | // squareCornersRect.set(left, top, left + radius, top + radius);
444 | // canvas.drawRect(squareCornersRect, bitmapPaint );
445 | // }
446 | //
447 | // if (!cornerRadiusRounded[Corner.TOP_RIGHT]) {
448 | // squareCornersRect.set(right - radius, top, right, radius);
449 | // canvas.drawRect(squareCornersRect, bitmapPaint );
450 | // }
451 | //
452 | // if (!cornerRadiusRounded[Corner.BOTTOM_RIGHT]) {
453 | // squareCornersRect.set(right - radius, bottom - radius, right, bottom);
454 | // canvas.drawRect(squareCornersRect, bitmapPaint );
455 | // }
456 | //
457 | // if (!cornerRadiusRounded[Corner.BOTTOM_LEFT]) {
458 | // squareCornersRect.set(left, bottom - radius, left + radius, bottom);
459 | // canvas.drawRect(squareCornersRect, bitmapPaint );
460 | // }
461 | // }
462 | //
463 | // private static boolean only(int index, boolean[] booleans) {
464 | // for (int i = 0, len = booleans.length; i < len; i++) {
465 | // if (booleans[i] != (i == index)) {
466 | // return false;
467 | // }
468 | // }
469 | // return true;
470 | // }
471 | //
472 | // private static boolean any(boolean[] booleans) {
473 | // for (boolean b : booleans) {
474 | // if (b) { return true; }
475 | // }
476 | // return false;
477 | // }
478 | //
479 | // private static boolean all(boolean[] booleans) {
480 | // for (boolean b : booleans) {
481 | // if (b) { return false; }
482 | // }
483 | // return true;
484 | // }
485 | }
486 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/java/com/codeforvictory/android/superimageview/roundedcorners/RoundedCornerImageViewHook.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.roundedcorners;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.drawable.Drawable;
6 | import android.util.AttributeSet;
7 | import android.widget.ImageView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 |
12 | interface RoundedCornerImageViewHook {
13 | void setup(@NonNull Context context, @Nullable AttributeSet attributeSet);
14 |
15 | // void delegateDispatchDraw(Canvas canvas);
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | /**
24 | * Needed for {@link ImageView#setImageDrawable(Drawable)}
25 | * We process the drawable that will be set in the ImageView and we use it as a hook for every
26 | * time {@link ImageView#setImageDrawable(Drawable)} is called
27 | *
28 | * This should be passed to the parent by the ImageView:
29 | * super.setImageDrawable(roundedImage.modifiedDrawable(drawable));
30 | *
31 | *
32 | *
33 | *
34 | */
35 | Drawable modifiedDrawable(Drawable drawable);
36 |
37 | /**
38 | * Usage:
39 | *
40 | * @Override
41 | * public void setImageBitmap(Bitmap bm) {
42 | * super.setImageDrawable(roundedImage.modifiedDrawable(bm));
43 | * }
44 | */
45 | Drawable modifiedDrawable(Bitmap bitmap);
46 |
47 | /**
48 | * Needed for {@link ImageView#drawableStateChanged()}
49 | *
50 | * Usage:
51 | *
52 | * @Override
53 | * protected void drawableStateChanged() {
54 | * super.drawableStateChanged();
55 | * roundedImage.notifyDrawableStateChanges();
56 | * }
57 | */
58 | void notifyDrawableStateChanges();
59 | }
60 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/java/com/codeforvictory/android/superimageview/roundedcorners/RoundedCornersImage.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.roundedcorners;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Path;
8 | import android.graphics.PorterDuff;
9 | import android.graphics.PorterDuffXfermode;
10 | import android.graphics.Rect;
11 | import android.graphics.RectF;
12 | import android.os.Build;
13 | import android.util.AttributeSet;
14 |
15 | import com.codeforvictory.android.superimageview.RoundedCorners;
16 |
17 | import androidx.annotation.NonNull;
18 | import androidx.annotation.Nullable;
19 |
20 | /**
21 | *
22 | *
23 | * The code is a modification of code found in https://github.com/florent37/ShapeOfView
24 | */
25 | public final class RoundedCornersImage implements RoundedCorners {
26 |
27 | private static final float DEFAULT_RADIUS = 0f;
28 |
29 | private final float[] cornerRadius = new float[]{ DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS };
30 | private final View view;
31 | private final Paint clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
32 | private final PorterDuffXfermode pdMode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
33 | private final Path clipPath = new Path();
34 | private final Rect canvasBounds = new Rect();
35 | private final RectF arcBounds = new RectF();
36 |
37 | public RoundedCornersImage(View view) {
38 | this.view = view;
39 | }
40 |
41 | // TODO: 9/8/18 IMPROVE PERFORMANCE: CLIPPATH + LESS MATH INVOLVED (ALLOCATION IS GOOD)
42 | @Override
43 | public void onDraw(Canvas canvas) {
44 | if (canvasBounds.width() != canvas.getWidth() && canvasBounds.height() != canvas.getHeight()) {
45 | canvas.getClipBounds(canvasBounds);
46 |
47 | clipPath.reset();
48 | clipPath.moveTo(canvasBounds.left + cornerRadius[0], canvasBounds.top);
49 |
50 | clipPath.lineTo(canvasBounds.right - cornerRadius[1], canvasBounds.top);
51 | arcBounds.left = canvasBounds.right - cornerRadius[1] * 2f;
52 | arcBounds.top = canvasBounds.top;
53 | arcBounds.right = canvasBounds.right;
54 | arcBounds.bottom = canvasBounds.top + cornerRadius[1] * 2f;
55 | clipPath.arcTo(arcBounds, -90, 90);
56 |
57 | clipPath.lineTo(canvasBounds.right, canvasBounds.bottom - cornerRadius[2]);
58 | arcBounds.left = canvasBounds.right - cornerRadius[2] * 2f;
59 | arcBounds.top = canvasBounds.bottom - cornerRadius[2] * 2f;
60 | arcBounds.right = canvasBounds.right;
61 | arcBounds.bottom = canvasBounds.bottom;
62 | clipPath.arcTo(arcBounds, 0, 90);
63 |
64 | clipPath.lineTo(canvasBounds.left + cornerRadius[3], canvasBounds.bottom);
65 | arcBounds.left = canvasBounds.left;
66 | arcBounds.top = canvasBounds.bottom - cornerRadius[3] * 2f;
67 | arcBounds.right = canvasBounds.left + cornerRadius[3] * 2f;
68 | arcBounds.bottom = canvasBounds.bottom;
69 | clipPath.arcTo(arcBounds, 90, 90);
70 |
71 | clipPath.lineTo(canvasBounds.left, canvasBounds.top + cornerRadius[0]);
72 | arcBounds.left = canvasBounds.left;
73 | arcBounds.top = canvasBounds.top;
74 | arcBounds.right = canvasBounds.left + cornerRadius[0] * 2f;
75 | arcBounds.bottom = canvasBounds.top + cornerRadius[0] * 2f;
76 | clipPath.arcTo(arcBounds, 180, 90);
77 |
78 | clipPath.close();
79 | }
80 |
81 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
82 | canvas.drawPath(clipPath, clipPaint);
83 | } else {
84 | // canvas.drawPath(rectView, clipPaint);
85 | }
86 | }
87 |
88 | @Override
89 | public void onLayoutChanged() {
90 | // handled in onDraw()
91 | }
92 |
93 | @Override
94 | public void setup(@NonNull Context context, @Nullable AttributeSet attributeSet) {
95 | if (attributeSet == null) {
96 | return;
97 | }
98 | final TypedArray a = view.getContext().obtainStyledAttributes(attributeSet, R.styleable.siv_RoundedCorners);
99 | final int corners = a.getDimensionPixelOffset(R.styleable.siv_RoundedCorners_siv_cornerRadius, Corner.NONE);
100 | if (corners != Corner.NONE) {
101 | cornerRadius[Corner.TOP_LEFT] = corners;
102 | cornerRadius[Corner.TOP_RIGHT] = corners;
103 | cornerRadius[Corner.BOTTOM_LEFT] = corners;
104 | cornerRadius[Corner.BOTTOM_RIGHT] = corners;
105 | } else {
106 | cornerRadius[Corner.TOP_LEFT] = a.getDimensionPixelOffset(R.styleable.siv_RoundedCorners_siv_cornerRadiusTopLeft, Corner.NONE);
107 | cornerRadius[Corner.TOP_RIGHT] = a.getDimensionPixelOffset(R.styleable.siv_RoundedCorners_siv_cornerRadiusTopRight, Corner.NONE);
108 | cornerRadius[Corner.BOTTOM_LEFT] = a.getDimensionPixelOffset(R.styleable.siv_RoundedCorners_siv_cornerRadiusBottomLeft, Corner.NONE);
109 | cornerRadius[Corner.BOTTOM_RIGHT] = a.getDimensionPixelOffset(R.styleable.siv_RoundedCorners_siv_cornerRadiusBottomRight, Corner.NONE);
110 | }
111 | a.recycle();
112 |
113 | for (int i = 0, len = this.cornerRadius.length; i < len; i++) {
114 | if (this.cornerRadius[i] < 0) {
115 | throw new IllegalStateException("This can't be possible");
116 | }
117 | }
118 |
119 | clipPaint.setAntiAlias(true);
120 | view.setWillNotDraw(false);
121 |
122 | // TODO: 9/9/18 STUDY WHY THIS IS NECESSARY
123 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
124 | clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
125 | view.setLayerType(android.view.View.LAYER_TYPE_HARDWARE, null);
126 | } else {
127 | clipPaint.setXfermode(pdMode);
128 | view.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/java/com/codeforvictory/android/superimageview/roundedcorners/RoundedCornerss.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview.roundedcorners;
2 |
3 | final class RoundedCornerss {
4 |
5 | // private Drawable backgroundDrawable; //? needed? @Nullable ? @NonNull?
6 | // private Drawable drawable; //? needed? @Nullable ? @NonNull?private boolean mMutateBackground = false;
7 |
8 | /**
9 | * @return the largest corner radius.
10 | */
11 | // public float getCornerRadiuses() {
12 | // return getMaxCornerRadius();
13 | // }
14 |
15 | /**
16 | * @return the largest corner radius.
17 | */
18 | // public float getMaxCornerRadius() {
19 | // float maxRadius = DEFAULT_RADIUS;
20 | // for (int i = cornerRadius.length - 1; i >= 0; i--) {
21 | // maxRadius = Math.max(cornerRadius[i], maxRadius);
22 | // }
23 | // return maxRadius;
24 | // }
25 |
26 | /**
27 | * Get the imageCorner radius of a specified imageCorner.
28 | *
29 | * @param imageCorner the imageCorner.
30 | * @return the radius.
31 | */
32 | // public float getCornerRadius(@Corner int imageCorner) {
33 | // return cornerRadius[imageCorner];
34 | // }
35 |
36 | /**
37 | * Set the corner radii of all corners in px.
38 | *
39 | * @param radius the radius to set.
40 | */
41 | // public void setCornerRadiuses(int radius) {
42 | // setCornerRadius(radius, radius, radius, radius);
43 | // }
44 |
45 | /**
46 | * Set all the corner radii from a dimension resource id.
47 | *
48 | * @param resId dimension resource id of radii.
49 | */
50 | // public void setCornerRadiusDimen(@DimenRes int resId) {
51 | // float radius = imageView.getResources().getDimension(resId);
52 | // setCornerRadius(radius, radius, radius, radius);
53 | // }
54 |
55 | /**
56 | * Set the corner radius of a specific corner from a dimension resource id.
57 | *
58 | * @param corner the corner to set.
59 | * @param resId the dimension resource id of the corner radius.
60 | */
61 | // public void setCornerRadiusDimen(@Corner int corner, @DimenRes int resId) {
62 | // if (corner == Corner.NONE) {
63 | // return;
64 | // }
65 | // setCornerRadius(corner, imageView.getResources().getDimensionPixelSize(resId));
66 | // }
67 |
68 | /**
69 | * Set the corner radii of all corners in px.
70 | *
71 | * @param radius the radius to set.
72 | */
73 | // public void setCornerRadius(float radius) {
74 | // setCornerRadius(radius, radius, radius, radius);
75 | // }
76 |
77 | /**
78 | * Set the corner radius of a specific corner in px.
79 | *
80 | * @param corner the corner to set.
81 | * @param radius the corner radius to set in px.
82 | */
83 | // public void setCornerRadius(@Corner int corner, float radius) {
84 | // if (cornerRadius[corner] == radius) {
85 | // return;
86 | // }
87 | //
88 | // cornerRadius[corner] = radius;
89 | //
90 | // updateDrawableAttrs();
91 | // updateBackgroundDrawableAttrs(false);
92 | // imageView.invalidate();
93 | // }
94 |
95 | /**
96 | * Set the corner radii of each corner individually. Currently only one unique nonzero value is
97 | * supported.
98 | *
99 | // * @param topLeft radius of the top left corner in px.
100 | // * @param topRight radius of the top right corner in px.
101 | // * @param bottomRight radius of the bottom right corner in px.
102 | // * @param bottomLeft radius of the bottom left corner in px.
103 | */
104 | // public void setCornerRadius(float topLeft, float topRight, float bottomLeft, float bottomRight) {
105 | // if (cornerRadius[Corner.TOP_LEFT] == topLeft && cornerRadius[Corner.TOP_RIGHT] == topRight && cornerRadius[Corner.BOTTOM_RIGHT] == bottomRight && cornerRadius[Corner.BOTTOM_LEFT] == bottomLeft) {
106 | // return;
107 | // }
108 | //
109 | // cornerRadius[Corner.TOP_LEFT] = topLeft;
110 | // cornerRadius[Corner.TOP_RIGHT] = topRight;
111 | // cornerRadius[Corner.BOTTOM_LEFT] = bottomLeft;
112 | // cornerRadius[Corner.BOTTOM_RIGHT] = bottomRight;
113 | //
114 | // updateDrawableAttrs();
115 | // updateBackgroundDrawableAttrs(false);
116 | // imageView.invalidate();
117 | // }
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | // @Override
126 | // public Drawable modifiedDrawable(Drawable drawable) {
127 | // this.drawable = SuperDrawable.fromDrawable(drawable);
128 | // updateDrawableAttrs();
129 | // return this.drawable;
130 | // }
131 |
132 | // @Override
133 | // public Drawable modifiedDrawable(Bitmap bitmap) {
134 | //// this.drawable = SuperDrawable.fromBitmap(bitmap);
135 | // updateDrawableAttrs();
136 | // return this.drawable;
137 | // }
138 | //
139 | // @Override
140 | // public void notifyDrawableStateChanges() {
141 | //// imageView.invalidate();
142 | // }
143 |
144 | // @Override
145 | // public void delegateScaleType(ImageView.ScaleType scaleType) {
146 | // // TODO: 8/28/18 CHECK IF REALLY NEEDED
147 | // if (imageView.getScaleType() != scaleType) {
148 | // updateDrawableAttrs();
149 | // updateBackgroundDrawableAttrs(false);
150 | // }
151 | // // parent scaleType invalidates.
152 | // }
153 |
154 | // private void updateDrawableAttrs() {
155 | // updateAttrs(drawable);
156 | // }
157 |
158 | // private void updateAttrs(Drawable drawable) {
159 | // if (drawable == null) { return; }
160 |
161 | // TODO how this can be possible?
162 | // if (drawable instanceof SuperDrawable) {
163 | // ((SuperDrawable) drawable).setCornerRadius(
164 | // cornerRadius[Corner.TOP_LEFT],
165 | // cornerRadius[Corner.TOP_RIGHT],
166 | // cornerRadius[Corner.BOTTOM_LEFT],
167 | // cornerRadius[Corner.BOTTOM_RIGHT]
168 | // );
169 | // }
170 | // }
171 |
172 |
173 |
174 | // private void updateBackgroundDrawableAttrs(boolean convert) {
175 | // if (mutateBackground) {
176 | // if (convert) {
177 | //// backgroundDrawable = SuperDrawable.fromDrawable(backgroundDrawable);
178 | // }
179 | // updateAttrs(backgroundDrawable);
180 | // }
181 | // }
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 | // @Override
192 | // public Drawable delegateSetImageBitmap(Bitmap bm) {
193 | // drawable = SuperDrawable.fromBitmap(bm);
194 | // updateDrawableAttrs();
195 | // imageView.setImageDrawable(this.drawable);
196 | // return drawable;
197 | // }
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | // @Override
207 | // public void setImageBitmap(Bitmap bm) {
208 | //
209 | //
210 | // super.setImageDrawable(drawable);
211 | // }
212 | //
213 | // @Override
214 | // public void setImageResource(@DrawableRes int resId) {
215 | // if (resource != resId) {
216 | // resource = resId;
217 | // drawable = resolveResource();
218 | // updateDrawableAttrs();
219 | // super.setImageDrawable(drawable);
220 | // }
221 | // }
222 | //
223 | // @Override
224 | // public void setImageURI(Uri uri) {
225 | // super.setImageURI(uri);
226 | // setImageDrawable(getDrawable());
227 | // }
228 | //
229 | // private Drawable resolveResource() {
230 | // Resources rsrc = getResources();
231 | // if (rsrc == null) { return null; }
232 | //
233 | // Drawable d = null;
234 | //
235 | // if (resource != 0) {
236 | // try {
237 | // d = rsrc.getDrawable(resource);
238 | // } catch (Exception e) {
239 | // Log.w(TAG, "Unable to find resource: " + resource, e);
240 | // // Don't try again.
241 | // resource = 0;
242 | // }
243 | // }
244 | // return SuperDrawable.fromDrawable(d);
245 | // }
246 | //
247 | // @Override
248 | // public void setBackground(Drawable background) {
249 | // setBackgroundDrawable(background);
250 | // }
251 | //
252 | // @Override
253 | // public void setBackgroundResource(@DrawableRes int resId) {
254 | // if (backgroundResource != resId) {
255 | // backgroundResource = resId;
256 | // backgroundDrawable = resolveBackgroundResource();
257 | // setBackgroundDrawable(backgroundDrawable);
258 | // }
259 | // }
260 | //
261 | // @Override
262 | // public void setBackgroundColor(int color) {
263 | // backgroundDrawable = new ColorDrawable(color);
264 | // setBackgroundDrawable(backgroundDrawable);
265 | // }
266 | //
267 | // private Drawable resolveBackgroundResource() {
268 | // Resources rsrc = getResources();
269 | // if (rsrc == null) { return null; }
270 | //
271 | // Drawable d = null;
272 | //
273 | // if (backgroundResource != 0) {
274 | // try {
275 | // d = rsrc.getDrawable(backgroundResource);
276 | // } catch (Exception e) {
277 | // Log.w(TAG, "Unable to find resource: " + backgroundResource, e);
278 | // // Don't try again.
279 | // backgroundResource = 0;
280 | // }
281 | // }
282 | // return SuperDrawable.fromDrawable(d);
283 | // }
284 | //
285 | // @Override
286 | // @Deprecated
287 | // public void setBackgroundDrawable(Drawable background) {
288 | // backgroundDrawable = background;
289 | // updateBackgroundDrawableAttrs(true);
290 | // //noinspection deprecation
291 | // super.setBackgroundDrawable(backgroundDrawable);
292 | // }
293 |
294 |
295 |
296 | // /**
297 | // * If {@code true}, we will also round the background drawable according to the settings on this
298 | // * ImageView.
299 | // *
300 | // * @return whether the background is mutated.
301 | // */
302 | // public boolean mutatesBackground() {
303 | // return mMutateBackground;
304 | // }
305 | //
306 | // /**
307 | // * Set whether the {@link RoundedImageView} should round the background drawable according to
308 | // * the settings in addition to the source drawable.
309 | // *
310 | // * @param mutate true if this view should mutate the background drawable.
311 | // */
312 | // public void mutateBackground(boolean mutate) {
313 | // if (mMutateBackground == mutate) { return; }
314 | //
315 | // mMutateBackground = mutate;
316 | // updateBackgroundDrawableAttrs(true);
317 | // invalidate();
318 | // }
319 | }
320 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/superimageview-roundedcorners/src/test/java/com/codeforvictory/roundedcorners/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.roundedcorners;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/superimageview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | resourcePrefix 'siv_'
5 |
6 | compileSdkVersion versions.compileSdk
7 |
8 | defaultConfig {
9 | minSdkVersion versions.minSdk
10 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // Espresso
11 | }
12 | }
13 |
14 | apply from: rootProject.file('gradle/maven-deployment.gradle')
15 | apply from: rootProject.file('gradle/code-quality-android.gradle')
16 |
17 | dependencies {
18 | implementation 'androidx.annotation:annotation:1.0.0'
19 | implementation 'androidx.core:core:1.0.0'
20 | implementation 'androidx.appcompat:appcompat:1.0.0'
21 | }
--------------------------------------------------------------------------------
/superimageview/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=superimageview
2 | POM_NAME=SuperImageView
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/superimageview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/superimageview/src/main/java/com/codeforvictory/android/superimageview/Crop.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Matrix;
5 | import android.graphics.drawable.Drawable;
6 | import android.util.AttributeSet;
7 | import android.widget.ImageView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 |
12 | public interface Crop {
13 | void setup(@NonNull Context context, @Nullable AttributeSet attributeSet);
14 | void onScaleTypeChanged(ImageView.ScaleType scaleType);
15 | void onFrameChanged();
16 |
17 | // We shouldn't get COnfiguration because we make the interface based on the implementation, and that can't happen
18 |
19 | interface View {
20 | Drawable getDrawable();
21 | Matrix getImageMatrix();
22 | void setImageMatrix(Matrix matrix);
23 | int getWidth();
24 | int getHeight();
25 | int getPaddingLeft();
26 | int getPaddingRight();
27 | int getPaddingTop();
28 | int getPaddingBottom();
29 | @NonNull Context getContext();
30 | boolean isInEditMode();
31 | void setScaleType(ImageView.ScaleType scaleType);
32 | void requestLayout();
33 | void invalidate();
34 | }
35 |
36 |
37 |
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/superimageview/src/main/java/com/codeforvictory/android/superimageview/RoundedCorners.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.util.AttributeSet;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 |
11 | public interface RoundedCorners {
12 | void setup(@NonNull Context context, @Nullable AttributeSet attributeSet);
13 | void onDraw(Canvas canvas);
14 | void onLayoutChanged();
15 |
16 | interface View {
17 | @NonNull Context getContext();
18 | void setLayerType(int layerType, @Nullable Paint paint);
19 | void setWillNotDraw(boolean willNotDraw);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/superimageview/src/main/java/com/codeforvictory/android/superimageview/SuperImageView.java:
--------------------------------------------------------------------------------
1 | package com.codeforvictory.android.superimageview;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.drawable.Drawable;
10 | import android.text.TextUtils;
11 | import android.util.AttributeSet;
12 | import android.util.Log;
13 |
14 | import java.lang.reflect.Constructor;
15 | import java.lang.reflect.InvocationTargetException;
16 |
17 | import androidx.annotation.NonNull;
18 | import androidx.annotation.Nullable;
19 | import androidx.appcompat.widget.AppCompatImageView;
20 |
21 | public class SuperImageView extends AppCompatImageView {
22 |
23 | @Nullable Class> cropImpl;
24 | @Nullable private Crop crop;
25 | @Nullable private RoundedCorners roundedCorners;
26 |
27 | public SuperImageView(Context context) {
28 | super(context);
29 | setup(context, null);
30 | }
31 |
32 | public SuperImageView(Context context, AttributeSet attrs) {
33 | super(context, attrs, 0);
34 | setup(context, attrs);
35 | }
36 |
37 | public SuperImageView(Context context, AttributeSet attrs, int defStyle) {
38 | super(context, attrs, defStyle);
39 | setup(context, attrs);
40 | }
41 |
42 | @SuppressWarnings("unchecked")
43 | @Nullable
44 | public T getFeature(final Class implementation) {
45 | if (crop != null && crop.getClass() == implementation) {
46 | return ((T) crop);
47 | } else if (roundedCorners != null && roundedCorners.getClass() == implementation) {
48 | return ((T) roundedCorners);
49 | } else {
50 | throw new IllegalStateException("The feature requested has not been initialized yet. Make sure you do.");
51 | }
52 | }
53 |
54 | public void setFeature(final Class implementation) {
55 | // Create new instance of the feature.
56 | }
57 |
58 | @Override
59 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
60 | super.onLayout(changed, left, top, right, bottom);
61 | if (changed && roundedCorners != null) {
62 | roundedCorners.onLayoutChanged();
63 | }
64 | }
65 |
66 | @Override
67 | protected void onDraw(Canvas canvas) {
68 | super.onDraw(canvas);
69 | if (roundedCorners != null) {
70 | roundedCorners.onDraw(canvas);
71 | }
72 | }
73 |
74 | @Override
75 | public void setScaleType(ScaleType scaleType) {
76 | if (crop != null) {
77 | crop.onScaleTypeChanged(scaleType);
78 | }
79 | super.setScaleType(scaleType);
80 | }
81 |
82 | @Override
83 | protected boolean setFrame(int l, int t, int r, int b) {
84 | final boolean changed = super.setFrame(l, t, r, b);
85 | if (changed && crop != null) {
86 | crop.onFrameChanged();
87 | }
88 |
89 | return changed;
90 | }
91 |
92 | private void setup(@NonNull Context context, @Nullable AttributeSet attributeSet) {
93 | if (attributeSet == null) {
94 | return;
95 | }
96 |
97 | @SuppressLint("") final TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.siv_SuperImageView);
98 | setupCrop(a.getString(R.styleable.siv_SuperImageView_siv_cropImplementation), context, attributeSet);
99 | setupRoundedCorners(
100 | a.getString(R.styleable.siv_SuperImageView_siv_roundedCornersImplementation),
101 | context,
102 | attributeSet
103 | );
104 | a.recycle();
105 | }
106 |
107 | private void setupCrop(String cropImplementation, Context context, AttributeSet attributeSet) {
108 | if (TextUtils.isEmpty(cropImplementation)) {
109 | return;
110 | }
111 | cropImplementation = cropImplementation.trim();
112 | if (cropImplementation.isEmpty()) {
113 | return;
114 | }
115 |
116 | try {
117 | // Stupid layoutlib cannot handle simple class loaders.
118 | // ClassLoader classLoader = isInEditMode() ? getClass().getClassLoader() : context.getClassLoader();
119 | // Class> cropClass = classLoader.loadClass(cropImplementation);
120 | // Constructor> constructor = cropClass.getConstructor(CROP_CONSTRUCTOR_SIGNATURE);
121 | // constructor.setAccessible(true);
122 | // Object[] constructorArgs = new Object[]{this};
123 | // this.crop = (Crop) constructor.newInstance(constructorArgs);
124 |
125 | // Class> cl = Class.forName(cropImplementation);
126 | cropImpl = Class.forName(cropImplementation);
127 | Constructor> constructor = cropImpl.getConstructor(Crop.View.class);
128 | Object[] constructorArgs = new Object[]{ new Crop.View() {
129 | @Override
130 | public Drawable getDrawable() {
131 | return SuperImageView.super.getDrawable();
132 | }
133 |
134 | @Override
135 | public Matrix getImageMatrix() {
136 | return SuperImageView.super.getImageMatrix();
137 | }
138 |
139 | @Override
140 | public void setImageMatrix(Matrix matrix) {
141 | SuperImageView.super.setImageMatrix(matrix);
142 | }
143 |
144 | @Override
145 | public int getWidth() {
146 | return SuperImageView.super.getWidth();
147 | }
148 |
149 | @Override
150 | public int getHeight() {
151 | return SuperImageView.super.getHeight();
152 | }
153 |
154 | @Override
155 | public int getPaddingLeft() {
156 | return SuperImageView.super.getPaddingLeft();
157 | }
158 |
159 | @Override
160 | public int getPaddingRight() {
161 | return SuperImageView.super.getPaddingRight();
162 | }
163 |
164 | @Override
165 | public int getPaddingTop() {
166 | return SuperImageView.super.getPaddingTop();
167 | }
168 |
169 | @Override
170 | public int getPaddingBottom() {
171 | return SuperImageView.super.getPaddingBottom();
172 | }
173 |
174 | @NonNull
175 | @Override
176 | public Context getContext() {
177 | return SuperImageView.super.getContext();
178 | }
179 |
180 | @Override
181 | public boolean isInEditMode() {
182 | return SuperImageView.super.isInEditMode();
183 | }
184 |
185 | @Override
186 | public void setScaleType(ScaleType scaleType) {
187 | SuperImageView.super.setScaleType(scaleType);
188 | }
189 |
190 | @Override
191 | public void requestLayout() {
192 | SuperImageView.super.requestLayout();
193 | }
194 |
195 | @Override
196 | public void invalidate() {
197 | SuperImageView.super.invalidate();
198 | }
199 | } };
200 | crop = (Crop) constructor.newInstance(constructorArgs);
201 | // Object o = constructor.newInstance(constructorArgs);
202 | crop.setup(context, attributeSet);
203 |
204 | // Class extends Crop> cropClass = classLoader.loadClass(cropImplementation).asSubclass(Crop.class);
205 | // Constructor extends Crop> constructor = cropClass.getConstructor(LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE);
206 | // Object[] constructorArgs = new Object[]{context, attrs, defStyleAttr, defStyleRes};
207 | // Constructor extends Crop> constructor = cropClass.getConstructor();
208 | } catch (ClassNotFoundException e) {
209 |
210 | } catch (NoSuchMethodException e) {
211 |
212 | } catch (IllegalAccessException e) {
213 |
214 | } catch (InstantiationException e) {
215 |
216 | } catch (InvocationTargetException e) {
217 |
218 | }
219 | // this.crop = (Crop) Class.forName(cropImplementation).newInstance();
220 | }
221 |
222 | private void setupRoundedCorners(String roundedCornersImplementation, Context context, AttributeSet attributeSet) {
223 | if (TextUtils.isEmpty(roundedCornersImplementation)) {
224 | return;
225 | }
226 | roundedCornersImplementation = roundedCornersImplementation.trim();
227 | if (roundedCornersImplementation.isEmpty()) {
228 | return;
229 | }
230 |
231 | try {
232 | Class> cl = Class.forName(roundedCornersImplementation);
233 | Constructor> constructor = cl.getConstructor(RoundedCorners.View.class);
234 | Object[] constructorArgs = new Object[]{ new RoundedCorners.View() {
235 | @NonNull
236 | @Override
237 | public Context getContext() {
238 | return SuperImageView.super.getContext();
239 | }
240 |
241 | @Override
242 | public void setLayerType(int layerType, @Nullable Paint paint) {
243 | SuperImageView.super.setLayerType(layerType, paint);
244 | }
245 |
246 | @Override
247 | public void setWillNotDraw(boolean willNotDraw) {
248 | SuperImageView.super.setWillNotDraw(willNotDraw);
249 | }
250 | } };
251 | roundedCorners = (RoundedCorners) constructor.newInstance(constructorArgs);
252 | roundedCorners.setup(context, attributeSet);
253 | } catch (ClassNotFoundException e) {
254 |
255 | } catch (NoSuchMethodException e) {
256 |
257 | } catch (IllegalAccessException e) {
258 |
259 | } catch (InstantiationException e) {
260 |
261 | } catch (InvocationTargetException e) {
262 |
263 | }
264 | }
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 | @Override
306 | public void setImageDrawable(Drawable drawable) {
307 | Log.d("", "");
308 | super.setImageDrawable(drawable);
309 | // roundedImage.requiresShapeUpdate();
310 |
311 |
312 | // if (drawable instanceof RoundedBitmapDrawable) {
313 | // super.setImageDrawable(drawable);
314 | // return;
315 | // }
316 | // RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(getResources(), ((BitmapDrawable) drawable).getBitmap());
317 | // mBitmapShader = new BitmapShader(dr.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
318 |
319 | // dr.setCornerRadius(10f);
320 | // super.setImageDrawable(dr);
321 | // this.requiersShapeUpdate = true;
322 | // super.setImageDrawable(drawable);
323 | // postInvalidate();
324 | }
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 | // @Override
336 | // public void setImageBitmap(Bitmap bm) {
337 | // super.setImageDrawable(roundedImage.modifiedDrawable(bm));
338 | // // I think it would be better not to modify this method because we are breaking Liskov principle?
339 | // // so we could use Bitmap modifiedBitmap(Bitmap bitmap);
340 | // // as
341 | // // super.setImageBitmap(roundedImage.modifiedBitmap(bm));
342 | // bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
343 | // }
344 | //
345 |
346 |
347 |
348 |
349 |
350 | }
351 |
--------------------------------------------------------------------------------
/superimageview/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------