Skip to content

Commit

Permalink
Merge branch 'add-option-for-internal-offset' into development
Browse files Browse the repository at this point in the history
  • Loading branch information
markormesher committed Sep 2, 2018
2 parents a11e62b + 859e548 commit f4944a8
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 21 deletions.
20 changes: 19 additions & 1 deletion README.md
Expand Up @@ -31,7 +31,7 @@ You can try the demo in one of two ways:

---

Note: depending on your app's configuration, you may need to add the following to your ProGuard rules:
**Note:** depending on your app's configuration, you may need to add the following to your ProGuard rules:

-dontwarn java.lang.invoke.*

Expand Down Expand Up @@ -76,6 +76,24 @@ The FAB can be positioned in any of the four corners of the activity via XML or

The FAB is aware of text-direction (right-to-left or left-to-right) and adjusts the meaning of "start" and "end" positions accordingly. This functionality can be overridden using the named constants for left and right.

The FAB can be offset from any of the four edges to precisely control its location, although this is not needed in most applications. The offset can be added to the top, bottom, start, end, left or right of the view. Where left and/or right offsets are specified they will both take precedence over start/end offsets.

// Java
fab.setInternalOffsetBottom(40.0f); // pixels

// Kotlin
fab.setInternalOffsetBottom(40.0f) // pixels

// XML
<uk.co.markormesher.android_fab.FloatingActionButton
xmlns:app="http://schemas.android.com/apk/res-auto"
...
app:internalOffsetBottom="20dp"
app:internalOffsetEnd="@dimen/some_dimen"
/>

**Note:** any offset is applied *in addition to* the default spacing around the FAB. If you need to counter this, subtract the default spacing (`fab.getOriginalInternalOffset()` in Java or `fab.originalInternalOffset` in Kotlin) from the value you want to use.

### FAB Icon

The icon displayed in the centre of the FAB can be set via XML using a `Drawable` reference or with `fab.setButtonIconResource(...)` using a `Drawable` resource ID. The icon will be centred in a 24dp x 24dp view group, as per the Android Material Design specs.
Expand Down
Binary file added fab/.DS_Store
Binary file not shown.
Expand Up @@ -2,13 +2,15 @@ package uk.co.markormesher.android_fab

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.support.annotation.ColorInt
import android.support.annotation.Dimension
import android.support.annotation.DrawableRes
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.Snackbar
Expand All @@ -28,21 +30,39 @@ import uk.co.markormesher.android_fab.extensions.clearParentAlignmentRules
import uk.co.markormesher.android_fab.fab.R



@Suppress("MemberVisibilityCanBePrivate", "unused") // because we want to expose the methods to end users
class FloatingActionButton: RelativeLayout {

private val SPEED_DIAL_ANIMATION_DURATION = 200L
private val HIDE_SHOW_ANIMATION_DURATION = 100L
companion object {
private const val SPEED_DIAL_ANIMATION_DURATION = 200L
private const val HIDE_SHOW_ANIMATION_DURATION = 100L
const val POSITION_TOP = 1
const val POSITION_BOTTOM = 2
const val POSITION_START = 4
const val POSITION_END = 8
const val POSITION_LEFT = 16
const val POSITION_RIGHT = 32
}

private val layoutInflater by lazy { LayoutInflater.from(context) }
private val isRightToLeft by lazy { resources.getBoolean(R.bool.is_right_to_left) }
val originalInternalOffset by lazy { resources.getDimension(R.dimen.fab_offset) }

private var isShown: Boolean = true
override fun isShown() = isShown

// defaults for all user-controllable parameters
private var buttonPosition = POSITION_BOTTOM.or(POSITION_END)
private var buttonBackgroundColour = 0xff0099ff.toInt()
private var buttonIconResource = 0
private var contentCoverColour = 0xccffffff.toInt()
var contentCoverEnabled = true
private var internalOffsetTop = 0f
private var internalOffsetBottom = 0f
private var internalOffsetStart = 0f
private var internalOffsetEnd = 0f
private var internalOffsetLeft = 0f
private var internalOffsetRight = 0f

private var onClickListener: OnClickListener? = null
private var speedDialMenuOpenListener: SpeedDialMenuOpenListener? = null
Expand All @@ -63,15 +83,6 @@ class FloatingActionButton: RelativeLayout {
private var isBusyAnimating = false
get() = busyAnimatingFabIconRotation || busyAnimatingContentCover || busyAnimatingSpeedDialMenuItems

companion object {
const val POSITION_TOP = 1
const val POSITION_BOTTOM = 2
const val POSITION_START = 4
const val POSITION_END = 8
const val POSITION_LEFT = 16
const val POSITION_RIGHT = 32
}

constructor(context: Context):
super(context) {
initView(null)
Expand All @@ -97,6 +108,12 @@ class FloatingActionButton: RelativeLayout {
state.putInt("buttonIconResource", buttonIconResource)
state.putInt("contentCoverColour", contentCoverColour)
state.putBoolean("contentCoverEnabled", contentCoverEnabled)
state.putFloat("internalOffsetTop", internalOffsetTop)
state.putFloat("internalOffsetBottom", internalOffsetBottom)
state.putFloat("internalOffsetStart", internalOffsetStart)
state.putFloat("internalOffsetEnd", internalOffsetEnd)
state.putFloat("internalOffsetLeft", internalOffsetLeft)
state.putFloat("internalOffsetRight", internalOffsetRight)

return state
}
Expand Down Expand Up @@ -124,6 +141,24 @@ class FloatingActionButton: RelativeLayout {

contentCoverEnabled = state.getBoolean("contentCoverEnabled", contentCoverEnabled)

internalOffsetTop = state.getFloat("internalOffsetTop", internalOffsetTop)
setInternalOffsetTop(internalOffsetTop)

internalOffsetBottom = state.getFloat("internalOffsetBottom", internalOffsetBottom)
setInternalOffsetBottom(internalOffsetBottom)

internalOffsetStart = state.getFloat("internalOffsetStart", internalOffsetStart)
setInternalOffsetStart(internalOffsetStart)

internalOffsetEnd = state.getFloat("internalOffsetEnd", internalOffsetEnd)
setInternalOffsetEnd(internalOffsetEnd)

internalOffsetLeft = state.getFloat("internalOffsetLeft", internalOffsetLeft)
setInternalOffsetLeft(internalOffsetLeft)

internalOffsetRight = state.getFloat("internalOffsetRight", internalOffsetRight)
setInternalOffsetRight(internalOffsetRight)

super.onRestoreInstanceState(state.getParcelable("_super"))
} else {
super.onRestoreInstanceState(state)
Expand Down Expand Up @@ -153,6 +188,12 @@ class FloatingActionButton: RelativeLayout {
setButtonPosition(attrs.getInteger(R.styleable.FloatingActionButton_buttonPosition, buttonPosition))
setButtonBackgroundColour(attrs.getColor(R.styleable.FloatingActionButton_buttonBackgroundColour, buttonBackgroundColour))
setButtonIconResource(attrs.getResourceId(R.styleable.FloatingActionButton_buttonIcon, 0))
setInternalOffsetTop(attrs.getDimension(R.styleable.FloatingActionButton_internalOffsetTop, 0f))
setInternalOffsetBottom(attrs.getDimension(R.styleable.FloatingActionButton_internalOffsetBottom, 0f))
setInternalOffsetStart(attrs.getDimension(R.styleable.FloatingActionButton_internalOffsetStart, 0f))
setInternalOffsetEnd(attrs.getDimension(R.styleable.FloatingActionButton_internalOffsetEnd, 0f))
setInternalOffsetLeft(attrs.getDimension(R.styleable.FloatingActionButton_internalOffsetLeft, 0f))
setInternalOffsetRight(attrs.getDimension(R.styleable.FloatingActionButton_internalOffsetRight, 0f))
} finally {
attrs.recycle()
}
Expand Down Expand Up @@ -204,7 +245,6 @@ class FloatingActionButton: RelativeLayout {

private fun setSpeedDialMenuItemViewOrder(view: ViewGroup) {
var labelFirst = true
val isRightToLeft = resources.getBoolean(R.bool.is_right_to_left)
if (buttonPosition.and(POSITION_LEFT) > 0) {
labelFirst = false
}
Expand Down Expand Up @@ -233,7 +273,7 @@ class FloatingActionButton: RelativeLayout {
}

fun setButtonPosition(position: Int) {
this.buttonPosition = position
buttonPosition = position

setViewLayoutParams(fab_card)
setViewLayoutParams(content_cover)
Expand All @@ -242,7 +282,7 @@ class FloatingActionButton: RelativeLayout {
}

fun setButtonBackgroundColour(@ColorInt colour: Int) {
this.buttonBackgroundColour = colour
buttonBackgroundColour = colour
if (Build.VERSION.SDK_INT >= 21) {
(fab_card as CardView).setCardBackgroundColor(colour)
} else {
Expand All @@ -251,11 +291,65 @@ class FloatingActionButton: RelativeLayout {
}

fun setButtonIconResource(@DrawableRes icon: Int) {
this.buttonIconResource = icon
if (icon <= 0) {
fab_icon_wrapper.setBackgroundResource(0)
buttonIconResource = icon
fab_icon_wrapper.setBackgroundResource(icon)
}

fun setInternalOffsetTop(@Dimension offsetPixels: Float) {
internalOffsetTop = offsetPixels
updateInternalOffset()
}

fun setInternalOffsetBottom(@Dimension offsetPixels: Float) {
internalOffsetBottom = offsetPixels
updateInternalOffset()
}

fun setInternalOffsetStart(@Dimension offsetPixels: Float) {
internalOffsetStart = offsetPixels
updateInternalOffset()
}

fun setInternalOffsetEnd(@Dimension offsetPixels: Float) {
internalOffsetEnd = offsetPixels
updateInternalOffset()
}

fun setInternalOffsetLeft(@Dimension offsetPixels: Float) {
internalOffsetLeft = offsetPixels
updateInternalOffset()
}

fun setInternalOffsetRight(@Dimension offsetPixels: Float) {
internalOffsetRight = offsetPixels
updateInternalOffset()
}

private fun updateInternalOffset() {
// if left/right are explicitly set, use them
if (internalOffsetLeft != 0f || internalOffsetRight != 0f) {
container.setPadding(
(originalInternalOffset + internalOffsetLeft).toInt(),
(originalInternalOffset + internalOffsetTop).toInt(),
(originalInternalOffset + internalOffsetRight).toInt(),
(originalInternalOffset + internalOffsetBottom).toInt()
)
} else {
fab_icon_wrapper.setBackgroundResource(icon)
if (Build.VERSION.SDK_INT >= 17) {
container.setPaddingRelative(
(originalInternalOffset + internalOffsetStart).toInt(),
(originalInternalOffset + internalOffsetTop).toInt(),
(originalInternalOffset + internalOffsetEnd).toInt(),
(originalInternalOffset + internalOffsetBottom).toInt()
)
} else {
container.setPadding(
(originalInternalOffset + if (isRightToLeft) internalOffsetEnd else internalOffsetStart).toInt(),
(originalInternalOffset + internalOffsetTop).toInt(),
(originalInternalOffset + if (isRightToLeft) internalOffsetStart else internalOffsetEnd).toInt(),
(originalInternalOffset + internalOffsetBottom).toInt()
)
}
}
}

Expand Down Expand Up @@ -347,6 +441,7 @@ class FloatingActionButton: RelativeLayout {
for (i in (0 until adapter.getCount())) {
val menuItem = adapter.getMenuItem(context, i)

@SuppressLint("InflateParams") // because we handle attachment to root internally
val view = layoutInflater.inflate(R.layout.menu_item, null) as ViewGroup
container.addView(view)
speedDialMenuViews.add(view)
Expand Down Expand Up @@ -409,7 +504,7 @@ class FloatingActionButton: RelativeLayout {
content_cover.isClickable = isSpeedDialMenuOpen
content_cover.isFocusable = isSpeedDialMenuOpen
if (isSpeedDialMenuOpen) {
content_cover.setOnClickListener({ toggleSpeedDialMenu() })
content_cover.setOnClickListener { toggleSpeedDialMenu() }
} else {
content_cover.setOnClickListener(null)
}
Expand Down
7 changes: 7 additions & 0 deletions fab/src/main/res/values/attrs.xml
Expand Up @@ -15,5 +15,12 @@

<attr name="buttonBackgroundColour" format="color"/>

<attr name="internalOffsetTop" format="dimension"/>
<attr name="internalOffsetBottom" format="dimension"/>
<attr name="internalOffsetStart" format="dimension"/>
<attr name="internalOffsetEnd" format="dimension"/>
<attr name="internalOffsetLeft" format="dimension"/>
<attr name="internalOffsetRight" format="dimension"/>

</declare-styleable>
</resources>

0 comments on commit f4944a8

Please sign in to comment.