Skip to content

Commit

Permalink
Merge pull request #12 from EudyContreras/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
EudyContreras authored Apr 11, 2020
2 parents ba727cf + 67de3b3 commit 2993591
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 78 deletions.
2 changes: 2 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Dev Site Banner](media/images/android_dev_site_banner.png)](https://medium.com/android-dev-site)

<div align="center">

![Banner Demo](./media/gifs/wide_banner_white.gif)
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Dev Site Banner](media/images/android_dev_site_banner.png)](https://medium.com/android-dev-site)

<div align="center">

Expand Down
1 change: 1 addition & 0 deletions DEMOS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Dev Site Banner](media/images/android_dev_site_banner.png)](https://medium.com/android-dev-site)

<div align="center">

Expand Down
45 changes: 42 additions & 3 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,49 @@
[![Dev Site Banner](media/images/android_dev_site_banner.png)](https://medium.com/android-dev-site)

<div align="center">

![Banner Demo](./media/gifs/wide_banner_white.gif)

## Examples coming soon!

</div>

## Using Skeleton Bones with Glide

Bones can be easily combined with glide by allowing the glide request callback to notify the skeleton drawable that the image load process is completed. This can be done through the **`image.notifySkeletonImageLoaded()`** extension which is available for ImageViews.

```kotlin
Glide.with(context)
.load(imageUrl)
.addListener(object : RequestListener<Drawable> {
override fun onLoadFailed(
exception: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
return this@loadImage.notifySkeletonImageLoaded()
}

override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
return this@loadImage.notifySkeletonImageLoaded()
}

})
.apply(RequestOptions().format(DecodeFormat.PREFER_ARGB_8888))
.into(this)

```

Assuming that the skeleton or shimmer effect is being shown for the image being loaded, calling the **`image.notifySkeletonImageLoaded()`** extension function will switch the loading state to false and it will remove any actve shimmer effects or skeletons.

The extension function allows this to work with any image loader that allows listening to request results. If the target ImageView is within a SkeletonParent, you must allow the image view to be its own state owner by setting the **` skeletonBoneStateOwener`** attribute to true. This only needed if you allowing the image view to listen to state changes with the **`skeletonBoneEnabled`** flag.

### More examples coming soon!

You are welcome to try out the demo app and inspect the xml for a full
live example of Bones.
live example of Bones.
44 changes: 24 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
[banner]: ./media/gifs/section_stripe_white.gif
[thick-banner]: ./media/gifs/wide_banner_white.gif

[![Dev Nation Banner](./media/images/android_dev_nation_banner_orig.png)](https://medium.com/android-dev-nation)

> **Android Developer Nation** is a developer driven community dedicated to sharing high quality resources and libraries. At dev-nation we the goal is to push the boundaries of the android platform and deliver top of the line and completely open source libraries for the android community. If you can sing our anthem and would like to contribute, you are more than welcome. 🏆
[![Dev Site Banner](./media/images/android_dev_site_banner.png)](https://medium.com/android-dev-site)
> **Android Developer Site** is a developer driven community dedicated to sharing high quality resources and libraries. At dev-site the goal is to push the boundaries of the android platform and deliver top of the line and completely open source libraries and resources for the android community. If you can sing our anthem and would like to contribute, you are more than welcome. 🏆
> ***"By developers for developers"***
![Banner Demo][thick-banner]
Expand Down Expand Up @@ -60,6 +59,27 @@ Library for dynamically generating and animating skeleton drawables. This librar
- **[Disclaimers](#disclaimer)**
- **[License](#license)**

<div align="center">

![Header Banner][banner]
# Resources
</div>

For a more thorough guides and descriptions please look at the following links:

[**Skeleton**](./docs/elements/SKELETON.md) Contains information about skeletons and their properties

[**Skeleton Bones**](./docs/elements/SKELETON_BONE.md) Contains information about bones and their properties

[**Shimmer Rays**](./docs/elements/SHIMMER_RAY.md) Contains information about shimmer rays and their properties

[**Shimmer Rays**](./docs/elements/BONE_SHIMMER_RAY.md) Contains information about shimmer rays and their properties

[**Examples**](./EXAMPLES.md) Contains examples and technical and technical guides
<br/>
<br/>


<div align="center">

![Header Banner][banner]
Expand Down Expand Up @@ -296,6 +316,7 @@ The following are bone properties that can be access through any View. Some of t
|:----------|:-----------|
|**app:skeletonBoneProps** | A reference to a **BoneProperties** object |
|**app:skeletonBoneEnabled** | Enables/Disables the loading state for the bone |
|**app:skeletonBoneStateOwner** | Marks the target view as an independent state owner|
|**app:skeletonBoneColor** |Determines the color of the bone generated for this view|
|**app:skeletonBoneToggleView** | When true, the bone owner view is hidden while loading. |
|**app:skeletonBoneShadeMultiplier** | Sets a shade multiplier use for lightening or darkening the bone color |
Expand Down Expand Up @@ -385,23 +406,6 @@ The BoneProperty holder can make use of the following properties. For a detailed
>A view can refer to a **BonePropertyHolder** using its id through the **`app:skeletonBonePropId`** attribute. In order to override the properties set in the referenced property holder, the attributes must be prepended with `prop_`. Example: **`app:prop_skeletonBoneColor`**
<br/>
<br/>
<div align="center">

![Header Banner][banner]
# Resources
</div>

For a more thorough guides and descriptions please look at the following links:

[**Skeleton**](./docs/elements/SKELETON.md) Contains information about skeletons and their properties

[**Skeleton Bones**](./docs/elements/SKELETON_BONE.md) Contains information about bones and their properties

[**Shimmer Rays**](./docs/elements/SHIMMER_RAY.md) Contains information about shimmer rays and their properties
<br/>
<br/>

<div align="center">
![Header Banner][banner]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ object SkeletonBoneBindings {
* **Binding Property**: app:skeletonBoneEnabled
*/
const val SKELETON_BONE_ENABLED = "skeletonBoneEnabled"
/**
* **Binding Property**: app:skeletonBoneStateOwner
*/
const val SKELETON_BONE_STATE_OWNER = "skeletonBoneStateOwner"
/**
* **Binding Property**: app:skeletonBoneColor
*/
Expand Down Expand Up @@ -312,6 +316,19 @@ internal fun View.setSkeletonBoneEnabled(enabled: Boolean?) {
}
}

@BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_STATE_OWNER)
internal fun View.setSkeletonBoneStateOwner(stateOwner: Boolean?) {
val id = generateId()
val parent = getParentSkeletonDrawable()

if (parent != null) {
parent.getProps().setStateOwner(id, stateOwner ?: true)
} else {
addBoneLoader(enabled = true)
setSkeletonBoneStateOwner(stateOwner)
}
}

@BindingAdapter(SkeletonBoneBindings.SKELETON_BONE_BACKGROUND)
internal fun View.setSkeletonBoneBackground(background: Drawable?) {
doWith(foreground) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.eudycontreras.boneslibrary.extensions

import android.widget.ImageView
import com.eudycontreras.boneslibrary.bindings.getParentSkeletonDrawable
import com.eudycontreras.boneslibrary.doWith
import com.eudycontreras.boneslibrary.framework.bones.BoneDrawable

/**
* Copyright (C) 2020 Bones
*
* @Project Project Bones
* @author Eudy Contreras.
* @since March 2020
*
* Notifies the backing bone for this ImageView that the image has
* been loaded.
*/

fun ImageView.notifySkeletonImageLoaded(): Boolean {
val id = generateId()
val parent = getParentSkeletonDrawable()
if (parent != null) {
parent.getProps().setStateOwner(id, false)
parent.getProps().getBoneProps(id).apply {
this.enabled = false
return true
}
}
doWith(foreground) {
if (it is BoneDrawable) {
it.getProps().enabled = false
return true
}
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.core.view.*
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.properties.Bounds
import com.eudycontreras.boneslibrary.properties.MutableColor
import java.lang.ref.WeakReference

Expand Down Expand Up @@ -40,7 +41,6 @@ internal fun View.generateId(): Int {
}
} else id
}

/**
* Applies a skeleton drawable to this ViewGroup
*/
Expand All @@ -55,6 +55,24 @@ fun View.applyBoneDrawable(): BoneDrawable {
return BoneDrawable.create(this)
}

fun View.compareBounds(bounds: Bounds): Int {
val xDiff = left - bounds.left.toInt()
val yDiff = top - bounds.top.toInt()
val widthDiff = measuredWidth - bounds.width.toInt()
val heightDiff = measuredHeight - bounds.height.toInt()

return xDiff + yDiff + widthDiff + heightDiff
}

fun View.getBounds(): Bounds {
return Bounds(
x = this.left.toFloat(),
y = this.top.toFloat(),
width = this.measuredWidth.toFloat(),
height = this.measuredHeight.toFloat()
)
}

fun View.hasValidMinBounds(boneProps: BoneProperties): Boolean {
boneProps.minHeight?.let {
if (measuredHeight < it) {
Expand All @@ -74,8 +92,7 @@ fun View.hasValidBounds(): Boolean {
}

fun View.hasDrawableBounds(boneProps: BoneProperties): Boolean {
val minThickness = boneProps.minThickness ?: BoneProperties.MIN_THICKNESS
return (measuredWidth > 0 && measuredHeight > minThickness)
return (measuredWidth > 0 && measuredHeight > boneProps.minThickness)
}

internal fun View.getBackgroundColor(): MutableColor? {
Expand Down Expand Up @@ -167,6 +184,19 @@ internal fun ViewGroup.descendantViews(predicate: ((view: View) -> Boolean)? = n
return views
}

internal fun ViewGroup.removeAllViews(predicate: ((view: View) -> Boolean)? = null) {
val views = mutableListOf<View>()
findViews(this, predicate, views)
views.forEach {
it.removeFromHierarchy()
}
}

internal fun View.removeFromHierarchy() {
val parent = parent as? ViewGroup?
parent?.removeView(this)
}

private fun findViews(
viewGroup: ViewGroup,
predicate: ((View) -> Boolean)? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ internal class Skeleton(
}
if (isDirty) {
owner?.let { recomputeAndBuild(it) }
isDirty = false
}
}

Expand Down Expand Up @@ -222,6 +223,7 @@ internal class Skeleton(
}
val bone = bones[id] ?: SkeletonBone.build(
view = child,
skeleton = this,
properties = props,
skeletonProperties = properties,
manager = manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.eudycontreras.boneslibrary.framework.bones.BoneProperties
import com.eudycontreras.boneslibrary.framework.bones.BoneProperties.Companion.HEIGHT_THRESHOLD
import com.eudycontreras.boneslibrary.framework.bones.BoneProperties.Companion.OVERFLOW_THRESHOLD
import com.eudycontreras.boneslibrary.framework.shimmer.ShimmerRay
import com.eudycontreras.boneslibrary.properties.Bounds
import com.eudycontreras.boneslibrary.properties.Color
import com.eudycontreras.boneslibrary.properties.CornerRadii
import com.eudycontreras.boneslibrary.properties.ShapeType
Expand All @@ -30,6 +31,7 @@ import kotlin.math.abs

internal class SkeletonBone(
val owner: View,
val parentSkeleton: Skeleton,
val boneProperties: BoneProperties,
private val skeletonProperties: SkeletonProperties
) : DrawableShape(), FadeTarget, UpdateTarget, Disposable, ContentLoader {
Expand All @@ -42,6 +44,8 @@ internal class SkeletonBone(

private var offsetViewBounds = Rect()

private var viewBounds = Bounds()

private fun getLength(owner: View): Float {
val ownerWidth = owner.width.toFloat() - (owner.horizontalMargin)
return boneProperties.width ?: ownerWidth
Expand Down Expand Up @@ -118,6 +122,8 @@ internal class SkeletonBone(
val relativeTop: Float = offsetViewBounds.centerY().toFloat()
val allowShadows = drawShadows && skeletonProperties.allowShadows && boneProperties.toggleView

this.viewBounds = view.getBounds()

this.shapeType = boneProperties.shapeType ?: shapeType

this.opacity = Color.MAX_COLOR
Expand Down Expand Up @@ -217,6 +223,9 @@ internal class SkeletonBone(
override fun onUpdate(fraction: Float) {
if (boneProperties.isDisposed) return

if (owner.compareBounds(viewBounds) != 0) {
parentSkeleton.isDirty = true
}
if (shimmerRays.size > 0) {
for (ray in shimmerRays) {
ray.onUpdate(fraction)
Expand Down Expand Up @@ -355,12 +364,14 @@ internal class SkeletonBone(
@JvmStatic
fun build(
view: View,
skeleton: Skeleton,
properties: BoneProperties,
skeletonProperties: SkeletonProperties,
manager: SkeletonManager
): SkeletonBone {
return SkeletonBone(
owner = view,
parentSkeleton = skeleton,
boneProperties = properties,
skeletonProperties = skeletonProperties
).apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ class SkeletonDrawable internal constructor(
field = value
owner?.let { viewGroup ->
viewGroup.doOnLayout {
skeletonManager.getSkeleton().compute(field, viewGroup) {
if (field) {
skeletonManager.getSkeleton().compute(field, viewGroup) {
skeletonManager.showSkeleton(field)
invalidateSelf()
}
} else {
skeletonManager.showSkeleton(field)
invalidateSelf()
}
Expand Down
Loading

0 comments on commit 2993591

Please sign in to comment.