From 075fba4a610247a2b8c2a4a7483b170941b888cc Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Mon, 22 Feb 2021 18:35:34 +0100 Subject: [PATCH 1/9] fix margin issue --- .../boneslibrary/framework/skeletons/SkeletonBone.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBone.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBone.kt index ae18332..6f85b90 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBone.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBone.kt @@ -47,7 +47,7 @@ internal class SkeletonBone( private var viewBounds = Bounds() private fun getLength(owner: View): Float { - val ownerWidth = owner.width.toFloat() - (owner.horizontalMargin) + val ownerWidth = owner.width.toFloat() return boneProperties.width ?: ownerWidth } From f50f8b70e4eddd8d14ae9781226061b3de87de48 Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Mon, 22 Feb 2021 19:51:31 +0100 Subject: [PATCH 2/9] utility extensions --- .../boneslibrary/bindings/SkeletonBindings.kt | 30 +++++++++++++++++++ .../bindings/SkeletonBoneBindings.kt | 24 ++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt index 49d3319..d952b6f 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt @@ -2,14 +2,17 @@ package com.eudycontreras.boneslibrary.bindings +import android.view.View import android.view.ViewGroup import androidx.annotation.ColorInt import androidx.databinding.BindingAdapter import com.eudycontreras.boneslibrary.MIN_OFFSET import com.eudycontreras.boneslibrary.doWith import com.eudycontreras.boneslibrary.extensions.descendantViews +import com.eudycontreras.boneslibrary.extensions.findParent import com.eudycontreras.boneslibrary.extensions.generateId import com.eudycontreras.boneslibrary.extensions.getProps +import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable import com.eudycontreras.boneslibrary.framework.bones.BoneProperties import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonDrawable import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonManager @@ -416,3 +419,30 @@ internal fun ViewGroup.setSkeletonBoneMaxThickness(maxThickness: Float?) { } } } + +/** + * Finds the nearest parent of this view that has + * an skeleton loader and returns the SkeletonDrawable loader + * associated with it. + * @see SkeletonDrawable + */ +fun ViewGroup.getParentSkeletonDrawable(): SkeletonDrawable? { + val skeletonParent = findParent { it.foreground is SkeletonDrawable } + return skeletonParent?.foreground as? SkeletonDrawable +} + +/** + * Returns true if this view has an ancestor with an attached + * SkeletonDrawable loader + * @see SkeletonDrawable + */ +fun ViewGroup.hasSkeletonLoaderAncestor(): Boolean { + return getParentSkeletonDrawable() != null +} + +/** + * Returns true if this view has SkeletonDrawable loader as its foreground + */ +fun ViewGroup.isSkeletonLoader(): Boolean { + return this.foreground is SkeletonDrawable +} \ No newline at end of file diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt index 4c6c38a..bf77e26 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt @@ -706,7 +706,29 @@ internal fun View.setSkeletonIgnored(ignored: Boolean?) { } } -internal fun View.getParentSkeletonDrawable(): SkeletonDrawable? { +/** + * Finds the nearest parent of this view that has + * an skeleton loader and returns the SkeletonDrawable loader + * associated with it. + * @see SkeletonDrawable + */ +fun View.getParentSkeletonDrawable(): SkeletonDrawable? { val skeletonParent = findParent { it.foreground is SkeletonDrawable } return skeletonParent?.foreground as? SkeletonDrawable } + +/** + * Returns true if this view has an ancestor with an attached + * SkeletonDrawable loader + * @see SkeletonDrawable + */ +fun View.hasSkeletonLoaderAncestor(): Boolean { + return getParentSkeletonDrawable() != null +} + +/** + * Returns true if this view has BoneDrawable loader as its foreground + */ +fun View.isBoneLoader(): Boolean { + return this.foreground is BoneDrawable +} \ No newline at end of file From 5bb56ec3351ed2d471fab322d2069236817844eb Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Tue, 23 Feb 2021 22:40:42 +0100 Subject: [PATCH 3/9] address https://github.com/EudyContreras/Skeleton-Bones/issues/20 --- .../boneslibrary/bindings/SkeletonBindings.kt | 19 +++++++++++++++++-- .../bindings/SkeletonBoneBindings.kt | 18 ++++++++++++++++++ .../framework/bones/BoneBuilder.kt | 2 +- .../framework/shimmer/ShimmerRayBuilder.kt | 4 ++-- .../framework/shimmer/ShimmerRayProperties.kt | 2 +- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt index 194dea9..e33ee5f 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt @@ -2,7 +2,6 @@ package com.eudycontreras.boneslibrary.bindings -import android.view.View import android.view.ViewGroup import androidx.annotation.ColorInt import androidx.databinding.BindingAdapter @@ -12,7 +11,6 @@ import com.eudycontreras.boneslibrary.extensions.descendantViews import com.eudycontreras.boneslibrary.extensions.findParent import com.eudycontreras.boneslibrary.extensions.generateId import com.eudycontreras.boneslibrary.extensions.getProps -import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable import com.eudycontreras.boneslibrary.framework.bones.BoneProperties import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonDrawable import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonManager @@ -443,4 +441,21 @@ fun ViewGroup.hasSkeletonLoaderAncestor(): Boolean { */ fun ViewGroup.isSkeletonLoader(): Boolean { return this.foreground is SkeletonDrawable +} + +/** + * Returns the SkeletonDrawable loader of this ViewGroup or null if it does not have one + */ +fun ViewGroup.getSkeletonDrawable(): SkeletonDrawable? { + return this.foreground as? SkeletonDrawable? +} + +/** + * Returns the SkeletonDrawable loader of this ViewGroup + * @throws IllegalStateException when this view does not contain a SkeletonDrawable + */ +fun ViewGroup.requireSkeletonDrawable(): SkeletonDrawable { + return runCatching { this.foreground as SkeletonDrawable }.getOrElse { + throw IllegalStateException("This view does not contain a SkeletonDrawable") + } } \ No newline at end of file diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt index bf77e26..20f52eb 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt @@ -2,6 +2,7 @@ package com.eudycontreras.boneslibrary.bindings import android.graphics.drawable.Drawable import android.view.View +import android.view.ViewGroup import androidx.annotation.ColorInt import androidx.annotation.Dimension import androidx.databinding.BindingAdapter @@ -731,4 +732,21 @@ fun View.hasSkeletonLoaderAncestor(): Boolean { */ fun View.isBoneLoader(): Boolean { return this.foreground is BoneDrawable +} + +/** + * Returns the BoneDrawable loader of this View or null if it does not have one + */ +fun View.getBoneDrawable(): BoneDrawable? { + return this.foreground as? BoneDrawable? +} + +/** + * Returns the BoneDrawable loader of this ViewGroup + * @throws IllegalStateException when this view does not contain a BoneDrawable + */ +fun ViewGroup.requireBoneDrawable(): BoneDrawable { + return runCatching { this.foreground as BoneDrawable }.getOrElse { + throw IllegalStateException("This view does not contain a BoneDrawable") + } } \ No newline at end of file diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt index f5a961a..5d5e44a 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt @@ -26,7 +26,7 @@ import com.eudycontreras.boneslibrary.properties.ShapeType * @see BoneProperties */ -data class BoneBuilder internal constructor( +data class BoneBuilder( internal val boneProperties: BoneProperties = BoneProperties() ) { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt index e42ae3d..98170e9 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt @@ -24,8 +24,8 @@ import com.eudycontreras.boneslibrary.properties.MutableColor * @see ShimmerRayProperties */ -data class ShimmerRayBuilder internal constructor( - private val shimmerRayProperties: ShimmerRayProperties +data class ShimmerRayBuilder( + private val shimmerRayProperties: ShimmerRayProperties = ShimmerRayProperties() ) { /** diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt index e96ad5a..1c3fff5 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt @@ -20,7 +20,7 @@ import com.eudycontreras.boneslibrary.properties.MutableColor * */ -class ShimmerRayProperties internal constructor(): Cloneable { +class ShimmerRayProperties: Cloneable { /** * @Project Project Bones From 0e92f5167a3a2a9f60187020b3045d4f28a2d056 Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Wed, 24 Feb 2021 00:17:06 +0100 Subject: [PATCH 4/9] reusable bone drawable --- .../bindings/SkeletonBoneBindings.kt | 37 ++++++++-- .../boneslibrary/common/Reusable.kt | 13 ++++ .../framework/bones/BoneDrawable.kt | 67 +++++++++++-------- .../framework/bones/BoneManager.kt | 35 +++++++--- .../framework/bones/BoneProperties.kt | 8 ++- 5 files changed, 119 insertions(+), 41 deletions(-) create mode 100644 boneslibrary/src/main/java/com/eudycontreras/boneslibrary/common/Reusable.kt diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt index 20f52eb..eda279a 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt @@ -138,7 +138,6 @@ object SkeletonBoneBindings { ///////////////////////// Skeleton Bone Binding Adapters /////////////////////// - /** * Adds a bone loader Drawable to this View. The loader is enabled by default. * @see BoneDrawable @@ -159,10 +158,11 @@ fun View.addBoneLoader(enabled: Boolean? = true, boneProps: BoneProperties? = nu this.foreground = BoneDrawable(BoneManager( owner = this, - foreground = drawableForeground, - background = drawableBackground, properties = properties - )) + ).apply { + this.foreground = drawableForeground + this.background = drawableBackground + }) with (this.foreground as BoneDrawable) { this.owner = this@addBoneLoader @@ -176,6 +176,35 @@ fun View.addBoneLoader(enabled: Boolean? = true, boneProps: BoneProperties? = nu return foreground as BoneDrawable } +fun View.addBoneLoader( + boneLoaderDrawable: BoneDrawable, + enabled: Boolean? = true +): BoneDrawable { + doWith(foreground) { + if (it !is BoneDrawable) { + boneLoaderDrawable.resetForReuse() + val properties: BoneProperties = boneLoaderDrawable.getProps() + + val drawableBackground = this.background + val drawableForeground = properties.background ?: this.foreground + + this.foreground = boneLoaderDrawable.apply { + boneManager.owner = this@addBoneLoader + boneManager.foreground = drawableForeground + boneManager.background = drawableBackground + } + + with(this.foreground as BoneDrawable) { + this.owner = this@addBoneLoader + this.enabled = enabled ?: true + this.baseForeground = drawableForeground + this.baseBackground = drawableBackground + } + } + } + return foreground as BoneDrawable +} + @BindingAdapter( value = [ SkeletonBoneBindings.SKELETON_BONE_PROPERTY_ID, diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/common/Reusable.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/common/Reusable.kt new file mode 100644 index 0000000..620cfcf --- /dev/null +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/common/Reusable.kt @@ -0,0 +1,13 @@ +package com.eudycontreras.boneslibrary.common + +/** + * Copyright (C) 2020 Project X + * + * @Project ProjectX + * @author Eudy Contreras. + * @since March 2020 + */ + +internal interface Reusable { + fun resetForReuse() +} \ No newline at end of file diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt index d8f8700..944277e 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt @@ -16,6 +16,7 @@ import androidx.core.view.doOnLayout import com.eudycontreras.boneslibrary.bindings.addBoneLoader import com.eudycontreras.boneslibrary.common.AnimatableCallback import com.eudycontreras.boneslibrary.common.AnimateableDrawable +import com.eudycontreras.boneslibrary.common.Reusable import com.eudycontreras.boneslibrary.extensions.saveProps import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable.Companion.create import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRay @@ -88,34 +89,11 @@ import com.eudycontreras.boneslibrary.tryGet */ class BoneDrawable internal constructor( - private val boneManager: BoneManager -) : GradientDrawable(), AnimateableDrawable, AnimatableCallback { + internal var boneManager: BoneManager +) : GradientDrawable(), AnimateableDrawable, AnimatableCallback, Reusable { init { - boneManager.setDrawable(this) - - boneManager.addUpdateListener { - invalidateSelf() - } - - boneManager.addAnimationListener( - onStart = { - listeners?.forEach { it.onAnimationStart(this) } - }, - onEnd = { - listeners?.forEach { it.onAnimationEnd(this) } - } - ) - - boneManager.onDiscarded { - owner?.foreground = baseForeground - if (boneManager.properties.allowWeakSavedState) { - owner?.saveProps(BoneProperties.TAG, boneManager.properties, true) - } else if (boneManager.properties.allowSavedState) { - owner?.saveProps(BoneProperties.TAG, boneManager.properties) - } - listeners?.clear() - } + initialize() } private var listeners: MutableList? = null @@ -172,9 +150,35 @@ class BoneDrawable internal constructor( } } + private fun initialize() { + boneManager.setDrawable(this) + + boneManager.addUpdateListener { + invalidateSelf() + } + + boneManager.addAnimationListener( + onStart = { + listeners?.forEach { it.onAnimationStart(this) } + }, + onEnd = { + listeners?.forEach { it.onAnimationEnd(this) } + } + ) + + boneManager.onDiscarded { + owner?.foreground = baseForeground + if (boneManager.properties.allowWeakSavedState) { + owner?.saveProps(BoneProperties.TAG, boneManager.properties, true) + } else if (boneManager.properties.allowSavedState) { + owner?.saveProps(BoneProperties.TAG, boneManager.properties) + } + listeners?.clear() + } + } + @RequiresApi(VERSION_CODES.N) private fun initializeProperties(drawable: Drawable) { - owner?.let { it.outlineProvider = ViewOutlineProvider.BACKGROUND } @@ -232,6 +236,15 @@ class BoneDrawable internal constructor( @Synchronized fun build(): BoneBuilder = boneManager.getBuilder() + override fun resetForReuse() { + owner = null + enabled = false + baseBackground = null + baseForeground = null + boneManager.resetForReuse() + initialize() + } + override fun draw(canvas: Canvas) { baseForeground?.draw(canvas) boneManager.renderer.render(canvas) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt index f72c5bc..db5436e 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt @@ -8,6 +8,7 @@ import com.eudycontreras.boneslibrary.Action import com.eudycontreras.boneslibrary.MAX_OFFSET import com.eudycontreras.boneslibrary.MIN_OFFSET import com.eudycontreras.boneslibrary.common.Disposable +import com.eudycontreras.boneslibrary.common.Reusable import com.eudycontreras.boneslibrary.extensions.animate import com.eudycontreras.boneslibrary.extensions.build import com.eudycontreras.boneslibrary.properties.Color @@ -21,14 +22,26 @@ import com.eudycontreras.boneslibrary.properties.Color */ internal class BoneManager( - private val owner: View, - internal var foreground: Drawable?, - internal var background: Drawable?, + owner: View, internal var properties: BoneProperties = BoneProperties() -) : Disposable { +) : Disposable, Reusable { private lateinit var drawable: BoneDrawable + internal var foreground: Drawable? = null + + internal var background: Drawable? = null + + internal var owner: View? = owner + set(value) { + field = value + if (value != null) { + bone = Bone.build(value, properties, this) + } + } + + private var bone: Bone = Bone.build(owner, properties, this) + private var fadeAnimator = ValueAnimator.ofFloat(MIN_OFFSET, MAX_OFFSET) private var boneAnimator = ValueAnimator.ofFloat(MIN_OFFSET, MAX_OFFSET) @@ -43,11 +56,9 @@ internal class BoneManager( private var discarded: Boolean = false - private val bone: Bone = Bone.build(owner, properties, this) - private val builder: BoneBuilder = BoneBuilder(properties) - val renderer: BoneRenderer = BoneRenderer(bone) + val renderer: BoneRenderer by lazy { BoneRenderer(bone) } val isDiscarded: Boolean get() = discarded @@ -70,13 +81,13 @@ internal class BoneManager( fun showBone(show: Boolean) { if (show) { if (foreground != null) { - owner.background = foreground + owner?.background = foreground } this.renderer.shouldRender = true startAnimation() } else { if (properties.transitionDuration > 0L) { - owner.background = background + owner?.background = background animateFadeOut() } else { this.renderer.shouldRender = false @@ -86,6 +97,12 @@ internal class BoneManager( } } + override fun resetForReuse() { + this.properties.resetForReuse() + this.discarded = false + this.renderer.shouldRender = true + } + override fun dispose() { this.stopAnimation() this.discarded = true diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt index 67a0dd5..113a68d 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt @@ -4,6 +4,7 @@ import android.graphics.drawable.Drawable import com.eudycontreras.boneslibrary.MAX_OFFSET import com.eudycontreras.boneslibrary.bindings.SkeletonBoneBindings import com.eudycontreras.boneslibrary.common.Cloneable +import com.eudycontreras.boneslibrary.common.Reusable import com.eudycontreras.boneslibrary.extensions.clone import com.eudycontreras.boneslibrary.extensions.dp import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties @@ -25,7 +26,7 @@ import com.eudycontreras.boneslibrary.properties.ShapeType * [Skeleton-Bones](https://github.com/EudyContreras/Skeleton-Bones) library on GitHub. */ -class BoneProperties: Cloneable{ +class BoneProperties: Cloneable, Reusable { @Volatile internal var enabledListener: ((enabled: Boolean) -> Unit)? = null @@ -438,6 +439,11 @@ class BoneProperties: Cloneable{ enabledListener?.invoke(value) } + override fun resetForReuse() { + this.isDisposed = false + this.isLoaded = false + } + /** * Returns a builder for this Bone Property instance. */ From 2155042fedcc12c1e66470e4ed076a6cbdb7b53e Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Wed, 24 Feb 2021 00:48:11 +0100 Subject: [PATCH 5/9] reusable skeleton drawable --- .../boneslibrary/bindings/SkeletonBindings.kt | 24 ++++++ .../framework/bones/BoneManager.kt | 3 +- .../framework/skeletons/Skeleton.kt | 8 +- .../framework/skeletons/SkeletonDrawable.kt | 77 +++++++++++-------- .../framework/skeletons/SkeletonManager.kt | 17 ++-- .../framework/skeletons/SkeletonProperties.kt | 15 +++- 6 files changed, 103 insertions(+), 41 deletions(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt index e33ee5f..39d9a26 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt @@ -105,6 +105,30 @@ fun ViewGroup.addSkeletonLoader(enabled: Boolean?, properties: SkeletonPropertie return foreground as SkeletonDrawable } +fun ViewGroup.addSkeletonLoader(enabled: Boolean?, skeletonLoaderDrawable: SkeletonDrawable): SkeletonDrawable { + doWith(foreground) { + if (it !is SkeletonDrawable) { + + val drawableBackground = this.background + val drawableForeground = this.foreground + + + this.foreground = skeletonLoaderDrawable.apply { + skeletonLoaderDrawable.resetForReuse() + } + + with (this.foreground as SkeletonDrawable) { + this.owner = this@addSkeletonLoader + this.enabled = enabled ?: true + this.baseDrawableForeground = drawableForeground + this.baseDrawableBackground = drawableBackground + } + } + } + return foreground as SkeletonDrawable +} + + @BindingAdapter(SkeletonBindings.SKELETON_ENABLED) internal fun ViewGroup.setSkeletonEnabled(enabled: Boolean?) { doWith(foreground) { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt index db5436e..f1c14bf 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt @@ -98,9 +98,10 @@ internal class BoneManager( } override fun resetForReuse() { - this.properties.resetForReuse() + this.dispose() this.discarded = false this.renderer.shouldRender = true + this.properties.resetForReuse() } override fun dispose() { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/Skeleton.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/Skeleton.kt index 16d0c1a..7052eb1 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/Skeleton.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/Skeleton.kt @@ -25,7 +25,7 @@ import com.eudycontreras.boneslibrary.properties.Color internal class Skeleton( private val manager: SkeletonManager, private val properties: SkeletonProperties -) : DrawableShape(), RenderTarget, UpdateTarget, FadeTarget, Disposable, ContentLoader { +) : DrawableShape(), RenderTarget, UpdateTarget, FadeTarget, Disposable, ContentLoader, Reusable { private var owner: ViewGroup? = null @@ -41,6 +41,12 @@ internal class Skeleton( private val shimmerRays: MutableList = mutableListOf() + override fun resetForReuse() { + isDirty = false + bones.clear() + shimmerRays.clear() + } + override fun concealContent() { for ((_, value) in bones) { value.concealContent() diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt index 527f3a3..5a608df 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt @@ -16,6 +16,7 @@ import androidx.core.view.doOnLayout import com.eudycontreras.boneslibrary.bindings.addSkeletonLoader import com.eudycontreras.boneslibrary.common.AnimatableCallback import com.eudycontreras.boneslibrary.common.AnimateableDrawable +import com.eudycontreras.boneslibrary.common.Reusable import com.eudycontreras.boneslibrary.extensions.saveProps import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonDrawable.Companion.create @@ -90,39 +91,10 @@ import com.eudycontreras.boneslibrary.tryGet class SkeletonDrawable internal constructor( private val skeletonManager: SkeletonManager -) : GradientDrawable(), AnimateableDrawable, AnimatableCallback { +) : GradientDrawable(), AnimateableDrawable, AnimatableCallback, Reusable { init { - skeletonManager.setDrawable(this) - - skeletonManager.addUpdateListener { - invalidateSelf() - - if (skeletonManager.properties.waiting) { - skeletonManager.properties.enabled = false - } - } - - skeletonManager.addAnimationListener( - onStart = { - listeners.forEach { it.onAnimationStart(this) } - }, - onEnd = { - listeners.forEach { it.onAnimationEnd(this) } - } - ) - - skeletonManager.onDiscarded { - val base = baseDrawableForeground - if (skeletonManager.properties.allowWeakSavedState) { - owner?.saveProps(SkeletonProperties.TAG, skeletonManager.properties.clone(), true) - } else if (skeletonManager.properties.allowSavedState) { - owner?.saveProps(SkeletonProperties.TAG, skeletonManager.properties.clone()) - } - listeners.clear() - owner?.foreground = null - owner?.foreground = base - } + initialize() } private val listeners: MutableList = mutableListOf() @@ -176,6 +148,39 @@ class SkeletonDrawable internal constructor( } } + private fun initialize() { + skeletonManager.setDrawable(this) + + skeletonManager.addUpdateListener { + invalidateSelf() + + if (skeletonManager.properties.waiting) { + skeletonManager.properties.enabled = false + } + } + + skeletonManager.addAnimationListener( + onStart = { + listeners.forEach { it.onAnimationStart(this) } + }, + onEnd = { + listeners.forEach { it.onAnimationEnd(this) } + } + ) + + skeletonManager.onDiscarded { + val base = baseDrawableForeground + if (skeletonManager.properties.allowWeakSavedState) { + owner?.saveProps(SkeletonProperties.TAG, skeletonManager.properties.clone(), true) + } else if (skeletonManager.properties.allowSavedState) { + owner?.saveProps(SkeletonProperties.TAG, skeletonManager.properties.clone()) + } + listeners.clear() + owner?.foreground = null + owner?.foreground = base + } + } + @RequiresApi(VERSION_CODES.N) private fun initializeProperties(drawable: Drawable) { when (drawable) { @@ -235,6 +240,16 @@ class SkeletonDrawable internal constructor( return skeletonManager.getBuilder() } + override fun resetForReuse() { + owner = null + enabled = false + baseDrawableBackground = null + baseDrawableForeground = null + skeletonManager.resetForReuse() + listeners.clear() + initialize() + } + override fun draw(canvas: Canvas) { skeletonManager.renderer.render(canvas) } diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt index 6e15bf7..3029611 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt @@ -7,6 +7,7 @@ import com.eudycontreras.boneslibrary.Action import com.eudycontreras.boneslibrary.MAX_OFFSET import com.eudycontreras.boneslibrary.MIN_OFFSET import com.eudycontreras.boneslibrary.common.Disposable +import com.eudycontreras.boneslibrary.common.Reusable import com.eudycontreras.boneslibrary.extensions.animate import com.eudycontreras.boneslibrary.extensions.build @@ -20,7 +21,7 @@ import com.eudycontreras.boneslibrary.extensions.build internal class SkeletonManager( var properties: SkeletonProperties = SkeletonProperties() -): Disposable { +): Disposable, Reusable { private lateinit var drawable: SkeletonDrawable @@ -38,6 +39,8 @@ internal class SkeletonManager( private val builder: SkeletonBuilder = SkeletonBuilder(properties) + val renderer: SkeletonRenderer = SkeletonRenderer(skeleton) + private var discardedListener: (() -> Unit)? = null private var discarded: Boolean = false @@ -45,11 +48,6 @@ internal class SkeletonManager( val isDiscarded: Boolean get() = discarded - val renderer: SkeletonRenderer = - SkeletonRenderer( - skeleton - ) - val isAnimating: Boolean get() = skeletonAnimator?.isRunning ?: false @@ -82,6 +80,13 @@ internal class SkeletonManager( } } + override fun resetForReuse() { + this.dispose() + this.discarded = false + this.renderer.shouldRender = true + this.properties.resetForReuse() + } + @Synchronized override fun dispose() { this.discarded = true diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt index b28225c..2d47a32 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt @@ -2,6 +2,7 @@ package com.eudycontreras.boneslibrary.framework.skeletons import com.eudycontreras.boneslibrary.bindings.SkeletonBindings import com.eudycontreras.boneslibrary.common.Cloneable +import com.eudycontreras.boneslibrary.common.Reusable import com.eudycontreras.boneslibrary.framework.bones.BoneProperties import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties import com.eudycontreras.boneslibrary.properties.CornerRadii @@ -24,7 +25,7 @@ import com.eudycontreras.boneslibrary.utilities.Shadow * [Skeleton-Bones](https://github.com/EudyContreras/Skeleton-Bones) library on GitHub. */ -class SkeletonProperties : Cloneable { +class SkeletonProperties : Cloneable, Reusable { private var boneProperties: MutableMap = mutableMapOf() @@ -232,6 +233,14 @@ class SkeletonProperties : Cloneable { } } + override fun resetForReuse() { + waiting = false + disposedIds.clear() + stateOwners.clear() + boneProperties.clear() + defaultBoneProperties.resetForReuse() + } + /** * @Project Project Bones * @author Eudy Contreras @@ -395,7 +404,9 @@ class SkeletonProperties : Cloneable { * * If true, Adds the given id and the state to the map of state owner. * When false it will remove the state owner since there in no point of - * keeping a loaded owner's state. + * keeping a loaded owner's state. A state owner will own the state of those + * bones or skeletons belonging to it. If a state owner state changes it will + * also change the state of the views it owns. * * @param ownerId The id of the state owner view. * @param state The state of the state owner From 0d77daa570621848c5cd63795ceb6889116db668 Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Thu, 25 Feb 2021 22:02:01 +0100 Subject: [PATCH 6/9] add shimmer ray prop handling for propery holder targets --- .../bindings/SkeletonBoneBindings.kt | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt index eda279a..560cef2 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt @@ -3,6 +3,7 @@ package com.eudycontreras.boneslibrary.bindings import android.graphics.drawable.Drawable import android.view.View import android.view.ViewGroup +import android.view.animation.Interpolator import androidx.annotation.ColorInt import androidx.annotation.Dimension import androidx.databinding.BindingAdapter @@ -220,7 +221,15 @@ fun View.addBoneLoader( "prop_${SkeletonBoneBindings.SKELETON_BONE_SAVE_STATE}", "prop_${SkeletonBoneBindings.SKELETON_BONE_WEAK_SAVE_STATE}", "prop_${SkeletonBoneBindings.SKELETON_BONE_SHADE_MULTIPLIER}", - "prop_${SkeletonBoneBindings.SKELETON_BONE_TRANSITION_DURATION}" + "prop_${SkeletonBoneBindings.SKELETON_BONE_TRANSITION_DURATION}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_COLOR}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_TILT}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_COUNT}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_THICKNESS}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_THICKNESS_RATIO}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_SPEED_MULTIPLIER}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_INTERPOLATOR}", + "prop_${SkeletonBoneShimmerRayBindings.SKELETON_BONE_SHIMMER_RAY_INTERPOLATOR_SHARED}" ], requireAll = false ) @@ -238,7 +247,15 @@ internal fun View.setBonePropertyId( allowSavedState: Boolean?, allowWeakSavedState: Boolean?, shadeMultiplier: Float?, - animDuration: Long? + animDuration: Long?, + shimmerRayColor: Int?, + shimmerRayTilt: Float?, + shimmerRayCount: Int?, + shimmerRayThickness: Float?, + shimmerRayThicknessRatio: Float?, + shimmerRaySpeedMultiplier: Float?, + shimmerRayInterpolator: Interpolator?, + shimmerRayInterpolatorShared: Boolean? ) { val parent = findParent() @@ -270,6 +287,18 @@ internal fun View.setBonePropertyId( if (allowWeakSavedState != null) setSkeletonBoneAllowWeakSavedState(allowSavedState = allowWeakSavedState) if (shadeMultiplier != null) setSkeletonBoneShadeMultiplier(shadeMultiplier = shadeMultiplier) if (animDuration != null) setSkeletonBoneTransitionDuration(duration = animDuration) + + /** + * Set shimmer props + */ + if (shimmerRayColor != null) setSkeletonBoneShimmerRayColor(rayColor = shimmerRayColor) + if (shimmerRayTilt != null) setSkeletonBoneShimmerRayTilt(rayTilt = shimmerRayTilt) + if (shimmerRayCount != null) setSkeletonBoneShimmerRayCount(count = shimmerRayCount) + if (shimmerRayThickness != null) setSkeletonBoneShimmerRayThickness(thickness = shimmerRayThickness) + if (shimmerRayThicknessRatio != null) setSkeletonBoneShimmerRayThicknessRatio(thicknessRatio = shimmerRayThicknessRatio) + if (shimmerRaySpeedMultiplier != null) setSkeletonBoneShimmerRaySpeedMultiplier(speedMultiplier = shimmerRaySpeedMultiplier) + if (shimmerRayInterpolator != null) setSkeletonBoneShimmerRayInterpolator(interpolator = shimmerRayInterpolator) + if (shimmerRayInterpolatorShared != null) setSkeletonBoneShimmerRaySharedInterpolator(shared = shimmerRayInterpolatorShared) } } From efa1d5a28503d1e99c3ad090ea06ea88be367994 Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Thu, 25 Feb 2021 23:44:29 +0100 Subject: [PATCH 7/9] bump versions --- app/build.gradle | 9 +-------- boneslibrary/build.gradle | 11 +++++------ build.gradle | 14 +++++++------- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 143b741..aac9829 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,6 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" @@ -79,17 +78,11 @@ dependencies { // Lifecycle implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$livedata_version" implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" implementation project(":boneslibrary") // Third party libs implementation 'de.hdodenhof:circleimageview:2.2.0' - - // Testing and mocking libs - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - testImplementation 'junit:junit:4.13' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/boneslibrary/build.gradle b/boneslibrary/build.gradle index 4c6c7f0..6dcba96 100644 --- a/boneslibrary/build.gradle +++ b/boneslibrary/build.gradle @@ -46,10 +46,9 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'com.google.code.gson:gson:2.8.6' - testImplementation 'junit:junit:4.13' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation "androidx.appcompat:appcompat:$appcompat_version" + implementation "androidx.core:core-ktx:$ktx_version" + + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" } diff --git a/build.gradle b/build.gradle index d9dcba1..c1ac576 100644 --- a/build.gradle +++ b/build.gradle @@ -2,15 +2,15 @@ buildscript { ext { - ktx_version = '1.2.0' - kotlin_version = '1.3.72' + ktx_version = '1.3.2' + kotlin_version = '1.4.10' + coroutines_version = '1.4.1' + lifecycle_version = '2.2.0' + livedata_version = '2.3.0' ktlint_version = '0.29.0' fragment_version = '1.3.0' - coroutines_version = '1.3.3' - lifecycle_version = '2.2.0' android_Version = '1.0.0' - appcompat_version = '1.1.0' - junit_version = '4.13' + appcompat_version = '1.2.0' gradle_version = '3.6.1' } repositories { @@ -19,7 +19,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.2' + classpath 'com.android.tools.build:gradle:4.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dda786d..650ecf3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Mar 16 21:15:25 CET 2020 +#Thu Feb 25 22:33:08 CET 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip From 23450d50066d08b9813cec5d9fc38a57806c741e Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Sun, 28 Feb 2021 12:45:48 +0100 Subject: [PATCH 8/9] api improvements and changes --- .../boneslibrary/bindings/SkeletonBindings.kt | 16 +- .../bindings/SkeletonBoneBindings.kt | 27 +-- .../bindings/SkeletonShimmerBoneBindings.kt | 1 - .../extensions/NumberExtensions.kt | 2 +- .../boneslibrary/extensions/ViewExtensions.kt | 4 + .../framework/bones/BoneBuilder.kt | 9 +- .../framework/bones/BoneDrawable.kt | 40 ++++- .../framework/bones/BoneManager.kt | 32 ++-- .../framework/bones/BoneProperties.kt | 14 +- .../framework/shimmer/ShimmerRayBuilder.kt | 9 +- .../framework/shimmer/ShimmerRayProperties.kt | 13 +- .../framework/skeletons/SkeletonBuilder.kt | 53 ++++-- .../framework/skeletons/SkeletonDrawable.kt | 32 +++- .../framework/skeletons/SkeletonManager.kt | 10 +- .../framework/skeletons/SkeletonProperties.kt | 162 ++++++++++++++++++ 15 files changed, 341 insertions(+), 83 deletions(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt index 39d9a26..37efdaa 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBindings.kt @@ -7,6 +7,7 @@ import androidx.annotation.ColorInt import androidx.databinding.BindingAdapter import com.eudycontreras.boneslibrary.MIN_OFFSET import com.eudycontreras.boneslibrary.doWith +import com.eudycontreras.boneslibrary.extensions.* import com.eudycontreras.boneslibrary.extensions.descendantViews import com.eudycontreras.boneslibrary.extensions.findParent import com.eudycontreras.boneslibrary.extensions.generateId @@ -92,7 +93,7 @@ fun ViewGroup.addSkeletonLoader(enabled: Boolean?, properties: SkeletonPropertie val drawableBackground = this.background val drawableForeground = this.foreground - this.foreground = SkeletonDrawable(SkeletonManager(getProps(SkeletonProperties.TAG) ?:properties)) + this.foreground = SkeletonDrawable(SkeletonManager(getProps(SkeletonProperties.TAG) ?: properties)) with (this.foreground as SkeletonDrawable) { this.owner = this@addSkeletonLoader @@ -112,7 +113,6 @@ fun ViewGroup.addSkeletonLoader(enabled: Boolean?, skeletonLoaderDrawable: Skele val drawableBackground = this.background val drawableForeground = this.foreground - this.foreground = skeletonLoaderDrawable.apply { skeletonLoaderDrawable.resetForReuse() } @@ -122,6 +122,9 @@ fun ViewGroup.addSkeletonLoader(enabled: Boolean?, skeletonLoaderDrawable: Skele this.enabled = enabled ?: true this.baseDrawableForeground = drawableForeground this.baseDrawableBackground = drawableBackground + this.skeletonManager + .getBuilder() + .applyBuilders() } } } @@ -260,7 +263,6 @@ internal fun ViewGroup.setSkeletonDissectLargeBones(dissect: Boolean?) { } } else { val parent = getParentSkeletonDrawable() - if (parent != null) { descendantViews().forEach { view -> val id = view.generateId() @@ -391,7 +393,7 @@ internal fun ViewGroup.setSkeletonBoneMinThickness(minThickness: Float?) { descendantViews().forEach { view -> val id = view.generateId() it.getProps().getBoneProps(id).apply { - this.minThickness = minThickness ?: BoneProperties.MIN_THICKNESS + this.minThickness = minThickness ?: BoneProperties.MIN_THICKNESS.dp } } } else { @@ -401,7 +403,7 @@ internal fun ViewGroup.setSkeletonBoneMinThickness(minThickness: Float?) { descendantViews().forEach { view -> val id = view.generateId() parent.getProps().getBoneProps(id).apply { - this.minThickness = minThickness ?: BoneProperties.MIN_THICKNESS + this.minThickness = minThickness ?: BoneProperties.MIN_THICKNESS.dp } } } else { @@ -419,7 +421,7 @@ internal fun ViewGroup.setSkeletonBoneMaxThickness(maxThickness: Float?) { descendantViews().forEach { view -> val id = view.generateId() it.getProps().getBoneProps(id).apply { - this.maxThickness = maxThickness ?: BoneProperties.MAX_THICKNESS + this.maxThickness = maxThickness ?: BoneProperties.MAX_THICKNESS.dp } } } else { @@ -429,7 +431,7 @@ internal fun ViewGroup.setSkeletonBoneMaxThickness(maxThickness: Float?) { descendantViews().forEach { view -> val id = view.generateId() parent.getProps().getBoneProps(id).apply { - this.maxThickness = maxThickness ?: BoneProperties.MAX_THICKNESS + this.maxThickness = maxThickness ?: BoneProperties.MAX_THICKNESS.dp } } } else { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt index 560cef2..c264c53 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt @@ -12,9 +12,10 @@ import com.eudycontreras.boneslibrary.MIN_OFFSET import com.eudycontreras.boneslibrary.doWith import com.eudycontreras.boneslibrary.extensions.* import com.eudycontreras.boneslibrary.framework.BonePropertyHolder -import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable +import com.eudycontreras.boneslibrary.framework.bones.* +import com.eudycontreras.boneslibrary.framework.bones.Bone import com.eudycontreras.boneslibrary.framework.bones.BoneManager -import com.eudycontreras.boneslibrary.framework.bones.BoneProperties +import com.eudycontreras.boneslibrary.framework.bones.BoneRenderer import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonDrawable import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonProperties import com.eudycontreras.boneslibrary.properties.CornerRadii @@ -157,12 +158,11 @@ fun View.addBoneLoader(enabled: Boolean? = true, boneProps: BoneProperties? = nu val drawableBackground = this.background val drawableForeground = properties.background ?: this.foreground - this.foreground = BoneDrawable(BoneManager( - owner = this, - properties = properties - ).apply { + this.foreground = BoneDrawable(BoneManager(properties = properties).apply { this.foreground = drawableForeground this.background = drawableBackground + this.innerBone = Bone.build(this@addBoneLoader, properties, this) + this.renderer = BoneRenderer(bone = innerBone) }) with (this.foreground as BoneDrawable) { @@ -178,8 +178,8 @@ fun View.addBoneLoader(enabled: Boolean? = true, boneProps: BoneProperties? = nu } fun View.addBoneLoader( - boneLoaderDrawable: BoneDrawable, - enabled: Boolean? = true + enabled: Boolean? = true, + boneLoaderDrawable: BoneDrawable ): BoneDrawable { doWith(foreground) { if (it !is BoneDrawable) { @@ -189,13 +189,14 @@ fun View.addBoneLoader( val drawableBackground = this.background val drawableForeground = properties.background ?: this.foreground - this.foreground = boneLoaderDrawable.apply { - boneManager.owner = this@addBoneLoader - boneManager.foreground = drawableForeground - boneManager.background = drawableBackground + boneLoaderDrawable.boneManager.apply { + this.foreground = drawableForeground + this.background = drawableBackground + this.innerBone = Bone.build(this@addBoneLoader, builder.boneProperties, this) + this.renderer = BoneRenderer(bone = innerBone) } - with(this.foreground as BoneDrawable) { + this.foreground = boneLoaderDrawable.apply { this.owner = this@addBoneLoader this.enabled = enabled ?: true this.baseForeground = drawableForeground diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonShimmerBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonShimmerBoneBindings.kt index 6fc3c76..d1253db 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonShimmerBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonShimmerBoneBindings.kt @@ -136,7 +136,6 @@ internal fun View.setSkeletonBoneShimmerRayCount(count: Int?) { } } - private fun View.setBoneShimmerRayCount(count: Int?) { doWith(foreground) { if (it is BoneDrawable) { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/NumberExtensions.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/NumberExtensions.kt index 488e75d..bf054d5 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/NumberExtensions.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/NumberExtensions.kt @@ -39,7 +39,7 @@ fun getDps(value: Float): Float { return value.dp } -fun Float.clamp(min: Float? = null, max: Float? = null): Float { +internal fun Float.clamp(min: Float? = null, max: Float? = null): Float { if (min == null && max == null) return this return when { this < min ?: this -> min ?: this diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/ViewExtensions.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/ViewExtensions.kt index 7f83a66..f8de6f2 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/ViewExtensions.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/extensions/ViewExtensions.kt @@ -148,6 +148,10 @@ internal inline fun View.saveProps(propId: Int, props: T, weak: Bool } } +internal fun View.clearProps(propId: Int) { + setTag(propId, null) +} + internal tailrec fun View.findParent(criteria: ((parent: View) -> Boolean)? = null): ViewGroup? { val parent: ViewGroup? = this.parent as? ViewGroup? diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt index 5d5e44a..6d53f3d 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneBuilder.kt @@ -2,6 +2,7 @@ package com.eudycontreras.boneslibrary.framework.bones import com.eudycontreras.boneslibrary.MAX_OFFSET import com.eudycontreras.boneslibrary.bindings.SkeletonBoneBindings +import com.eudycontreras.boneslibrary.extensions.dp import com.eudycontreras.boneslibrary.framework.bones.BoneProperties.Companion.DISTANCE import com.eudycontreras.boneslibrary.framework.bones.BoneProperties.Companion.MAX_THICKNESS import com.eudycontreras.boneslibrary.framework.bones.BoneProperties.Companion.MIN_THICKNESS @@ -27,7 +28,7 @@ import com.eudycontreras.boneslibrary.properties.ShapeType */ data class BoneBuilder( - internal val boneProperties: BoneProperties = BoneProperties() + internal var boneProperties: BoneProperties = BoneProperties() ) { /** @@ -167,7 +168,7 @@ data class BoneBuilder( * @see SkeletonBoneBindings.SKELETON_BONE_MIN_THICKNESS */ fun setMinThickness(minThickness: Float? = null): BoneBuilder { - this.boneProperties.minThickness = minThickness ?: MIN_THICKNESS + this.boneProperties.minThickness = minThickness ?: MIN_THICKNESS.dp return this } @@ -189,7 +190,7 @@ data class BoneBuilder( * @see SkeletonBone * @see SkeletonBoneBindings.SKELETON_BONE_MAX_THICKNESS */ - fun setMaxThickness(maxThickness: Float = MAX_THICKNESS): BoneBuilder { + fun setMaxThickness(maxThickness: Float = MAX_THICKNESS.dp): BoneBuilder { this.boneProperties.maxThickness = maxThickness return this } @@ -352,7 +353,7 @@ data class BoneBuilder( * @param distance The distance between dissected bones. * @see SkeletonBone */ - fun setMaxDistance(distance: Float = DISTANCE): BoneBuilder { + fun setMaxDistance(distance: Float = DISTANCE.dp): BoneBuilder { this.boneProperties.sectionDistance = distance return this } diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt index 944277e..f218a0f 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneDrawable.kt @@ -17,9 +17,13 @@ import com.eudycontreras.boneslibrary.bindings.addBoneLoader import com.eudycontreras.boneslibrary.common.AnimatableCallback import com.eudycontreras.boneslibrary.common.AnimateableDrawable import com.eudycontreras.boneslibrary.common.Reusable +import com.eudycontreras.boneslibrary.extensions.clearProps import com.eudycontreras.boneslibrary.extensions.saveProps import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable.Companion.create import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRay +import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonDrawable +import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonManager +import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonProperties import com.eudycontreras.boneslibrary.properties.CornerRadii import com.eudycontreras.boneslibrary.properties.ShapeType import com.eudycontreras.boneslibrary.tryGet @@ -61,6 +65,8 @@ import com.eudycontreras.boneslibrary.tryGet * this.enabled = false * this.color = Colors.RED * } + * + * etc.. * ``` * Using a **BoneDrawable** Instead of a wrapper provides the following benefits: * - Lightweight and easy to use @@ -172,6 +178,8 @@ class BoneDrawable internal constructor( owner?.saveProps(BoneProperties.TAG, boneManager.properties, true) } else if (boneManager.properties.allowSavedState) { owner?.saveProps(BoneProperties.TAG, boneManager.properties) + } else { + owner?.clearProps(BoneProperties.TAG) } listeners?.clear() } @@ -222,9 +230,9 @@ class BoneDrawable internal constructor( @Synchronized fun setProps(properties: BoneProperties) { boneManager.properties = properties.clone() - owner?.let { - if (it.isLaidOut) { - boneManager.getBone().compute(it) + owner?.let { view -> + if (view.isLaidOut) { + boneManager.getBone().compute(view) } } } @@ -234,8 +242,18 @@ class BoneDrawable internal constructor( * this **BoneDrawable** */ @Synchronized + @Deprecated( + message = "This function will soon be removed Use builder() instead", + replaceWith = ReplaceWith("builder()") + ) fun build(): BoneBuilder = boneManager.getBuilder() + /** + * Retrieves the property builder which can be used for building + * this **SkeletonDrawable** + */ + fun builder(): BoneBuilder = boneManager.getBuilder() + override fun resetForReuse() { owner = null enabled = false @@ -358,5 +376,21 @@ class BoneDrawable internal constructor( fun builder(defaultProps: BoneProperties): BoneBuilder { return BoneBuilder(defaultProps) } + + /** + * Returns a SkeletonDrawable which is then built with the given builder + */ + @JvmStatic + fun from(builder: BoneBuilder): BoneDrawable { + return BoneDrawable(BoneManager(builder)) + } + + /** + * Returns a SkeletonDrawable which is then built with the given properties + */ + @JvmStatic + fun from(properties: BoneProperties): BoneDrawable { + return BoneDrawable(BoneManager(properties)) + } } } diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt index f1c14bf..27efab2 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneManager.kt @@ -2,7 +2,6 @@ package com.eudycontreras.boneslibrary.framework.bones import android.animation.ValueAnimator import android.graphics.drawable.Drawable -import android.view.View import android.view.animation.LinearInterpolator import com.eudycontreras.boneslibrary.Action import com.eudycontreras.boneslibrary.MAX_OFFSET @@ -22,25 +21,24 @@ import com.eudycontreras.boneslibrary.properties.Color */ internal class BoneManager( - owner: View, - internal var properties: BoneProperties = BoneProperties() + internal val builder: BoneBuilder = BoneBuilder() ) : Disposable, Reusable { + constructor(properties: BoneProperties): this(BoneBuilder(properties)) + private lateinit var drawable: BoneDrawable + lateinit var renderer: BoneRenderer + internal var foreground: Drawable? = null internal var background: Drawable? = null - internal var owner: View? = owner - set(value) { - field = value - if (value != null) { - bone = Bone.build(value, properties, this) - } - } + internal var properties: BoneProperties + set(value) { builder.boneProperties = value} + get() = builder.boneProperties - private var bone: Bone = Bone.build(owner, properties, this) + internal lateinit var innerBone: Bone private var fadeAnimator = ValueAnimator.ofFloat(MIN_OFFSET, MAX_OFFSET) @@ -56,10 +54,6 @@ internal class BoneManager( private var discarded: Boolean = false - private val builder: BoneBuilder = BoneBuilder(properties) - - val renderer: BoneRenderer by lazy { BoneRenderer(bone) } - val isDiscarded: Boolean get() = discarded @@ -81,13 +75,13 @@ internal class BoneManager( fun showBone(show: Boolean) { if (show) { if (foreground != null) { - owner?.background = foreground + drawable.owner?.background = foreground } this.renderer.shouldRender = true startAnimation() } else { if (properties.transitionDuration > 0L) { - owner?.background = background + drawable.owner?.background = background animateFadeOut() } else { this.renderer.shouldRender = false @@ -107,7 +101,7 @@ internal class BoneManager( override fun dispose() { this.stopAnimation() this.discarded = true - this.bone.dispose() + this.innerBone.dispose() this.updateListeners.clear() this.startListeners.clear() this.endListeners.clear() @@ -119,7 +113,7 @@ internal class BoneManager( } fun getBone(): Bone { - return bone + return innerBone } fun onDiscarded(listener: () -> Unit) { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt index 113a68d..9a88278 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/bones/BoneProperties.kt @@ -1,6 +1,8 @@ package com.eudycontreras.boneslibrary.framework.bones + import android.graphics.drawable.Drawable +import androidx.annotation.Dimension as DimenRes import com.eudycontreras.boneslibrary.MAX_OFFSET import com.eudycontreras.boneslibrary.bindings.SkeletonBoneBindings import com.eudycontreras.boneslibrary.common.Cloneable @@ -180,7 +182,7 @@ class BoneProperties: Cloneable, Reusable { * @see SkeletonBoneBindings.SKELETON_BONE_MIN_THICKNESS */ @Volatile - var minThickness: Float = MIN_THICKNESS + var minThickness: Float = MIN_THICKNESS.dp /** * @Project Project Bones @@ -197,7 +199,7 @@ class BoneProperties: Cloneable, Reusable { * @see SkeletonBoneBindings.SKELETON_BONE_MAX_THICKNESS */ @Volatile - var maxThickness: Float = MAX_THICKNESS + var maxThickness: Float = MAX_THICKNESS.dp /** * @Project Project Bones @@ -417,7 +419,7 @@ class BoneProperties: Cloneable, Reusable { * @see SkeletonBone */ @Volatile - var sectionDistance: Float = DISTANCE + var sectionDistance: Float = DISTANCE.dp /** * @Project Project Bones @@ -498,10 +500,10 @@ class BoneProperties: Cloneable, Reusable { internal companion object { - @JvmStatic val MIN_THICKNESS = 10f.dp - @JvmStatic val MAX_THICKNESS = 10f.dp + @DimenRes(unit = DimenRes.DP) const val MIN_THICKNESS = 10f + @DimenRes(unit = DimenRes.DP) const val MAX_THICKNESS = 10f - @JvmStatic val DISTANCE = 10f.dp + @DimenRes(unit = DimenRes.DP) const val DISTANCE = 10f const val OVERFLOW_THRESHOLD = 2.5 const val HEIGHT_THRESHOLD = 1.5f diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt index 98170e9..4b43ca9 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayBuilder.kt @@ -2,6 +2,7 @@ package com.eudycontreras.boneslibrary.framework.shimmer import android.view.animation.Interpolator import com.eudycontreras.boneslibrary.MAX_OFFSET +import com.eudycontreras.boneslibrary.extensions.dp import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties.Companion.DEFAULT_DURATION import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties.Companion.DEFAULT_RAY_TILT import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties.Companion.DEFAULT_THICKNESS_RATIO @@ -161,7 +162,7 @@ data class ShimmerRayBuilder( * ``` * @param thickness The thickness/width of the shimmer ray */ - fun setThickness(thickness: Float = MAX_THICKNESS): ShimmerRayBuilder { + fun setThickness(thickness: Float = MAX_THICKNESS.dp): ShimmerRayBuilder { this.shimmerRayProperties.shimmerRayThickness = thickness return this } @@ -193,12 +194,16 @@ data class ShimmerRayBuilder( * @since March 2020 * * Sets the duration of the **Shimmer Rays** animation. This is the duration of the whole animation. The - * individual **Shimmer Rays** may appear to be animated much quicker. + * individual **Shimmer Rays** may appear to be animated much quicker.This property applies to the parent + * skeleton only. Shimmer ray durations applied to bones or inner skeletons will be ignored. + * Use the **setSpeedMultiplier** builder function in order to adjust the speed of children bones and skeletons + * * ``` * ``` * **Default:** 2000L * ``` * ``` + * @see setSpeedMultiplier * @param duration The total duration of the shimmer ray animation */ fun setAnimationDuration(duration: Long = DEFAULT_DURATION): ShimmerRayBuilder { diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt index 1c3fff5..ccecaa1 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/shimmer/ShimmerRayProperties.kt @@ -1,11 +1,11 @@ package com.eudycontreras.boneslibrary.framework.shimmer import android.view.animation.* +import androidx.annotation.Dimension import androidx.interpolator.view.animation.FastOutLinearInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator import com.eudycontreras.boneslibrary.MAX_OFFSET import com.eudycontreras.boneslibrary.common.Cloneable -import com.eudycontreras.boneslibrary.extensions.dp import com.eudycontreras.boneslibrary.properties.MutableColor /** @@ -162,12 +162,16 @@ class ShimmerRayProperties: Cloneable { * @since March 2020 * * Sets the duration of the **Shimmer Rays** animation. This is the duration of the whole animation. The - * individual **Shimmer Rays** may appear to be animated much quicker. + * individual **Shimmer Rays** may appear to be animated much quicker. This property applies to the parent + * skeleton only. Shimmer ray durations applied to bones or inner skeletons will be ignored. + * Use the **shimmerRaySpeedMultiplier** property in order to adjust the speed of children bones and skeletons + * * ``` * ``` * **Default:** 2000L * ``` * ``` + * @see shimmerRaySpeedMultiplier */ @Volatile var shimmerRayAnimDuration: Long = DEFAULT_DURATION @@ -221,8 +225,9 @@ class ShimmerRayProperties: Cloneable { return ShimmerRayBuilder(this) } - internal companion object { - @JvmStatic val MAX_THICKNESS = 120.dp + + companion object { + @Dimension(unit = Dimension.DP) const val MAX_THICKNESS = 120 const val DEFAULT_RAY_TILT = -0.3f const val DEFAULT_RAY_COUNT = 0 diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBuilder.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBuilder.kt index 5030218..77e3b83 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBuilder.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonBuilder.kt @@ -10,8 +10,7 @@ import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties.Com import com.eudycontreras.boneslibrary.properties.CornerRadii import com.eudycontreras.boneslibrary.properties.MutableColor import com.eudycontreras.boneslibrary.properties.ShapeType - -//TODO Update to reflect new properties +import java.util.* /** * Copyright (C) 2020 Project Bones @@ -30,9 +29,11 @@ import com.eudycontreras.boneslibrary.properties.ShapeType */ class SkeletonBuilder( - internal val skeletonProperties: SkeletonProperties = SkeletonProperties() + internal var skeletonProperties: SkeletonProperties = SkeletonProperties() ) { + private val builderQueue: Queue<() -> Unit> = LinkedList() + /** * @Project Project Bones * @author Eudy Contreras @@ -46,7 +47,7 @@ class SkeletonBuilder( * @see BoneBuilder */ fun withBoneBuilder(builder: BoneBuilder.() -> Unit): SkeletonBuilder { - builder.invoke(skeletonProperties.getBoneProps().builder()) + builderQueue.add { builder.invoke(skeletonProperties.getBoneProps().builder()) } return this } @@ -63,8 +64,9 @@ class SkeletonBuilder( * @see BoneProperties * @see BoneBuilder */ - fun withBoneBuilder(view: View, builder: BoneBuilder.() -> Unit): SkeletonBuilder { - builder.invoke(skeletonProperties.getBoneProperties(view.generateId()).builder()) + fun withBoneBuilder(view: View?, builder: BoneBuilder.() -> Unit): SkeletonBuilder { + if (view == null) return this + builderQueue.add { builder.invoke(skeletonProperties.getBoneProperties(view.generateId()).builder()) } return this } @@ -82,7 +84,7 @@ class SkeletonBuilder( * @see BoneBuilder */ fun withBoneBuilder(ownerId: Int, builder: BoneBuilder.() -> Unit): SkeletonBuilder { - builder.invoke(skeletonProperties.getBoneProperties(ownerId).builder()) + builderQueue.add { builder.invoke(skeletonProperties.getBoneProperties(ownerId).builder()) } return this } @@ -95,7 +97,7 @@ class SkeletonBuilder( * @see BoneBuilder */ fun withShimmerBuilder(builder: ShimmerRayBuilder.() -> Unit): SkeletonBuilder { - builder.invoke(skeletonProperties.shimmerRayProperties.builder()) + builderQueue.add { builder.invoke(skeletonProperties.shimmerRayProperties.builder()) } return this } @@ -116,7 +118,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_TRANSITION_DURATION */ fun setStateTransitionDuration(duration: Long = DEFAULT_DURATION): SkeletonBuilder { - this.skeletonProperties.stateTransitionDuration = duration + builderQueue.add { this.skeletonProperties.stateTransitionDuration = duration } return this } @@ -137,7 +139,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_USE_TRANSITION */ fun setUseStateTransition(useTransition: Boolean = true): SkeletonBuilder { - this.skeletonProperties.useStateTransition = useTransition + builderQueue.add { this.skeletonProperties.useStateTransition = useTransition } return this } @@ -160,7 +162,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_SAVE_STATE */ fun setAllowSavedState(allowSavedState: Boolean = false): SkeletonBuilder { - this.skeletonProperties.allowSavedState = allowSavedState + builderQueue.add { this.skeletonProperties.allowSavedState = allowSavedState } return this } @@ -185,7 +187,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_BACKGROUND_COLOR */ fun setColor(color: MutableColor? = null): SkeletonBuilder { - this.skeletonProperties.skeletonBackgroundColor = color + builderQueue.add { this.skeletonProperties.skeletonBackgroundColor = color } return this } @@ -207,7 +209,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_ANIMATE_RESTORED_BOUNDS */ fun setAnimateRestoreBounds(animateRestoreBounds: Boolean = false): SkeletonBuilder { - this.skeletonProperties.animateRestoredBounds = animateRestoreBounds + builderQueue.add { this.skeletonProperties.animateRestoredBounds = animateRestoreBounds } return this } @@ -232,7 +234,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_CORNER_RADIUS */ fun setCornerRadii(cornerRadii: CornerRadii? = null): SkeletonBuilder { - this.skeletonProperties.skeletonCornerRadii = cornerRadii + builderQueue.add { this.skeletonProperties.skeletonCornerRadii = cornerRadii } return this } @@ -256,7 +258,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_CORNER_RADIUS */ fun setCornerRadii(cornerRadius: Float? = null): SkeletonBuilder { - this.skeletonProperties.skeletonCornerRadii = cornerRadius?.let { CornerRadii(cornerRadius) } + builderQueue.add { this.skeletonProperties.skeletonCornerRadii = cornerRadius?.let { CornerRadii(cornerRadius) } } return this } @@ -277,7 +279,7 @@ class SkeletonBuilder( * @see SkeletonBindings.SKELETON_ENABLED */ fun setEnabled(enabled: Boolean = true): SkeletonBuilder { - this.skeletonProperties.enabled = enabled + builderQueue.add { this.skeletonProperties.enabled = enabled } return this } @@ -294,7 +296,7 @@ class SkeletonBuilder( * generation */ fun withIgnoredBones(vararg ids: Int): SkeletonBuilder { - this.skeletonProperties.addIgnored(*ids) + builderQueue.add { this.skeletonProperties.addIgnored(*ids) } return this } @@ -311,8 +313,21 @@ class SkeletonBuilder( * generation */ fun withIgnoredBones(vararg views: View): SkeletonBuilder { - val ids = views.map { it.generateId() }.toIntArray() - this.skeletonProperties.addIgnored(*ids) + builderQueue.add { this.skeletonProperties.addIgnored(*views.map { it.generateId() }.toIntArray()) } + return this + } + + @Synchronized + internal fun clearBuilders(): SkeletonBuilder { + builderQueue.clear() + return this + } + + @Synchronized + internal fun applyBuilders(): SkeletonBuilder { + while (builderQueue.peek() != null) { + builderQueue.poll()?.invoke() + } return this } } diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt index 5a608df..f9435f6 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt @@ -90,13 +90,15 @@ import com.eudycontreras.boneslibrary.tryGet */ class SkeletonDrawable internal constructor( - private val skeletonManager: SkeletonManager + internal val skeletonManager: SkeletonManager ) : GradientDrawable(), AnimateableDrawable, AnimatableCallback, Reusable { init { initialize() } + constructor(): this(SkeletonManager()) + private val listeners: MutableList = mutableListOf() private val self: GradientDrawable @@ -135,11 +137,13 @@ class SkeletonDrawable internal constructor( owner?.let { viewGroup -> viewGroup.doOnLayout { if (field) { + skeletonManager.getBuilder().applyBuilders() skeletonManager.getSkeleton().compute(field, viewGroup) { skeletonManager.showSkeleton(field) invalidateSelf() } } else { + skeletonManager.showSkeleton(field) invalidateSelf() } @@ -236,10 +240,20 @@ class SkeletonDrawable internal constructor( * this **SkeletonDrawable** */ @Synchronized + @Deprecated( + message = "This function will soon be removed Use builder() instead", + replaceWith = ReplaceWith("builder()") + ) fun build(): SkeletonBuilder { return skeletonManager.getBuilder() } + /** + * Retrieves the property builder which can be used for building + * this **SkeletonDrawable** + */ + fun builder(): SkeletonBuilder = skeletonManager.getBuilder() + override fun resetForReuse() { owner = null enabled = false @@ -354,5 +368,21 @@ class SkeletonDrawable internal constructor( fun builder(defaultProps: SkeletonProperties = SkeletonProperties()): SkeletonBuilder { return SkeletonBuilder(defaultProps) } + + /** + * Returns a SkeletonDrawable which is then built with the given builder + */ + @JvmStatic + fun from(builder: SkeletonBuilder): SkeletonDrawable { + return SkeletonDrawable(SkeletonManager(builder)) + } + + /** + * Returns a SkeletonDrawable which is then built with the given properties + */ + @JvmStatic + fun from(properties: SkeletonProperties): SkeletonDrawable { + return SkeletonDrawable(SkeletonManager(properties)) + } } } diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt index 3029611..f776deb 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonManager.kt @@ -20,9 +20,15 @@ import com.eudycontreras.boneslibrary.extensions.build */ internal class SkeletonManager( - var properties: SkeletonProperties = SkeletonProperties() + internal val builder: SkeletonBuilder = SkeletonBuilder(SkeletonProperties()) ): Disposable, Reusable { + constructor(properties: SkeletonProperties): this(SkeletonBuilder(properties)) + + internal var properties: SkeletonProperties + set(value) { builder.skeletonProperties = value} + get() = builder.skeletonProperties + private lateinit var drawable: SkeletonDrawable private var fadeAnimator = ValueAnimator.ofFloat(MIN_OFFSET, MAX_OFFSET) @@ -37,8 +43,6 @@ internal class SkeletonManager( private val skeleton: Skeleton = Skeleton(this, properties) - private val builder: SkeletonBuilder = SkeletonBuilder(properties) - val renderer: SkeletonRenderer = SkeletonRenderer(skeleton) private var discardedListener: (() -> Unit)? = null diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt index 2d47a32..63e1501 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonProperties.kt @@ -1,8 +1,10 @@ package com.eudycontreras.boneslibrary.framework.skeletons +import android.view.View import com.eudycontreras.boneslibrary.bindings.SkeletonBindings import com.eudycontreras.boneslibrary.common.Cloneable import com.eudycontreras.boneslibrary.common.Reusable +import com.eudycontreras.boneslibrary.extensions.generateId import com.eudycontreras.boneslibrary.framework.bones.BoneProperties import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRayProperties import com.eudycontreras.boneslibrary.properties.CornerRadii @@ -274,10 +276,48 @@ class SkeletonProperties : Cloneable, Reusable { * @see BoneProperties */ @Synchronized + @Deprecated( + message = "this is spelled wrong and will be removed", + replaceWith = ReplaceWith("setBoneProps") + ) fun settBoneProps(ownerId: Int, boneProps: BoneProperties) { boneProperties[ownerId] = boneProps } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Sets the **BoneProperties** for the bone with + * the given ownerId. + * + * @param ownerId The id of the view this bone is meant to represent. + * + * @see BoneProperties + */ + @Synchronized + fun setBoneProps(ownerId: Int, boneProps: BoneProperties) { + boneProperties[ownerId] = boneProps + } + + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Sets the **BoneProperties** for the bone with + * the given ownerId. + * + * @param view The view this bone is meant to represent. + * + * @see BoneProperties + */ + @Synchronized + fun setBoneProps(view: View, boneProps: BoneProperties) { + setBoneProps(view.generateId(), boneProps) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -295,6 +335,23 @@ class SkeletonProperties : Cloneable, Reusable { return ignoredIds.contains(ownerId) } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Returns true when the view with the given id is currently + * being ignored during **Bone** generation. + * + * @param ownerId The id of the view which is meant to be a **Bone's** owner. + * + * @see BoneProperties + */ + @Synchronized + fun isIgnored(view: View): Boolean { + return isIgnored(view.generateId()) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -311,6 +368,22 @@ class SkeletonProperties : Cloneable, Reusable { return disposedIds.contains(ownerId) } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Returns true when the view with the given id has been disposed + * + * @param view The view which is meant to be a **Bone's** owner. + * + * @see BoneProperties + */ + @Synchronized + fun isDisposed(view: View): Boolean { + return isDisposed(view.generateId()) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -329,6 +402,24 @@ class SkeletonProperties : Cloneable, Reusable { ignoredIds.addAll(ownerId.asList()) } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Adds the given id to list of ignored ids. + * This will prevent the generation of the bone meant to represent the owner + * view. + * + * @param view The view which is meant to be a **Bone's** owner. + * + * @see BoneProperties + */ + @Synchronized + fun addIgnored(vararg view: View) { + ignoredIds.addAll(view.map { it.generateId() }) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -380,6 +471,22 @@ class SkeletonProperties : Cloneable, Reusable { } ?: false } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Returns the state state of the state owner + * + * @param ownerId The id of the state owner view + * + * @see BoneProperties + */ + @Synchronized + fun getStateOwnerState(view: View): Boolean { + return getStateOwnerState(view.generateId()) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -397,6 +504,23 @@ class SkeletonProperties : Cloneable, Reusable { return stateOwners.containsKey(ownerId) } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Returns true when the view with the given id is currently + * being a state owner. + * + * @param view The id of the state owner view + * + * @see BoneProperties + */ + @Synchronized + fun hasStateOwner(view: View): Boolean { + return hasStateOwner(view.generateId()) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -422,6 +546,27 @@ class SkeletonProperties : Cloneable, Reusable { } } + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * If true, Adds the given id and the state to the map of state owner. + * When false it will remove the state owner since there in no point of + * keeping a loaded owner's state. A state owner will own the state of those + * bones or skeletons belonging to it. If a state owner state changes it will + * also change the state of the views it owns. + * + * @param view The state owner view. + * @param state The state of the state owner + * + * @see BoneProperties + */ + @Synchronized + fun setStateOwner(view: View, state: Boolean) { + setStateOwner(view.generateId(), state) + } + /** * @Project Project Bones * @author Eudy Contreras @@ -438,6 +583,23 @@ class SkeletonProperties : Cloneable, Reusable { stateOwners.remove(ownerId) } + + /** + * @Project Project Bones + * @author Eudy Contreras + * @since March 2020 + * + * Removes the given id from the mpa of state owners. + * + * @param view The state owner view. + * + * @see BoneProperties + */ + @Synchronized + fun removeStateOwner(view: View) { + removeStateOwner(view.generateId()) + } + /** * @Project Project Bones * @author Eudy Contreras From 8ceca0ec2927cc956ee2b33940da5a7e1a43ed40 Mon Sep 17 00:00:00 2001 From: Eudy Contreras Date: Sun, 28 Feb 2021 14:02:41 +0100 Subject: [PATCH 9/9] Fixes https://github.com/EudyContreras/Skeleton-Bones/issues/16 --- .../bindings/SkeletonBoneBindings.kt | 73 +++++++++++++------ .../framework/skeletons/SkeletonDrawable.kt | 8 +- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt index c264c53..669b141 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/bindings/SkeletonBoneBindings.kt @@ -22,6 +22,7 @@ import com.eudycontreras.boneslibrary.properties.CornerRadii import com.eudycontreras.boneslibrary.properties.MutableColor import com.eudycontreras.boneslibrary.properties.ShapeType import com.eudycontreras.boneslibrary.tryWith +import java.util.* /** * Copyright (C) 2020 Bones @@ -326,6 +327,11 @@ internal fun View.setSkeletonBoneEnabledAndProps(enabled: Boolean?, boneProps: B } } +private fun withBuilder(action: () -> Unit) { + action() + SkeletonDrawable.builderList.add(action) +} + @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_PROPERTY_PROPS) internal fun View.setSkeletonBoneProps(boneProps: BoneProperties? = null) { val ownerId = generateId() @@ -435,7 +441,18 @@ internal fun View.setSkeletonBoneToggleView(toggleView: Boolean?) { this.toggleView = toggleView ?: true } } else { - setSkeletonBoneToggleView(toggleView) + setBoneToggleView(toggleView) + } +} + +private fun View.setBoneToggleView(toggleView: Boolean?) { + doWith(foreground) { + if (it is BoneDrawable) { + it.getProps().toggleView = toggleView ?: false + } else { + addBoneLoader(enabled = true) + setBoneToggleView(toggleView) + } } } @@ -449,12 +466,23 @@ internal fun View.setSkeletonBoneMatchBounds(matchBounds: Boolean?) { this.matchOwnersBounds = matchBounds ?: false } } else { - setSkeletonBoneMatchBounds(matchBounds) + setBoneMatchBounds(matchBounds) + } +} + +private fun View.setBoneMatchBounds(matchBounds: Boolean?) { + doWith(foreground) { + if (it is BoneDrawable) { + it.getProps().matchOwnersBounds = matchBounds ?: false + } else { + addBoneLoader(enabled = true) + setBoneMatchBounds(matchBounds) + } } } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_SHAPE_TYPE) -internal fun View.setSkeletonBoneShapeType(shapeType: ShapeType?) { +internal fun View.setSkeletonBoneShapeType(shapeType: ShapeType?) = withBuilder { val ownerId = generateId() val parent = getParentSkeletonDrawable() @@ -479,13 +507,13 @@ private fun View.setBoneShapeType(shapeType: ShapeType?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_SECTION_DISTANCE) -internal fun View.setSkeletonBoneSectionDistance(@Dimension distance: Float?) { +internal fun View.setSkeletonBoneSectionDistance(@Dimension distance: Float?) = withBuilder builder@{ val ownerId = generateId() val parent = getParentSkeletonDrawable() if (parent != null) { parent.getProps().getBoneProps(ownerId).apply { - this.sectionDistance = distance ?: return + this.sectionDistance = distance ?: return@builder } } else { setBoneSectionDistance(distance) @@ -505,7 +533,7 @@ private fun View.setBoneSectionDistance(@Dimension distance: Float?) { @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_COLOR) -internal fun View.setSkeletonBoneColor(@ColorInt boneColor: Int?) { +internal fun View.setSkeletonBoneColor(@ColorInt boneColor: Int?) = withBuilder { val ownerId = generateId() val parent = getParentSkeletonDrawable() @@ -530,7 +558,7 @@ private fun View.setBoneColor(@ColorInt boneColor: Int?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_SHADE_MULTIPLIER) -internal fun View.setSkeletonBoneShadeMultiplier(shadeMultiplier: Float?) { +internal fun View.setSkeletonBoneShadeMultiplier(shadeMultiplier: Float?) = withBuilder { val ownerId = generateId() val parent = getParentSkeletonDrawable() @@ -556,7 +584,7 @@ private fun View.setBoneShadeMultiplier(shadeMultiplier: Float?) { @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_CORNER_RADIUS) -internal fun View.setSkeletonBoneCorners(cornerRadius: Float?) { +internal fun View.setSkeletonBoneCorners(cornerRadius: Float?) = withBuilder { val ownerId = generateId() val parent = getParentSkeletonDrawable() @@ -581,7 +609,7 @@ private fun View.setBoneCorners(cornerRadius: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_TRANSITION_DURATION) -internal fun View.setSkeletonBoneTransitionDuration(duration: Long?) { +internal fun View.setSkeletonBoneTransitionDuration(duration: Long?) = withBuilder { val ownerId = generateId() val parent = getParentSkeletonDrawable() @@ -606,7 +634,7 @@ private fun View.setBoneTransitionDuration(duration: Long?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_WIDTH) -internal fun View.setSkeletonBoneWidth(width: Float?) { +internal fun View.setSkeletonBoneWidth(width: Float?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { it.getProps().getBoneProps(ownerId).apply { @@ -616,7 +644,7 @@ internal fun View.setSkeletonBoneWidth(width: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_MIN_WIDTH) -internal fun View.setSkeletonBoneMinWidth(minWidth: Float?) { +internal fun View.setSkeletonBoneMinWidth(minWidth: Float?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { it.getProps().getBoneProps(ownerId).apply { @@ -625,9 +653,8 @@ internal fun View.setSkeletonBoneMinWidth(minWidth: Float?) { } } - @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_HEIGHT) -internal fun View.setSkeletonBoneHeight(height: Float?) { +internal fun View.setSkeletonBoneHeight(height: Float?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { it.getProps().getBoneProps(ownerId).apply { @@ -637,7 +664,7 @@ internal fun View.setSkeletonBoneHeight(height: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_MIN_HEIGHT) -internal fun View.setSkeletonBoneMinHeight(minHeight: Float?) { +internal fun View.setSkeletonBoneMinHeight(minHeight: Float?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { it.getProps().getBoneProps(ownerId).apply { @@ -647,13 +674,13 @@ internal fun View.setSkeletonBoneMinHeight(minHeight: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_MIN_THICKNESS) -internal fun View.setSkeletonBoneMinThickness(thickness: Float?) { +internal fun View.setSkeletonBoneMinThickness(thickness: Float?) = withBuilder builder@{ val ownerId = generateId() val parent = getParentSkeletonDrawable() if (parent != null) { parent.getProps().getBoneProps(ownerId).apply { - this.minThickness = thickness ?: return + this.minThickness = thickness ?: return@builder } } else { setBoneMinThickness(thickness) @@ -672,13 +699,13 @@ private fun View.setBoneMinThickness(thickness: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_MAX_THICKNESS) -internal fun View.setSkeletonBoneMaxThickness(thickness: Float?) { +internal fun View.setSkeletonBoneMaxThickness(thickness: Float?) = withBuilder builder@{ val ownerId = generateId() val parent = getParentSkeletonDrawable() if (parent != null) { parent.getProps().getBoneProps(ownerId).apply { - this.maxThickness = thickness ?: return + this.maxThickness = thickness ?: return@builder } } else { setBoneMaxThickness(thickness) @@ -697,7 +724,7 @@ private fun View.setBoneMaxThickness(thickness: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_SIZE) -internal fun View.setSkeletonBoneSize(value: Float?) { +internal fun View.setSkeletonBoneSize(value: Float?) = withBuilder { tryWith { setSkeletonBoneWidth(value) setSkeletonBoneHeight(value) @@ -705,7 +732,7 @@ internal fun View.setSkeletonBoneSize(value: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_TRANSLATION_X) -internal fun View.setSkeletonBoneTranslationX(@Dimension translation: Float?) { +internal fun View.setSkeletonBoneTranslationX(@Dimension translation: Float?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { it.getProps().getBoneProps(ownerId).apply { @@ -715,7 +742,7 @@ internal fun View.setSkeletonBoneTranslationX(@Dimension translation: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_TRANSLATION_Y) -internal fun View.setSkeletonBoneTranslationY(@Dimension translation: Float?) { +internal fun View.setSkeletonBoneTranslationY(@Dimension translation: Float?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { it.getProps().getBoneProps(ownerId).apply { @@ -725,7 +752,7 @@ internal fun View.setSkeletonBoneTranslationY(@Dimension translation: Float?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_DISSECT_LARGE) -internal fun View.setSkeletonBoneDissectLargeBones(dissect: Boolean?) { +internal fun View.setSkeletonBoneDissectLargeBones(dissect: Boolean?) = withBuilder { val ownerId = generateId() val parent = getParentSkeletonDrawable() @@ -750,7 +777,7 @@ private fun View.setBoneDissectLargeBones(dissect: Boolean?) { } @BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_IGNORED) -internal fun View.setSkeletonIgnored(ignored: Boolean?) { +internal fun View.setSkeletonIgnored(ignored: Boolean?) = withBuilder { val ownerId = generateId() getParentSkeletonDrawable()?.let { val props = it.getProps() diff --git a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt index f9435f6..0bac797 100644 --- a/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt +++ b/boneslibrary/src/main/java/com/eudycontreras/boneslibrary/framework/skeletons/SkeletonDrawable.kt @@ -22,6 +22,7 @@ import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable import com.eudycontreras.boneslibrary.framework.skeletons.SkeletonDrawable.Companion.create import com.eudycontreras.boneslibrary.properties.CornerRadii import com.eudycontreras.boneslibrary.tryGet +import java.util.* /** * Copyright (C) 2020 Bones @@ -137,13 +138,16 @@ class SkeletonDrawable internal constructor( owner?.let { viewGroup -> viewGroup.doOnLayout { if (field) { + while (builderList.peek() != null) { + builderList.poll()?.invoke() + } skeletonManager.getBuilder().applyBuilders() skeletonManager.getSkeleton().compute(field, viewGroup) { skeletonManager.showSkeleton(field) invalidateSelf() } } else { - + builderList.clear() skeletonManager.showSkeleton(field) invalidateSelf() } @@ -329,6 +333,8 @@ class SkeletonDrawable internal constructor( } companion object { + internal val builderList: Queue<() -> Unit> = LinkedList() + /** * Creates an instance of a SkeletonDrawable. The drawable is directly * attached to the ViewGroup passed in the constructor. The SkeletonDrawable can