diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
new file mode 100644
index 0000000..b5b9d46
Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..681f41a
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..223bbca
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..cf4c1a0
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..921bc77
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..c565aeb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/navEditor.xml b/.idea/navEditor.xml
new file mode 100644
index 0000000..4513118
--- /dev/null
+++ b/.idea/navEditor.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 6aa8ba8..c649577 100644
--- a/README.md
+++ b/README.md
@@ -1,81 +1,30 @@
-# MultiImageView
-[](https://codebeat.co/projects/github-com-stfalcon-studio-multiimageview-master) [  ](https://bintray.com/bevzaanton/maven/MultiImageView/_latestVersion)
+I forked this library to carry on it's development, I've extended the examples to include a recycler view example, the shape and corner radius can now be set from xml,
-Library for display a few images in one MultiImageView like avatar of group chat
-
+to create the image view in xml
-### Who we are
-Need iOS and Android apps, MVP development or prototyping? Contact us via info@stfalcon.com. We develop software since 2009, and we're known experts in this field. Check out our [portfolio](https://stfalcon.com/en/portfolio) and see more libraries from [stfalcon-studio](https://stfalcon-studio.github.io/).
-
-### Download
-
-Download via Gradle:
-```gradle
-compile 'com.github.stfalcon:multiimageview:0.1'
-```
-
-or Maven:
-```xml
-
- com.github.stfalcon
- multiimageview
- 0.1
- pom
-
-```
-
-### Usage
-Add MultiImageView to layout xml file
-```xml
-
-```
-In java class find view by id
-```java
-final MultiImageView multiImageView = (MultiImageView) findViewById(R.id.iv);
-```
-For adding image to MultiImageView use method addImage(Bitmap bitmap). For exapple:
-```java
-multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar1));
-```
-For setting shape of MultiImageView use method setShape(MultiImageView.Shape shape).
-```java
-multiImageView.setShape(MultiImageView.Shape.RECTANGLE);//Rectangle with round corners
-multiImageView.setShape(MultiImageView.Shape.CIRCLE);//Circle
-multiImageView.setShape(MultiImageView.Shape.NONE);//Without shape
-```
-If you choose rectangle shape you can set corner radius
-```java
-multiImageView.setRectCorners(50);
-```
-To clear MultiImageView use:
-```java
-multiImageView.clear();
-```
-
-
-Take a look at the [sample project](sample) for more information
-
-### License
+ android:layout_height="100dp"
+ app:shape="rectangle"
+ app:corner_radius="60" />
+
+
-```
-Copyright 2017 stfalcon.com
+
+
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+to add an image use
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-```
+ multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar1));
+
+to clear images use
+ multiImageView.clear();
+
+the corner radius only applys to the rectangle shape other wise it will be ignored you can set this in xml or programmatically
+
+
-[sample]:
diff --git a/build.gradle b/build.gradle
index 8e45e2b..d956c7f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,22 +1,34 @@
// 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.72'
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:4.1.0-rc02'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.novoda:bintray-release:0.3.4'
+ classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+
}
}
+
allprojects {
repositories {
jcenter()
+ google()
+ maven {
+ url 'https://maven.google.com/'
+ name 'Google'
+ }
+ maven { url 'https://jitpack.io' }
}
}
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..e08c3fc 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
+#Thu Sep 24 16:45:00 BST 2020
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-6.5-bin.zip
diff --git a/multiimageview/build.gradle b/multiimageview/build.gradle
index ea36db7..99b27f6 100644
--- a/multiimageview/build.gradle
+++ b/multiimageview/build.gradle
@@ -1,18 +1,17 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
-apply plugin: 'com.novoda.bintray-release'
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,26 +24,25 @@ android {
main.java.srcDirs += 'src/main/kotlin'
}
}
-
-publish {
- groupId = 'com.github.stfalcon'
- artifactId = 'multiimageview'
- publishVersion = '0.1'
- desc = 'Library for display a few images in one MultiImageView like avatar of group chat'
- licences = ['Apache-2.0']
- uploadName='MultiImageView'
- website = 'https://github.com/stfalcon-studio/MultiImageView.git'
+buildscript {
+ repositories {
+ jcenter()
+ }
}
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 "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ testImplementation 'junit:junit:4.12'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'com.github.martipello:MultiImageView:1.0.7'
+
}
repositories {
mavenCentral()
}
+
+
diff --git a/multiimageview/src/androidTest/java/com/stfalcon/multiimageview/ExampleInstrumentedTest.java b/multiimageview/src/androidTest/java/com/sealstudios/multiimageview/ExampleInstrumentedTest.java
similarity index 94%
rename from multiimageview/src/androidTest/java/com/stfalcon/multiimageview/ExampleInstrumentedTest.java
rename to multiimageview/src/androidTest/java/com/sealstudios/multiimageview/ExampleInstrumentedTest.java
index aa82c05..b0ad792 100644
--- a/multiimageview/src/androidTest/java/com/stfalcon/multiimageview/ExampleInstrumentedTest.java
+++ b/multiimageview/src/androidTest/java/com/sealstudios/multiimageview/ExampleInstrumentedTest.java
@@ -1,4 +1,4 @@
-package com.stfalcon.multiimageview;
+package com.sealstudios.multiimageview;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
diff --git a/multiimageview/src/main/AndroidManifest.xml b/multiimageview/src/main/AndroidManifest.xml
index 3577cd3..78f6a54 100644
--- a/multiimageview/src/main/AndroidManifest.xml
+++ b/multiimageview/src/main/AndroidManifest.xml
@@ -1,5 +1,5 @@
+ package="com.sealstudios.multiimageview">
diff --git a/multiimageview/src/main/java/com/sealstudios/multiimageview/MultiImageView.kt b/multiimageview/src/main/java/com/sealstudios/multiimageview/MultiImageView.kt
new file mode 100644
index 0000000..851e03f
--- /dev/null
+++ b/multiimageview/src/main/java/com/sealstudios/multiimageview/MultiImageView.kt
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * Copyright 2016 stfalcon.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+
+package com.sealstudios.multiimageview
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.graphics.*
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.util.AttributeSet
+import android.util.TypedValue
+import android.widget.ImageView
+import java.util.*
+import kotlin.math.max
+
+
+/**
+ * Created by Anton Bevza on 12/22/16.
+ */
+
+class MultiImageView @JvmOverloads constructor (context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ImageView(context, attrs) {
+
+ val TOP_RIGHT = 0
+ val TOP_LEFT = 1
+ val BOTTOM_RIGHT = 2
+ val BOTTOM_LEFT = 3
+
+ //Shape of view
+ var shape = Shape.NONE
+ set(value) {
+ field = value
+ invalidate()
+ }
+ //Corners radius for rectangle shape
+ var rectCorners = 100
+
+ private val bitmaps = ArrayList()
+ private val path = Path()
+ private val rect = RectF()
+ private var multiDrawable: Drawable? = null
+
+ /**
+ * Add image to view
+ */
+ fun addImage(bitmap: Bitmap) {
+ bitmaps.add(bitmap)
+ refresh()
+ }
+
+ /**
+ * Add image to view
+ */
+ fun addAllImages(bitmaps: MutableList) {
+ this.bitmaps.clear()
+ this.bitmaps.addAll(bitmaps)
+ refresh()
+ }
+
+ /**
+ * Remove all images
+ */
+ fun clear() {
+ bitmaps.clear()
+ refresh()
+ }
+
+ /**
+ * Get images count
+ */
+ fun getBitmapCount(): Int {
+ return bitmaps.size
+ }
+
+ /**
+ * Set badge text
+ */
+ fun setBadgeText() {
+
+ }
+
+// override fun onAttachedToWindow() {
+// super.onAttachedToWindow()
+// refresh()
+// }
+
+ init {
+ attrs?.let {
+ bitmaps.clear()
+ val typedArray = context.obtainStyledAttributes(it, R.styleable.MultiImageView)
+ shape = typedArray.getEnum(R.styleable.MultiImageView_shape, Shape.NONE)
+ rectCorners = typedArray.getInt(R.styleable.MultiImageView_corner_radius, 100)
+ val badgeColor = typedArray.getColor(R.styleable.MultiImageView_badge_color, getThemeAccentColor(context))
+ val badgeTextColor = typedArray.getColor(R.styleable.MultiImageView_badge_text_color, android.R.attr.textColor)
+ val badgeLocation = typedArray.getString(R.styleable.MultiImageView_badge_location)
+ val badgeMinCount = typedArray.getInt(R.styleable.MultiImageView_badge_shown_from_count, 4)
+ val badgeMaxCount = typedArray.getInt(R.styleable.MultiImageView_badge_shown_to_count, 9)
+ typedArray.recycle()
+ }
+ }
+
+
+ /**
+ * recreate MultiDrawable and set it as Drawable to ImageView
+ */
+ private fun refresh() {
+ multiDrawable = MultiDrawable(bitmaps)
+ setImageDrawable(multiDrawable)
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ if (canvas != null) {
+ if (drawable != null) {
+ //if shape not set - just draw
+ if (shape != Shape.NONE) {
+ path.reset()
+ //ImageView size
+ rect.set(0f, 0f, width.toFloat(), height.toFloat())
+ if (shape == Shape.RECTANGLE) {
+ //Rectangle with corners
+ path.addRoundRect(rect, rectCorners.toFloat(),
+ rectCorners.toFloat(), Path.Direction.CW)
+ } else {
+ //Oval
+ path.addOval(rect, Path.Direction.CW)
+ }
+ //Clip with shape
+ canvas.clipPath(path)
+ }
+ super.onDraw(canvas)
+ }
+ }
+ }
+
+
+ private fun getThemeAccentColor(context: Context): Int {
+ val colorAttr: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ android.R.attr.colorAccent
+ } else {
+ //Get colorAccent defined for AppCompat
+ context.resources.getIdentifier("colorAccent", "attr", context.packageName)
+ }
+ val outValue = TypedValue()
+ context.theme.resolveAttribute(colorAttr, outValue, true)
+ return outValue.data
+ }
+
+
+ //Types of shape
+ enum class Shape {
+ CIRCLE, RECTANGLE, NONE
+ }
+
+ inline fun > TypedArray.getEnum(index: Int, default: T) =
+ getInt(index, -1).let { if (it >= 0) enumValues()[it] else default
+ }
+}
+
+class MultiDrawable(private val bitmaps: ArrayList) : Drawable() {
+
+ private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private val items = ArrayList()
+
+ /**
+ * Create PhotoItem with position and size depends of count of images
+ */
+ private fun init() {
+ items.clear()
+ 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 > 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())
+ 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(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())))
+ }
+ }
+ }
+
+ 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, 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
+ }
+
+ /***
+ * Data class for store bitmap and position
+ */
+ data class PhotoItem(val bitmap: Bitmap, val position: Rect)
+
+
+ //***Needed to override***//
+ override fun setAlpha(alpha: Int) {
+ paint.alpha = alpha
+ }
+
+ override fun onBoundsChange(bounds: Rect) {
+ super.onBoundsChange(bounds)
+ init()
+ }
+
+ override fun getOpacity() = PixelFormat.TRANSLUCENT
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ paint.colorFilter = colorFilter
+ }
+
+
+ //***------------------***//
+}
+
diff --git a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt b/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt
deleted file mode 100644
index 243c0dc..0000000
--- a/multiimageview/src/main/java/com/stfalcon/multiimageview/MultiImageView.kt
+++ /dev/null
@@ -1,180 +0,0 @@
-/*******************************************************************************
- * Copyright 2016 stfalcon.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *******************************************************************************/
-
-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.*
-
-/**
- * Created by Anton Bevza on 12/22/16.
- */
-
-class MultiImageView(context: Context, attrs: AttributeSet) : ImageView(context, attrs) {
- //Shape of view
- var shape = Shape.NONE
- set(value) {
- field = value
- invalidate()
- }
- //Corners radius for rectangle shape
- var rectCorners = 100
-
- private val bitmaps = ArrayList()
- private val path = Path()
- private val rect = RectF()
- private var multiDrawable: Drawable? = null
-
- /**
- * Add image to view
- */
- fun addImage(bitmap: Bitmap) {
- bitmaps.add(bitmap)
- refresh()
- }
-
- /**
- * Remove all images
- */
- fun clear() {
- bitmaps.clear()
- refresh()
- }
-
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- refresh()
- }
-
- /**
- * recreate MultiDrawable and set it as Drawable to ImageView
- */
- private fun refresh() {
- multiDrawable = MultiDrawable(bitmaps)
- setImageDrawable(multiDrawable)
- }
-
- override fun onDraw(canvas: Canvas?) {
- if (canvas != null) {
- if (drawable != null) {
- //if shape not set - just draw
- if (shape != Shape.NONE) {
- path.reset()
- //ImageView size
- rect.set(0f, 0f, width.toFloat(), height.toFloat())
- if (shape == Shape.RECTANGLE) {
- //Rectangle with corners
- path.addRoundRect(rect, rectCorners.toFloat(),
- rectCorners.toFloat(), Path.Direction.CW)
- } else {
- //Oval
- path.addOval(rect, Path.Direction.CW)
- }
- //Clip with shape
- canvas.clipPath(path)
- }
- super.onDraw(canvas)
- }
- }
- }
-
- //Types of shape
- enum class Shape {
- CIRCLE, RECTANGLE, NONE
- }
-}
-
-class MultiDrawable(val bitmaps: ArrayList) : Drawable() {
- private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
- private val items = ArrayList()
-
- /**
- * Create PhotoItem with position and size depends of count of images
- */
- 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())))
- }
- }
-
- override fun draw(canvas: Canvas?) {
- if (canvas != null) {
- 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)
- }
-
- /***
- * Data class for store bitmap and position
- */
- data class PhotoItem(val bitmap: Bitmap, val position: Rect)
-
-
- //***Needed to override***//
- override fun setAlpha(alpha: Int) {
- paint.alpha = alpha
- }
-
- override fun onBoundsChange(bounds: Rect) {
- super.onBoundsChange(bounds)
- init()
- }
-
- override fun getOpacity() = PixelFormat.TRANSLUCENT
-
- override fun setColorFilter(colorFilter: ColorFilter) {
- paint.colorFilter = colorFilter
- }
- //***------------------***//
-}
-
diff --git a/multiimageview/src/main/res/values/attrs.xml b/multiimageview/src/main/res/values/attrs.xml
new file mode 100755
index 0000000..4fe4ce5
--- /dev/null
+++ b/multiimageview/src/main/res/values/attrs.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/multiimageview/src/test/java/com/stfalcon/multiimageview/ExampleUnitTest.java b/multiimageview/src/test/java/com/sealstudios/multiimageview/ExampleUnitTest.java
similarity index 90%
rename from multiimageview/src/test/java/com/stfalcon/multiimageview/ExampleUnitTest.java
rename to multiimageview/src/test/java/com/sealstudios/multiimageview/ExampleUnitTest.java
index 533d5ec..7c24778 100644
--- a/multiimageview/src/test/java/com/stfalcon/multiimageview/ExampleUnitTest.java
+++ b/multiimageview/src/test/java/com/sealstudios/multiimageview/ExampleUnitTest.java
@@ -1,4 +1,4 @@
-package com.stfalcon.multiimageview;
+package com.sealstudios.multiimageview;
import org.junit.Test;
diff --git a/sample/build.gradle b/sample/build.gradle
index 35cf6de..2d2721f 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -1,15 +1,16 @@
apply plugin: 'com.android.application'
+apply plugin: "androidx.navigation.safeargs"
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.0"
+ compileSdkVersion 29
+ buildToolsVersion "29.0.2"
defaultConfig {
- applicationId "com.stfalcon.multiimageview.sample"
+ applicationId "com.sealstudios.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 +21,31 @@ 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.2.0'
+
+ //Navigation
+ implementation "androidx.navigation:navigation-fragment:2.3.0"
+ //Navigation ui
+ implementation "androidx.navigation:navigation-ui:2.3.0"
+
+ //Design
+ implementation "androidx.legacy:legacy-support-core-utils:1.0.0"
+ implementation 'com.google.android.material:material:1.3.0-alpha02'
+ implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha05'
+ implementation "androidx.constraintlayout:constraintlayout:2.0.1"
+
+ //Glide
+ implementation ("com.github.bumptech.glide:glide:4.11.0") {
+ exclude group: "com.android.support"
+ }
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
+ annotationProcessor 'androidx.annotation:annotation:1.1.0'
+
+// testImpelementation 'junit:junit:4.12'
+ implementation project (':multiimageview')
+
}
diff --git a/sample/src/androidTest/java/com/stfalcon/multiimageview/sample/ExampleInstrumentedTest.java b/sample/src/androidTest/java/com/sealstudios/multiimageview/sample/ExampleInstrumentedTest.java
similarity index 93%
rename from sample/src/androidTest/java/com/stfalcon/multiimageview/sample/ExampleInstrumentedTest.java
rename to sample/src/androidTest/java/com/sealstudios/multiimageview/sample/ExampleInstrumentedTest.java
index ae84188..b217159 100644
--- a/sample/src/androidTest/java/com/stfalcon/multiimageview/sample/ExampleInstrumentedTest.java
+++ b/sample/src/androidTest/java/com/sealstudios/multiimageview/sample/ExampleInstrumentedTest.java
@@ -1,4 +1,4 @@
-package com.stfalcon.multiimageview.sample;
+package com.sealstudios.multiimageview.sample;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
index 6b42df4..5afe00d 100644
--- a/sample/src/main/AndroidManifest.xml
+++ b/sample/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
+ package="com.sealstudios.multiimageview.sample">
-
+
diff --git a/sample/src/main/java/com/sealstudios/multiimageview/sample/MainActivity.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/MainActivity.java
new file mode 100644
index 0000000..af81609
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/MainActivity.java
@@ -0,0 +1,28 @@
+package com.sealstudios.multiimageview.sample;
+
+import android.os.Bundle;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+
+public class MainActivity extends AppCompatActivity {
+
+ private NavController navController;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ 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/MainActivity.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/MainFragment.java
similarity index 52%
rename from sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java
rename to sample/src/main/java/com/sealstudios/multiimageview/sample/MainFragment.java
index 885a633..7fa2926 100644
--- a/sample/src/main/java/com/stfalcon/multiimageview/sample/MainActivity.java
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/MainFragment.java
@@ -1,24 +1,48 @@
-package com.stfalcon.multiimageview.sample;
+package com.sealstudios.multiimageview.sample;
import android.graphics.BitmapFactory;
-import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.Button;
-import com.stfalcon.multiimageview.MultiImageView;
+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.sealstudios.multiimageview.MultiImageView;
+
+public class MainFragment extends Fragment {
-public class MainActivity extends AppCompatActivity {
private int imageCount = 0;
+ private NavController navController;
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- final MultiImageView multiImageView = (MultiImageView) findViewById(R.id.iv);
+ }
+
+ @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 = (Button) findViewById(R.id.button);
+ Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -42,7 +66,7 @@ public void onClick(View view) {
multiImageView.setRectCorners(50);
//Change shape of image
- Button buttonShape = (Button) findViewById(R.id.buttonShape);
+ Button buttonShape = view.findViewById(R.id.buttonShape);
buttonShape.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -56,6 +80,14 @@ public void onClick(View view) {
}
});
+ 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/sealstudios/multiimageview/sample/PreviewFragment.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/PreviewFragment.java
new file mode 100644
index 0000000..4c9fc41
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/PreviewFragment.java
@@ -0,0 +1,87 @@
+package com.sealstudios.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.sealstudios.multiimageview.MultiImageView;
+import com.sealstudios.multiimageview.sample.glide.GlideApp;
+import com.sealstudios.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 super Bitmap> 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/sealstudios/multiimageview/sample/RecyclerViewExample.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/RecyclerViewExample.java
new file mode 100644
index 0000000..729202d
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/RecyclerViewExample.java
@@ -0,0 +1,144 @@
+package com.sealstudios.multiimageview.sample;
+
+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.navigation.NavController;
+import androidx.navigation.Navigation;
+import androidx.navigation.fragment.FragmentNavigator;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.sealstudios.multiimageview.MultiImageView;
+import com.sealstudios.multiimageview.sample.adapters.MultiImageViewAdapter;
+import com.sealstudios.multiimageview.sample.decorator.MultiImageViewItemDecorator;
+import com.sealstudios.multiimageview.sample.glide.GlideApp;
+import com.sealstudios.multiimageview.sample.helpers.ClickHelper;
+import com.sealstudios.multiimageview.sample.models.MultiImageViewModel;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+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};
+ private String TAG = "RecyclerViewExample";
+
+ @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 < 30; i++){
+ MultiImageViewModel model = new MultiImageViewModel();
+ model.setId("id-" + i);
+ model.setImages(createStructuredImageList(structuredImageListCount[i / 3]));
+ 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) {
+ MultiImageView multiImageView = v.findViewById(R.id.iv);
+ Log.d(TAG,"multiImageView bitmap count " + multiImageView.getBitmapCount());
+ navigateToPreview(multiImageViewAdapter.getItem(position), v);
+ }
+}
diff --git a/sample/src/main/java/com/sealstudios/multiimageview/sample/adapters/MultiImageViewAdapter.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/adapters/MultiImageViewAdapter.java
new file mode 100644
index 0000000..703e0d7
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/adapters/MultiImageViewAdapter.java
@@ -0,0 +1,120 @@
+package com.sealstudios.multiimageview.sample.adapters;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.LayoutInflater;
+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.sealstudios.multiimageview.sample.R;
+import com.sealstudios.multiimageview.sample.adapters.view_holders.MyMultiImageViewHolder;
+import com.sealstudios.multiimageview.sample.helpers.ClickHelper;
+import com.sealstudios.multiimageview.sample.models.MultiImageViewModel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+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);
+ holder.multiImageView.clear();
+ holder.imageSetCounter.set(0);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ holder.multiImageView.setTransitionName("transitionName-" + model.getId());
+ }
+
+ if (!model.getImages().isEmpty()){
+// setImages(holder, model.getImages(), holder.imageSetCounter);
+ getAndSetImages(holder,model.getImages(), holder.imageSetCounter, new ArrayList());
+ }
+
+ }
+
+ private void getAndSetImages(final MyMultiImageViewHolder holder, final List imageIdentifiers, final AtomicInteger imageSetCount, final List bitmaps){
+
+ glide.asBitmap().load(imageIdentifiers.get(imageSetCount.get())).into(new CustomTarget() {
+
+ @Override
+ public void onResourceReady(@NonNull Bitmap resource, @Nullable com.bumptech.glide.request.transition.Transition super Bitmap> transition) {
+ bitmaps.add(resource);
+ if (imageSetCount.get() < imageIdentifiers.size() - 1){
+ imageSetCount.getAndIncrement();
+ getAndSetImages(holder,imageIdentifiers, imageSetCount, bitmaps);
+ } else {
+ holder.multiImageView.addAllImages(bitmaps);
+ }
+ }
+
+ @Override
+ public void onLoadCleared(@Nullable Drawable placeholder) {
+
+ }
+ });
+ }
+
+ private void setImages(@NonNull final MyMultiImageViewHolder holder, final List imageIdentifiers, final AtomicInteger imageSetCount) {
+
+ glide.asBitmap().load(imageIdentifiers.get(imageSetCount.get())).into(new CustomTarget() {
+
+ @Override
+ public void onResourceReady(@NonNull Bitmap resource, @Nullable com.bumptech.glide.request.transition.Transition super Bitmap> transition) {
+ holder.multiImageView.addImage(resource);
+ if (imageSetCount.get() < imageIdentifiers.size() - 1){
+ imageSetCount.getAndIncrement();
+ setImages(holder, imageIdentifiers, imageSetCount);
+ }
+ }
+
+ @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/sealstudios/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java
new file mode 100644
index 0000000..d2e53fe
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/adapters/view_holders/MyMultiImageViewHolder.java
@@ -0,0 +1,33 @@
+package com.sealstudios.multiimageview.sample.adapters.view_holders;
+
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.sealstudios.multiimageview.MultiImageView;
+import com.sealstudios.multiimageview.sample.R;
+import com.sealstudios.multiimageview.sample.helpers.ClickHelper;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class MyMultiImageViewHolder extends RecyclerView.ViewHolder {
+
+ public MultiImageView multiImageView;
+ public AtomicInteger imageSetCounter = new AtomicInteger(0);
+
+ public MyMultiImageViewHolder(@NonNull View itemView, final ClickHelper clickHelper) {
+ super(itemView);
+ multiImageView = itemView.findViewById(R.id.iv);
+ multiImageView.clear();
+ multiImageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ clickHelper.click(v, getAdapterPosition());
+ }
+ });
+ }
+
+
+
+}
diff --git a/sample/src/main/java/com/sealstudios/multiimageview/sample/decorator/MultiImageViewItemDecorator.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/decorator/MultiImageViewItemDecorator.java
new file mode 100644
index 0000000..4f01c72
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/decorator/MultiImageViewItemDecorator.java
@@ -0,0 +1,31 @@
+package com.sealstudios.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/sealstudios/multiimageview/sample/glide/MyGlideApp.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/glide/MyGlideApp.java
new file mode 100644
index 0000000..db9a6da
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/glide/MyGlideApp.java
@@ -0,0 +1,10 @@
+package com.sealstudios.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/sealstudios/multiimageview/sample/helpers/ClickHelper.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/helpers/ClickHelper.java
new file mode 100644
index 0000000..6b5e5d4
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/helpers/ClickHelper.java
@@ -0,0 +1,7 @@
+package com.sealstudios.multiimageview.sample.helpers;
+
+import android.view.View;
+
+public interface ClickHelper {
+ void click(View v, int position);
+}
diff --git a/sample/src/main/java/com/sealstudios/multiimageview/sample/models/MultiImageViewModel.java b/sample/src/main/java/com/sealstudios/multiimageview/sample/models/MultiImageViewModel.java
new file mode 100644
index 0000000..aab353a
--- /dev/null
+++ b/sample/src/main/java/com/sealstudios/multiimageview/sample/models/MultiImageViewModel.java
@@ -0,0 +1,62 @@
+package com.sealstudios.multiimageview.sample.models;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.LinkedList;
+
+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/drawable/screenshot_1582383274.png b/sample/src/main/res/drawable/screenshot_1582383274.png
new file mode 100644
index 0000000..10ec5f1
Binary files /dev/null and b/sample/src/main/res/drawable/screenshot_1582383274.png differ
diff --git a/sample/src/main/res/drawable/screenshot_1582383276.png b/sample/src/main/res/drawable/screenshot_1582383276.png
new file mode 100644
index 0000000..10ec5f1
Binary files /dev/null and b/sample/src/main/res/drawable/screenshot_1582383276.png differ
diff --git a/sample/src/main/res/drawable/screenshot_1582383280.png b/sample/src/main/res/drawable/screenshot_1582383280.png
new file mode 100644
index 0000000..c588471
Binary files /dev/null and b/sample/src/main/res/drawable/screenshot_1582383280.png differ
diff --git a/sample/src/main/res/drawable/screenshot_1582383283.png b/sample/src/main/res/drawable/screenshot_1582383283.png
new file mode 100644
index 0000000..b9fe763
Binary files /dev/null and b/sample/src/main/res/drawable/screenshot_1582383283.png differ
diff --git a/sample/src/main/res/drawable/screenshot_1582383286.png b/sample/src/main/res/drawable/screenshot_1582383286.png
new file mode 100644
index 0000000..ecaae2f
Binary files /dev/null and b/sample/src/main/res/drawable/screenshot_1582383286.png differ
diff --git a/sample/src/main/res/drawable/screenshot_1582383289.png b/sample/src/main/res/drawable/screenshot_1582383289.png
new file mode 100644
index 0000000..020ebb2
Binary files /dev/null and b/sample/src/main/res/drawable/screenshot_1582383289.png differ
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
index 4acd1a5..0883197 100644
--- a/sample/src/main/res/layout/activity_main.xml
+++ b/sample/src/main/res/layout/activity_main.xml
@@ -1,33 +1,18 @@
+ tools:context="com.sealstudios.multiimageview.sample.MainActivity">
-
-
-
-
-
+
diff --git a/sample/src/main/res/layout/fragment_main.xml b/sample/src/main/res/layout/fragment_main.xml
new file mode 100644
index 0000000..6061dcf
--- /dev/null
+++ b/sample/src/main/res/layout/fragment_main.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/layout/preview_layout.xml b/sample/src/main/res/layout/preview_layout.xml
new file mode 100644
index 0000000..0e8bc9b
--- /dev/null
+++ b/sample/src/main/res/layout/preview_layout.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/layout/recycler_view_layout.xml b/sample/src/main/res/layout/recycler_view_layout.xml
new file mode 100644
index 0000000..eab066f
--- /dev/null
+++ b/sample/src/main/res/layout/recycler_view_layout.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/layout/view_holder.xml b/sample/src/main/res/layout/view_holder.xml
new file mode 100644
index 0000000..ffd05d0
--- /dev/null
+++ b/sample/src/main/res/layout/view_holder.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/navigation/main_navigation.xml b/sample/src/main/res/navigation/main_navigation.xml
new file mode 100644
index 0000000..1cf8dd4
--- /dev/null
+++ b/sample/src/main/res/navigation/main_navigation.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml
index 47c8224..94e6c12 100644
--- a/sample/src/main/res/values/dimens.xml
+++ b/sample/src/main/res/values/dimens.xml
@@ -2,4 +2,5 @@
16dp
16dp
+ 8dp
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
index 398a180..d7b5b05 100644
--- a/sample/src/main/res/values/strings.xml
+++ b/sample/src/main/res/values/strings.xml
@@ -2,4 +2,5 @@
MultiImageView
Add photo
Change shape
+ Recycler View Example
diff --git a/sample/src/test/java/com/stfalcon/multiimageview/sample/ExampleUnitTest.java b/sample/src/test/java/com/sealstudios/multiimageview/sample/ExampleUnitTest.java
similarity index 88%
rename from sample/src/test/java/com/stfalcon/multiimageview/sample/ExampleUnitTest.java
rename to sample/src/test/java/com/sealstudios/multiimageview/sample/ExampleUnitTest.java
index 7e9be2c..0b9dbc8 100644
--- a/sample/src/test/java/com/stfalcon/multiimageview/sample/ExampleUnitTest.java
+++ b/sample/src/test/java/com/sealstudios/multiimageview/sample/ExampleUnitTest.java
@@ -1,4 +1,4 @@
-package com.stfalcon.multiimageview.sample;
+package com.sealstudios.multiimageview.sample;
import org.junit.Test;