From 424dc4e6281a962991e3e462d5b4821980950d0f Mon Sep 17 00:00:00 2001 From: martin seal Date: Fri, 6 Dec 2019 14:56:45 +0000 Subject: [PATCH 01/20] upgraded to android x, fixed the white lines issue --- build.gradle | 14 ++- gradle.properties | 2 + gradle/wrapper/gradle-wrapper.properties | 4 +- multiimageview/build.gradle | 44 ++++--- .../stfalcon/multiimageview/MultiImageView.kt | 116 +++++++++++++----- sample/build.gradle | 18 +-- .../multiimageview/sample/MainActivity.java | 3 +- 7 files changed, 135 insertions(+), 66 deletions(-) diff --git a/build.gradle b/build.gradle index 8e45e2b..c3c6e2f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,30 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.0.5-3' + ext.kotlin_version = '1.3.50' repositories { jcenter() + maven { + url 'https://maven.google.com/' + name 'Google' + } } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.5.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.novoda:bintray-release:0.3.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } + allprojects { repositories { jcenter() + maven { + url 'https://maven.google.com/' + name 'Google' + } } } diff --git a/gradle.properties b/gradle.properties index aac7c9b..9e6fce1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,6 +9,8 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. +android.enableJetifier=true +android.useAndroidX=true org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 04e285f..f1fbaaa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 28 10:00:20 PST 2015 +#Fri Dec 06 12:59:19 GMT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/multiimageview/build.gradle b/multiimageview/build.gradle index ea36db7..d72714d 100644 --- a/multiimageview/build.gradle +++ b/multiimageview/build.gradle @@ -1,18 +1,18 @@ apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' apply plugin: 'com.novoda.bintray-release' +apply plugin: 'kotlin-android' android { - compileSdkVersion 25 - buildToolsVersion "25.0.0" + compileSdkVersion 29 + buildToolsVersion "29.0.2" defaultConfig { minSdkVersion 16 - targetSdkVersion 25 + targetSdkVersion 29 versionCode 1 versionName "0.1" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -25,8 +25,30 @@ android { main.java.srcDirs += 'src/main/kotlin' } } +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.novoda:bintray-release:0.8.1' + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + implementation 'androidx.appcompat:appcompat:1.1.0' + testImplementation 'junit:junit:4.12' + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} +repositories { + mavenCentral() +} publish { + userOrg = 'stfalcon' groupId = 'com.github.stfalcon' artifactId = 'multiimageview' publishVersion = '0.1' @@ -36,15 +58,3 @@ publish { website = 'https://github.com/stfalcon-studio/MultiImageView.git' } -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - compile 'com.android.support:appcompat-v7:25.0.0' - testCompile 'junit:junit:4.12' - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" -} -repositories { - mavenCentral() -} diff --git a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt index 243c0dc..818f53b 100644 --- a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt +++ b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt @@ -23,6 +23,10 @@ import android.media.ThumbnailUtils import android.util.AttributeSet import android.widget.ImageView import java.util.* +import android.graphics.Bitmap +import android.graphics.RectF +import kotlin.math.max + /** * Created by Anton Bevza on 12/22/16. @@ -102,7 +106,8 @@ class MultiImageView(context: Context, attrs: AttributeSet) : ImageView(context, } } -class MultiDrawable(val bitmaps: ArrayList) : Drawable() { +class MultiDrawable(private val bitmaps: ArrayList) : Drawable() { + private val paint = Paint(Paint.ANTI_ALIAS_FLAG) private val items = ArrayList() @@ -111,47 +116,87 @@ class MultiDrawable(val bitmaps: ArrayList) : Drawable() { */ private fun init() { items.clear() - if (bitmaps.size == 1) { - val bitmap = scaleCenterCrop(bitmaps[0], bounds.width(), bounds.height()) - items.add(PhotoItem(bitmap, Rect(0, 0, bounds.width(), bounds.height()))) - } else if (bitmaps.size == 2) { - val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width(), bounds.height() / 2) - val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width(), bounds.height() / 2) - items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width() / 2, bounds.height()))) - items.add(PhotoItem(bitmap2, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height()))) - } else if (bitmaps.size == 3) { - val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width(), bounds.height() / 2) - val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width() / 2, bounds.height() / 2) - val bitmap3 = scaleCenterCrop(bitmaps[2], bounds.width() / 2, bounds.height() / 2) - items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width() / 2, bounds.height()))) - items.add(PhotoItem(bitmap2, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) - items.add(PhotoItem(bitmap3, Rect(bounds.width() / 2, bounds.height() / 2, bounds.width(), bounds.height()))) - } - if (bitmaps.size == 4) { - val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width() / 2, bounds.height() / 2) - val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width() / 2, bounds.height() / 2) - val bitmap3 = scaleCenterCrop(bitmaps[2], bounds.width() / 2, bounds.height() / 2) - val bitmap4 = scaleCenterCrop(bitmaps[3], bounds.width() / 2, bounds.height() / 2) - items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width() / 2, bounds.height() / 2))) - items.add(PhotoItem(bitmap2, Rect(0, bounds.height() / 2, bounds.width() / 2, bounds.height()))) - items.add(PhotoItem(bitmap3, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) - items.add(PhotoItem(bitmap4, Rect(bounds.width() / 2, bounds.height() / 2, bounds.width(), bounds.height()))) + paint.isAntiAlias = true + paint.isFilterBitmap = true + paint.isDither = true + + when { + bitmaps.size == 1 -> { + val bitmap = scaleCenterCrop(bitmaps[0], bounds.width(), bounds.height()) + items.add(PhotoItem(bitmap, Rect(0, 0, bounds.width(), bounds.height()))) + } + bitmaps.size == 2 -> { + val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width() / 2, bounds.height()) + val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width() / 2, bounds.height()) + items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width(), bounds.height()))) + items.add(PhotoItem(bitmap2, Rect(bounds.width() / 2, 0, bounds.width() + bounds.width() / 2, bounds.height()))) + } + bitmaps.size == 3 -> { + val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width() / 2, bounds.height()) + val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width(), bounds.height()) + val bitmap3 = scaleCenterCrop(bitmaps[2], bounds.width(), bounds.height()) + items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width(), bounds.height()))) + items.add(PhotoItem(bitmap2, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) + items.add(PhotoItem(bitmap3, Rect(bounds.width() / 2, bounds.height() / 2, bounds.width(), bounds.height()))) + } + bitmaps.size == 4 -> { + val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width(), bounds.height()) + val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width(), bounds.height()) + val bitmap3 = scaleCenterCrop(bitmaps[2], bounds.width(), bounds.height()) + val bitmap4 = scaleCenterCrop(bitmaps[3], bounds.width(), bounds.height()) + items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width() / 2, bounds.height() / 2))) + items.add(PhotoItem(bitmap2, Rect(0, bounds.height() / 2, bounds.width() / 2, bounds.height()))) + items.add(PhotoItem(bitmap3, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) + items.add(PhotoItem(bitmap4, Rect(bounds.width() / 2, bounds.height() / 2, bounds.width(), bounds.height()))) + } } } - override fun draw(canvas: Canvas?) { - if (canvas != null) { - items.forEach { - canvas.drawBitmap(it.bitmap, bounds, it.position, paint) - } + override fun draw(canvas: Canvas) { + items.forEach { + canvas.drawBitmap(it.bitmap, bounds, it.position, paint) } } /** * scale and center crop image */ - private fun scaleCenterCrop(source: Bitmap, newHeight: Int, newWidth: Int): Bitmap { - return ThumbnailUtils.extractThumbnail(source, newWidth, newHeight) +// private fun scaleCenterCrop(source: Bitmap, newHeight: Int, newWidth: Int): Bitmap { +// return ThumbnailUtils.extractThumbnail(source, newWidth, newHeight) +// } + + + private fun scaleCenterCrop(source: Bitmap, newWidth : Int, newHeight : Int): Bitmap { + val sourceWidth = source.width + val sourceHeight = source.height + + // Compute the scaling factors to fit the new height and width, respectively. + // To cover the final image, the final scaling will be the bigger + // of these two. + val xScale = newWidth.toFloat() / sourceWidth + val yScale = newHeight.toFloat() / sourceHeight + val scale = max(xScale, yScale) + + // Now get the size of the source bitmap when scaled + val scaledWidth = scale * sourceWidth + val scaledHeight = scale * sourceHeight + + // Let's find out the upper left coordinates if the scaled bitmap + // should be centered in the new size give by the parameters + val left = (newWidth - scaledWidth) / 2 + val top = (newHeight - scaledHeight) / 2 + + // The target rectangle for the new, scaled version of the source bitmap will now + // be + val targetRect = RectF(left, top, left + scaledWidth, top + scaledHeight) + + // Finally, we create a new bitmap of the specified size and draw our new, + // scaled bitmap onto it. + val dest = Bitmap.createBitmap(newWidth, newHeight, source.config) + val canvas = Canvas(dest) + canvas.drawBitmap(source, null, targetRect, null) + + return dest } /*** @@ -172,9 +217,12 @@ class MultiDrawable(val bitmaps: ArrayList) : Drawable() { override fun getOpacity() = PixelFormat.TRANSLUCENT - override fun setColorFilter(colorFilter: ColorFilter) { + override fun setColorFilter(colorFilter: ColorFilter?) { paint.colorFilter = colorFilter } + + + //***------------------***// } diff --git a/sample/build.gradle b/sample/build.gradle index 35cf6de..c48a3b6 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,15 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.0" + compileSdkVersion 29 + buildToolsVersion "29.0.2" defaultConfig { applicationId "com.stfalcon.multiimageview.sample" minSdkVersion 16 - targetSdkVersion 25 + targetSdkVersion 29 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -20,11 +20,11 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:appcompat-v7:25.0.0' - testCompile 'junit:junit:4.12' - compile project (':multiimageview') + implementation 'androidx.appcompat:appcompat:1.1.0' +// testImpelementation 'junit:junit:4.12' + implementation project (':multiimageview') } diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java index 885a633..0be1407 100644 --- a/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java @@ -1,11 +1,12 @@ package com.stfalcon.multiimageview.sample; import android.graphics.BitmapFactory; -import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; +import androidx.appcompat.app.AppCompatActivity; + import com.stfalcon.multiimageview.MultiImageView; public class MainActivity extends AppCompatActivity { From bcc738dbf4a491e08ae54872a96eef1d450bcc89 Mon Sep 17 00:00:00 2001 From: martin seal Date: Fri, 6 Dec 2019 15:05:04 +0000 Subject: [PATCH 02/20] added jitpack --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index c3c6e2f..1cbc7a1 100644 --- a/build.gradle +++ b/build.gradle @@ -25,6 +25,7 @@ allprojects { url 'https://maven.google.com/' name 'Google' } + maven { url 'https://jitpack.io' } } } From 432e5e4f81d2010f308dc0a7de01f96cb6664b4e Mon Sep 17 00:00:00 2001 From: martin seal Date: Fri, 6 Dec 2019 15:28:26 +0000 Subject: [PATCH 03/20] rolled back gradle because of an obsolete api in the gradle plugin --- build.gradle | 4 ++-- multiimageview/build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 1cbc7a1..380940f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.3.10' repositories { jcenter() maven { @@ -10,7 +10,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.android.tools.build:gradle:3.2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/multiimageview/build.gradle b/multiimageview/build.gradle index d72714d..6aa5d18 100644 --- a/multiimageview/build.gradle +++ b/multiimageview/build.gradle @@ -53,7 +53,7 @@ publish { artifactId = 'multiimageview' publishVersion = '0.1' desc = 'Library for display a few images in one MultiImageView like avatar of group chat' - licences = ['Apache-2.0'] +// licences = ['Apache-2.0'] uploadName='MultiImageView' website = 'https://github.com/stfalcon-studio/MultiImageView.git' } From 42e52a512edc26f072850bf411e446d823d4ce39 Mon Sep 17 00:00:00 2001 From: martin seal Date: Fri, 6 Dec 2019 15:37:37 +0000 Subject: [PATCH 04/20] rolled back gradle because of an obsolete api in the gradle plugin --- multiimageview/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multiimageview/build.gradle b/multiimageview/build.gradle index 6aa5d18..0454961 100644 --- a/multiimageview/build.gradle +++ b/multiimageview/build.gradle @@ -30,7 +30,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.novoda:bintray-release:0.8.1' + classpath 'com.novoda:bintray-release:0.9' } } From c3194817ec2fc45be6292e5833e51c74beece0be Mon Sep 17 00:00:00 2001 From: martin seal Date: Fri, 6 Dec 2019 16:02:50 +0000 Subject: [PATCH 05/20] rolled back gradle because of an obsolete api in the gradle plugin --- build.gradle | 3 ++- multiimageview/build.gradle | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 380940f..9689590 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ buildscript { ext.kotlin_version = '1.3.10' repositories { + google() jcenter() maven { url 'https://maven.google.com/' @@ -10,7 +11,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' + classpath 'com.android.tools.build:gradle:3.5.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/multiimageview/build.gradle b/multiimageview/build.gradle index 0454961..fef29c5 100644 --- a/multiimageview/build.gradle +++ b/multiimageview/build.gradle @@ -30,7 +30,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.novoda:bintray-release:0.9' + classpath 'com.novoda:bintray-release:0.9.1' } } From 9ccc268395bcf4a566e837bb57e9f77a39b4996d Mon Sep 17 00:00:00 2001 From: martin seal Date: Sun, 22 Dec 2019 12:34:27 +0000 Subject: [PATCH 06/20] changed order of bitmaps to a more predictable order, 1 = center, 2 = left then right, 3 = left then top right then bottom right, 4 = top left then top right then bottom left then bottom right --- .../main/java/com/stfalcon/multiimageview/MultiImageView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt index 818f53b..78dd02e 100644 --- a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt +++ b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt @@ -145,8 +145,8 @@ class MultiDrawable(private val bitmaps: ArrayList) : Drawable() { val bitmap3 = scaleCenterCrop(bitmaps[2], bounds.width(), bounds.height()) val bitmap4 = scaleCenterCrop(bitmaps[3], bounds.width(), bounds.height()) items.add(PhotoItem(bitmap1, Rect(0, 0, bounds.width() / 2, bounds.height() / 2))) - items.add(PhotoItem(bitmap2, Rect(0, bounds.height() / 2, bounds.width() / 2, bounds.height()))) - items.add(PhotoItem(bitmap3, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) + items.add(PhotoItem(bitmap3, Rect(0, bounds.height() / 2, bounds.width() / 2, bounds.height()))) + items.add(PhotoItem(bitmap2, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) items.add(PhotoItem(bitmap4, Rect(bounds.width() / 2, bounds.height() / 2, bounds.width(), bounds.height()))) } } From 50afabd6caf3e056d4b347502e5139a6696cfa60 Mon Sep 17 00:00:00 2001 From: martin seal Date: Thu, 20 Feb 2020 16:24:01 +0000 Subject: [PATCH 07/20] added a new example to showcase some of the shortcomings of the multiimageview added 2 new methods one for add all which isnt tested and one for getting the bitmap count for better debugging --- build.gradle | 3 +- multiimageview/build.gradle | 1 + .../stfalcon/multiimageview/MultiImageView.kt | 23 ++- sample/build.gradle | 21 +++ .../multiimageview/sample/MainActivity.java | 62 ++------ .../multiimageview/sample/MainFragment.java | 95 ++++++++++++ .../sample/PreviewFragment.java | 87 +++++++++++ .../sample/RecyclerViewExample.java | 146 ++++++++++++++++++ .../adapters/MultiImageViewAdapter.java | 89 +++++++++++ .../view_holders/MyMultiImageViewHolder.java | 32 ++++ .../MultiImageViewItemDecorator.java | 31 ++++ .../sample/glide/MyGlideApp.java | 10 ++ .../sample/helpers/ClickHelper.java | 7 + .../sample/models/MultiImageViewModel.java | 64 ++++++++ sample/src/main/res/layout/activity_main.xml | 31 +--- sample/src/main/res/layout/fragment_main.xml | 55 +++++++ sample/src/main/res/layout/preview_layout.xml | 22 +++ .../main/res/layout/recycler_view_layout.xml | 14 ++ sample/src/main/res/layout/view_holder.xml | 11 ++ .../main/res/navigation/main_navigation.xml | 38 +++++ sample/src/main/res/values/dimens.xml | 1 + sample/src/main/res/values/strings.xml | 1 + 22 files changed, 766 insertions(+), 78 deletions(-) create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/MainFragment.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/PreviewFragment.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/RecyclerViewExample.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/MultiImageViewAdapter.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/decorator/MultiImageViewItemDecorator.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/glide/MyGlideApp.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/helpers/ClickHelper.java create mode 100644 sample/src/main/java/com/stfalcon/multiimageview/sample/models/MultiImageViewModel.java create mode 100644 sample/src/main/res/layout/fragment_main.xml create mode 100644 sample/src/main/res/layout/preview_layout.xml create mode 100644 sample/src/main/res/layout/recycler_view_layout.xml create mode 100644 sample/src/main/res/layout/view_holder.xml create mode 100644 sample/src/main/res/navigation/main_navigation.xml diff --git a/build.gradle b/build.gradle index 9689590..330dba2 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,6 @@ buildscript { ext.kotlin_version = '1.3.10' repositories { - google() jcenter() maven { url 'https://maven.google.com/' @@ -13,6 +12,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -22,6 +22,7 @@ buildscript { allprojects { repositories { jcenter() + google() maven { url 'https://maven.google.com/' name 'Google' diff --git a/multiimageview/build.gradle b/multiimageview/build.gradle index fef29c5..e9078a1 100644 --- a/multiimageview/build.gradle +++ b/multiimageview/build.gradle @@ -42,6 +42,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' testImplementation 'junit:junit:4.12' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + } repositories { mavenCentral() diff --git a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt index 78dd02e..a0d9fcf 100644 --- a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt +++ b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt @@ -19,12 +19,9 @@ package com.stfalcon.multiimageview import android.content.Context import android.graphics.* import android.graphics.drawable.Drawable -import android.media.ThumbnailUtils import android.util.AttributeSet import android.widget.ImageView import java.util.* -import android.graphics.Bitmap -import android.graphics.RectF import kotlin.math.max @@ -55,6 +52,14 @@ class MultiImageView(context: Context, attrs: AttributeSet) : ImageView(context, refresh() } + /** + * Add image to view + */ + fun addAllImages(bitmaps: MutableList) { + this.bitmaps.addAll(bitmaps) + refresh() + } + /** * Remove all images */ @@ -63,6 +68,13 @@ class MultiImageView(context: Context, attrs: AttributeSet) : ImageView(context, refresh() } + /** + * Get images count + */ + fun getBitmapCount(): Int { + return bitmaps.size + } + override fun onAttachedToWindow() { super.onAttachedToWindow() refresh() @@ -139,7 +151,7 @@ class MultiDrawable(private val bitmaps: ArrayList) : Drawable() { items.add(PhotoItem(bitmap2, Rect(bounds.width() / 2, 0, bounds.width(), bounds.height() / 2))) items.add(PhotoItem(bitmap3, Rect(bounds.width() / 2, bounds.height() / 2, bounds.width(), bounds.height()))) } - bitmaps.size == 4 -> { + bitmaps.size > 3 -> { val bitmap1 = scaleCenterCrop(bitmaps[0], bounds.width(), bounds.height()) val bitmap2 = scaleCenterCrop(bitmaps[1], bounds.width(), bounds.height()) val bitmap3 = scaleCenterCrop(bitmaps[2], bounds.width(), bounds.height()) @@ -166,7 +178,7 @@ class MultiDrawable(private val bitmaps: ArrayList) : Drawable() { // } - private fun scaleCenterCrop(source: Bitmap, newWidth : Int, newHeight : Int): Bitmap { + private fun scaleCenterCrop(source: Bitmap, newWidth: Int, newHeight: Int): Bitmap { val sourceWidth = source.width val sourceHeight = source.height @@ -222,7 +234,6 @@ class MultiDrawable(private val bitmaps: ArrayList) : Drawable() { } - //***------------------***// } diff --git a/sample/build.gradle b/sample/build.gradle index c48a3b6..743e4fb 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.application' +apply plugin: "androidx.navigation.safeargs" android { compileSdkVersion 29 @@ -25,6 +26,26 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) implementation 'androidx.appcompat:appcompat:1.1.0' + + //Navigation + implementation "androidx.navigation:navigation-fragment:2.2.0-rc04" + //Navigation ui + implementation "androidx.navigation:navigation-ui:2.2.0-rc04" + + //Design + implementation "androidx.legacy:legacy-support-core-utils:1.0.0" + implementation 'com.google.android.material:material:1.2.0-alpha04' + implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha01' + implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta4" + + //Glide + implementation ("com.github.bumptech.glide:glide:4.9.0") { + exclude group: "com.android.support" + } + annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' + annotationProcessor 'androidx.annotation:annotation:1.1.0' + // testImpelementation 'junit:junit:4.12' implementation project (':multiimageview') + } diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java index 0be1407..756e642 100644 --- a/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java @@ -1,62 +1,28 @@ package com.stfalcon.multiimageview.sample; -import android.graphics.BitmapFactory; import android.os.Bundle; -import android.view.View; -import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; - -import com.stfalcon.multiimageview.MultiImageView; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; public class MainActivity extends AppCompatActivity { - private int imageCount = 0; + + private NavController navController; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - final MultiImageView multiImageView = (MultiImageView) findViewById(R.id.iv); - - //add images - Button button = (Button) findViewById(R.id.button); - button.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - imageCount += 1; - if (imageCount == 1) { - multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar1)); - } else if (imageCount == 2) { - multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar2)); - } else if (imageCount == 3) { - multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar3)); - } else if (imageCount == 4) { - multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar4)); - } else { - multiImageView.clear(); - imageCount = 0; - } - } - }); - - //set corner radius for rectangle shape - multiImageView.setRectCorners(50); - - //Change shape of image - Button buttonShape = (Button) findViewById(R.id.buttonShape); - buttonShape.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (multiImageView.getShape() == MultiImageView.Shape.NONE) { - multiImageView.setShape(MultiImageView.Shape.RECTANGLE); - } else if (multiImageView.getShape() == MultiImageView.Shape.RECTANGLE) { - multiImageView.setShape(MultiImageView.Shape.CIRCLE); - } else { - multiImageView.setShape(MultiImageView.Shape.NONE); - } - } - }); - - multiImageView.clear(); + navController = Navigation.findNavController(this, R.id.main_navigation_fragment); + + } + + + @Override + public boolean onSupportNavigateUp() { + return navController.navigateUp() || + super.onSupportNavigateUp(); } + } diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/MainFragment.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/MainFragment.java new file mode 100644 index 0000000..1574654 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/MainFragment.java @@ -0,0 +1,95 @@ +package com.stfalcon.multiimageview.sample; + +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; +import androidx.navigation.ui.NavigationUI; + +import com.stfalcon.multiimageview.MultiImageView; + +import java.util.Objects; + +public class MainFragment extends Fragment { + + private int imageCount = 0; + private NavController navController; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_main, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + navController = Navigation.findNavController(view); + NavigationUI.setupActionBarWithNavController((AppCompatActivity) view.getContext(), + navController); + final MultiImageView multiImageView = view.findViewById(R.id.iv); + + //add images + Button button = view.findViewById(R.id.button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + imageCount += 1; + if (imageCount == 1) { + multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar1)); + } else if (imageCount == 2) { + multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar2)); + } else if (imageCount == 3) { + multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar3)); + } else if (imageCount == 4) { + multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar4)); + } else { + multiImageView.clear(); + imageCount = 0; + } + } + }); + + //set corner radius for rectangle shape + multiImageView.setRectCorners(50); + + //Change shape of image + Button buttonShape = view.findViewById(R.id.buttonShape); + buttonShape.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (multiImageView.getShape() == MultiImageView.Shape.NONE) { + multiImageView.setShape(MultiImageView.Shape.RECTANGLE); + } else if (multiImageView.getShape() == MultiImageView.Shape.RECTANGLE) { + multiImageView.setShape(MultiImageView.Shape.CIRCLE); + } else { + multiImageView.setShape(MultiImageView.Shape.NONE); + } + } + }); + + Button recyclerExample = view.findViewById(R.id.recycler_view_example_button); + recyclerExample.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + navController.navigate(R.id.action_mainFragment_to_recyclerViewExample); + } + }); + + multiImageView.clear(); + } +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/PreviewFragment.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/PreviewFragment.java new file mode 100644 index 0000000..7399523 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/PreviewFragment.java @@ -0,0 +1,87 @@ +package com.stfalcon.multiimageview.sample; + +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.transition.TransitionInflater; + +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.transition.Transition; +import com.stfalcon.multiimageview.MultiImageView; +import com.stfalcon.multiimageview.sample.glide.GlideApp; +import com.stfalcon.multiimageview.sample.models.MultiImageViewModel; + +public class PreviewFragment extends Fragment { + + private MultiImageViewModel model; + private String TAG = "PreviewFragment"; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + getFragmentArguments(); + super.onCreate(savedInstanceState); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + androidx.transition.Transition transition = TransitionInflater.from(getActivity()) + .inflateTransition(android.R.transition.move); + setSharedElementReturnTransition(transition); + setSharedElementEnterTransition(transition); + setExitTransition(transition); + return inflater.inflate(R.layout.preview_layout, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + final MultiImageView multiImageView = view.findViewById(R.id.iv); + if (model != null){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + multiImageView.setTransitionName("transitionName-" + model.getId()); + } + + setPreviewImages(view, multiImageView); + } + + } + + private void setPreviewImages(@NonNull View view, final MultiImageView multiImageView) { + + for (int d : model.getImages()){ + + GlideApp.with(view).asBitmap().load(d).into(new CustomTarget() { + + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition transition) { + Log.d(TAG,"set image " + resource.hashCode()); + multiImageView.addImage(resource); + Log.d(TAG,"added " + multiImageView.getBitmapCount() + " image(s)"); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } + } + + private void getFragmentArguments() { + if (getArguments() != null) { + PreviewFragmentArgs args = PreviewFragmentArgs.fromBundle(getArguments()); + model = args.getMultiImageViewModel(); + } + } + +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/RecyclerViewExample.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/RecyclerViewExample.java new file mode 100644 index 0000000..3554d46 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/RecyclerViewExample.java @@ -0,0 +1,146 @@ +package com.stfalcon.multiimageview.sample; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.navigation.NavController; +import androidx.navigation.NavDirections; +import androidx.navigation.Navigation; +import androidx.navigation.fragment.FragmentNavigator; +import androidx.navigation.ui.NavigationUI; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.stfalcon.multiimageview.sample.adapters.MultiImageViewAdapter; +import com.stfalcon.multiimageview.sample.decorator.MultiImageViewItemDecorator; +import com.stfalcon.multiimageview.sample.glide.GlideApp; +import com.stfalcon.multiimageview.sample.helpers.ClickHelper; +import com.stfalcon.multiimageview.sample.models.MultiImageViewModel; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +import static com.stfalcon.multiimageview.sample.MainFragmentDirections.actionMainFragmentToRecyclerViewExample; + +public class RecyclerViewExample extends Fragment implements ClickHelper { + + private MultiImageViewAdapter multiImageViewAdapter; + private int[] avatars = new int[]{R.drawable.avatar1,R.drawable.avatar2,R.drawable.avatar3,R.drawable.avatar4}; + private int[] structuredImageListCount = new int[]{1,2,3,4,1,2,3,4,1,2}; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.recycler_view_layout, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + multiImageViewAdapter = new MultiImageViewAdapter(getActivity(), new ArrayList(), this, GlideApp.with(this)); + RecyclerView recyclerView = view.findViewById(R.id.recycler_view); + GridLayoutManager gridLayoutManager = new GridLayoutManager(view.getContext(), 3, RecyclerView.VERTICAL, false); + recyclerView.setAdapter(multiImageViewAdapter); + recyclerView.setLayoutManager(gridLayoutManager); + recyclerView.addItemDecoration(new MultiImageViewItemDecorator(view.getResources().getDimensionPixelSize(R.dimen.grid_spacing))); + refreshAdapterWithStructure(); + } + + + private List createRandomModelList(){ + List modelList = new ArrayList<>(); + for (int i = 0; i < 10; i++){ + MultiImageViewModel model = new MultiImageViewModel(); + model.setId("id-" + i); + model.setImages(createRandomModelImageList()); + modelList.add(model); + } + return modelList; + } + + private LinkedList createRandomModelImageList(){ + Random rand = new Random(); + int n = rand.nextInt(4) + 1; + LinkedList drawables = new LinkedList<>(); + + for (int i = 0; i < n; i++){ + drawables.add(avatars[i]); + } + return drawables; + } + + private LinkedList createStructuredModelList(){ + LinkedList modelList = new LinkedList<>(); + for (int i = 0; i < 10; i++){ + MultiImageViewModel model = new MultiImageViewModel(); + model.setId("id-" + i); + model.setImages(createStructuredImageList(structuredImageListCount[i])); + modelList.add(model); + } + return modelList; + } + + private LinkedList createStructuredImageList(int index){ + + LinkedList drawables = new LinkedList<>(); + + for (int i = 0; i < index; i++){ + drawables.add(avatars[i]); + } + return drawables; + } + + private void refreshAdapterWithStructure(){ + multiImageViewAdapter.refreshAdapter(createStructuredModelList()); + } + + private void refreshAdapterWithRandom(){ + multiImageViewAdapter.refreshAdapter(createRandomModelList()); + } + + private void navigateToPreview(MultiImageViewModel model, View v){ + NavController navController = Navigation.findNavController(v); + + RecyclerViewExampleDirections.ActionRecyclerViewExampleToPreviewFragment directions = RecyclerViewExampleDirections.actionRecyclerViewExampleToPreviewFragment(); + directions.setMultiImageViewModel(model); + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + + FragmentNavigator.Extras.Builder extrasBuilder = + new FragmentNavigator.Extras.Builder(); + extrasBuilder.addSharedElement(v, v.getTransitionName()); + + navController.navigate(directions, extrasBuilder.build()); + + } else { + + navController.navigate(directions); + + } + + + + } + + @Override + public void click(View v, int position) { + navigateToPreview(multiImageViewAdapter.getItem(position), v); + } +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/MultiImageViewAdapter.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/MultiImageViewAdapter.java new file mode 100644 index 0000000..f881db7 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/MultiImageViewAdapter.java @@ -0,0 +1,89 @@ +package com.stfalcon.multiimageview.sample.adapters; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.request.target.CustomTarget; +import com.stfalcon.multiimageview.sample.R; +import com.stfalcon.multiimageview.sample.adapters.view_holders.MyMultiImageViewHolder; +import com.stfalcon.multiimageview.sample.helpers.ClickHelper; +import com.stfalcon.multiimageview.sample.models.MultiImageViewModel; + +import java.util.List; + +public class MultiImageViewAdapter extends RecyclerView.Adapter { + + private Context context; + private List multiImageViewModels; + private ClickHelper clickHelper; + private RequestManager glide; + private String TAG = "MultiImageViewAdapter"; + + public MultiImageViewAdapter(Context context, List multiImageViewModels, ClickHelper clickHelper, + RequestManager glide) { + this.context = context; + this.glide = glide; + this.clickHelper = clickHelper; + this.multiImageViewModels = multiImageViewModels; + } + + @NonNull + @Override + public MyMultiImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MyMultiImageViewHolder(LayoutInflater.from(context).inflate(R.layout.view_holder, parent, false), clickHelper); + } + + @Override + public void onBindViewHolder(@NonNull final MyMultiImageViewHolder holder, int position) { + MultiImageViewModel model = multiImageViewModels.get(position); + Log.d(TAG,"image view bitmap count " + holder.multiImageView.getBitmapCount()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + holder.multiImageView.setTransitionName("transitionName-" + model.getId()); + } + for (Integer s : model.getImages()){ + setImages(holder, s); + } + } + + private void setImages(@NonNull final MyMultiImageViewHolder holder, Integer s) { + + glide.asBitmap().load(s).into(new CustomTarget() { + + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable com.bumptech.glide.request.transition.Transition transition) { + holder.multiImageView.addImage(resource); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } + + public MultiImageViewModel getItem(int position){ + return multiImageViewModels.get(position); + } + + public void refreshAdapter(List models){ + multiImageViewModels.clear(); + multiImageViewModels.addAll(models); + notifyDataSetChanged(); + } + + @Override + public int getItemCount() { + return multiImageViewModels.size(); + } +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java new file mode 100644 index 0000000..b8b7526 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java @@ -0,0 +1,32 @@ +package com.stfalcon.multiimageview.sample.adapters.view_holders; + +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.stfalcon.multiimageview.MultiImageView; +import com.stfalcon.multiimageview.sample.R; +import com.stfalcon.multiimageview.sample.helpers.ClickHelper; + +public class MyMultiImageViewHolder extends RecyclerView.ViewHolder { + + public MultiImageView multiImageView; + + public MyMultiImageViewHolder(@NonNull View itemView, final ClickHelper clickHelper) { + super(itemView); + multiImageView = itemView.findViewById(R.id.iv); + multiImageView.clear(); + multiImageView.setShape(MultiImageView.Shape.RECTANGLE); + multiImageView.setRectCorners(8); + multiImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + clickHelper.click(v, getAdapterPosition()); + } + }); + } + + + +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/decorator/MultiImageViewItemDecorator.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/decorator/MultiImageViewItemDecorator.java new file mode 100644 index 0000000..0923782 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/decorator/MultiImageViewItemDecorator.java @@ -0,0 +1,31 @@ +package com.stfalcon.multiimageview.sample.decorator; + +import android.graphics.Rect; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class MultiImageViewItemDecorator extends RecyclerView.ItemDecoration { + + private final int spacing; + + public MultiImageViewItemDecorator(int spacing) { + this.spacing = spacing; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + + int position = parent.getChildLayoutPosition(view); + + if (position % 2 != 0) { + outRect.right = spacing; + } + + outRect.left = spacing; + outRect.bottom = spacing; + + } +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/glide/MyGlideApp.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/glide/MyGlideApp.java new file mode 100644 index 0000000..39cccd1 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/glide/MyGlideApp.java @@ -0,0 +1,10 @@ +package com.stfalcon.multiimageview.sample.glide; + + +import com.bumptech.glide.annotation.GlideModule; +import com.bumptech.glide.module.AppGlideModule; + +@GlideModule +public class MyGlideApp extends AppGlideModule { + +} \ No newline at end of file diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/helpers/ClickHelper.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/helpers/ClickHelper.java new file mode 100644 index 0000000..afbbc00 --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/helpers/ClickHelper.java @@ -0,0 +1,7 @@ +package com.stfalcon.multiimageview.sample.helpers; + +import android.view.View; + +public interface ClickHelper { + void click(View v, int position); +} diff --git a/sample/src/main/java/com/stfalcon/multiimageview/sample/models/MultiImageViewModel.java b/sample/src/main/java/com/stfalcon/multiimageview/sample/models/MultiImageViewModel.java new file mode 100644 index 0000000..60fd1ae --- /dev/null +++ b/sample/src/main/java/com/stfalcon/multiimageview/sample/models/MultiImageViewModel.java @@ -0,0 +1,64 @@ +package com.stfalcon.multiimageview.sample.models; + +import android.graphics.drawable.Drawable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.LinkedList; +import java.util.List; + +public class MultiImageViewModel implements Parcelable { + + private String id; + private LinkedList images; + + public MultiImageViewModel() { + } + + public MultiImageViewModel(String id, LinkedList images) { + this.id = id; + this.images = images; + } + + protected MultiImageViewModel(Parcel in) { + id = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public MultiImageViewModel createFromParcel(Parcel in) { + return new MultiImageViewModel(in); + } + + @Override + public MultiImageViewModel[] newArray(int size) { + return new MultiImageViewModel[size]; + } + }; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public LinkedList getImages() { + return images; + } + + public void setImages(LinkedList images) { + this.images = images; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(id); + } +} diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 4acd1a5..2246629 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -1,33 +1,18 @@ - - -