diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 36842b5..65da200 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -23,6 +23,7 @@
app:backgroundColor="@color/colorPrimary"
app:textColor="@color/colorTextPrimary"
app:textSize="14sp"
+ app:cornerRadius="10dp"
app:iconSize="24dp"
app:indicatorColor="#2DFFFFFF"
app:indicatorRadius="10dp"
diff --git a/lib/src/main/java/me/ibrahimsn/lib/Constants.kt b/lib/src/main/java/me/ibrahimsn/lib/Constants.kt
index 168ff1b..ebdd2b7 100644
--- a/lib/src/main/java/me/ibrahimsn/lib/Constants.kt
+++ b/lib/src/main/java/me/ibrahimsn/lib/Constants.kt
@@ -19,8 +19,12 @@ object Constants {
const val DEFAULT_ICON_MARGIN = 4F
const val DEFAULT_TEXT_SIZE = 11F
const val DEFAULT_CORNER_RADIUS = 20F
+ const val DEFAULT_BAR_CORNER_RADIUS = 0F
const val OPAQUE = 255
const val TRANSPARENT = 0
+
+ const val COS_45 = 0.525321988
+ const val SHADOW_MULTIPLIER = 1.5f
}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/RoundRectDrawable.kt b/lib/src/main/java/me/ibrahimsn/lib/RoundRectDrawable.kt
new file mode 100644
index 0000000..83ec729
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/RoundRectDrawable.kt
@@ -0,0 +1,237 @@
+/*
+* Copyright 2020 Brook Mezgebu
+* Copyright 2018 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package me.ibrahimsn.lib
+
+import android.content.res.ColorStateList
+import android.graphics.*
+import android.graphics.drawable.Drawable
+import androidx.annotation.RequiresApi
+import me.ibrahimsn.lib.Constants.COS_45
+import me.ibrahimsn.lib.Constants.SHADOW_MULTIPLIER
+import kotlin.math.ceil
+
+/**
+ * Very simple drawable that draws a rounded rectangle background with arbitrary corners and also
+ * reports proper outline for Lollipop.
+ *
+ *
+ * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable.
+ */
+@RequiresApi(21)
+class RoundRectDrawable( backgroundColor: ColorStateList?, private var mRadius: Float,
+ private val topLeft: Boolean = false,
+ private val topRight: Boolean = false,
+ private val bottomLeft: Boolean = false,
+ private val bottomRight: Boolean = false
+) : Drawable() {
+
+ private val mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
+ private val mBoundsF: RectF
+ private val mBoundsI: Rect
+
+ var padding = 0f
+ private set
+
+ private var mInsetForPadding = false
+ private var mInsetForRadius = true
+ private var mBackground: ColorStateList? = null
+ private var mTintFilter: PorterDuffColorFilter? = null
+ private var mTint: ColorStateList? = null
+ private var mTintMode: PorterDuff.Mode? = PorterDuff.Mode.SRC_IN
+
+ private fun setBackground(color: ColorStateList?) {
+ mBackground = color ?: ColorStateList.valueOf(Color.TRANSPARENT)
+ mPaint.color = mBackground?.getColorForState(state, mBackground?.defaultColor ?: Color.TRANSPARENT) ?: Color.TRANSPARENT
+ }
+
+ fun setPadding( padding: Float, insetForPadding: Boolean, insetForRadius: Boolean) {
+ if (padding == this.padding && mInsetForPadding == insetForPadding && mInsetForRadius == insetForRadius) {
+ return
+ }
+
+ this.padding = padding
+ mInsetForPadding = insetForPadding
+ mInsetForRadius = insetForRadius
+ updateBounds(null)
+ invalidateSelf()
+ }
+
+ override fun draw(canvas: Canvas) {
+ val paint = mPaint
+ val clearColorFilter: Boolean
+ if (mTintFilter != null && paint.colorFilter == null) {
+ paint.colorFilter = mTintFilter
+ clearColorFilter = true
+ } else clearColorFilter = false
+
+ canvas.drawPath(
+ Util.roundedRect(mBoundsF, mRadius, mRadius, topLeft, topRight, bottomRight, bottomLeft),
+ paint
+ );
+
+ if (clearColorFilter) {
+ paint.colorFilter = null
+ }
+ }
+
+ private fun calculateVerticalPadding(maxShadowSize: Float, cornerRadius: Float, addPaddingForCorners: Boolean): Float {
+ return if (addPaddingForCorners) {
+ (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius).toFloat()
+ } else {
+ maxShadowSize * SHADOW_MULTIPLIER
+ }
+ }
+
+ private fun calculateHorizontalPadding(
+ maxShadowSize: Float, cornerRadius: Float,
+ addPaddingForCorners: Boolean
+ ): Float {
+ return if (addPaddingForCorners) {
+ (maxShadowSize + (1 - COS_45) * cornerRadius).toFloat()
+ } else {
+ maxShadowSize
+ }
+ }
+
+ private fun updateBounds(bounds: Rect?) {
+ var bounds = bounds
+
+ if (bounds == null) bounds = getBounds()
+
+ mBoundsF[bounds!!.left.toFloat(), bounds.top.toFloat(), bounds.right.toFloat()] = bounds.bottom.toFloat()
+ mBoundsI.set(bounds)
+
+ if (mInsetForPadding) {
+ val vInset: Float = calculateVerticalPadding(
+ padding,
+ mRadius,
+ mInsetForRadius
+ )
+
+ val hInset: Float = calculateHorizontalPadding(
+ padding,
+ mRadius,
+ mInsetForRadius
+ )
+
+ mBoundsI.inset(
+ ceil(hInset.toDouble()).toInt(),
+ ceil(vInset.toDouble()).toInt()
+ )
+
+ // to make sure they have same bounds.
+ mBoundsF.set(mBoundsI)
+ }
+ }
+
+ override fun onBoundsChange(bounds: Rect) {
+ super.onBoundsChange(bounds)
+ updateBounds(bounds)
+ }
+
+ override fun getOutline(outline: Outline) {
+ outline.setConvexPath(
+ Util.roundedRect(mBoundsF,
+ mRadius, mRadius,
+ tl = topLeft, tr = topRight, br = bottomRight, bl = bottomLeft
+ )
+ )
+ }
+
+ override fun setAlpha(alpha: Int) {
+ mPaint.alpha = alpha
+ }
+
+ override fun setColorFilter(cf: ColorFilter) {
+ mPaint.colorFilter = cf
+ }
+
+ override fun getOpacity(): Int {
+ return PixelFormat.TRANSLUCENT
+ }
+
+ var radius: Float
+ get() = mRadius
+ set(radius) {
+ if (radius == mRadius) {
+ return
+ }
+ mRadius = radius
+ updateBounds(null)
+ invalidateSelf()
+ }
+
+ var color: ColorStateList?
+ get() = mBackground
+ set(color) {
+ setBackground(color)
+ invalidateSelf()
+ }
+
+ override fun setTintList(tint: ColorStateList) {
+ mTint = tint
+ mTintFilter = createTintFilter(mTint, mTintMode)
+ invalidateSelf()
+ }
+
+ override fun setTintMode(tintMode: PorterDuff.Mode) {
+ mTintMode = tintMode
+ mTintFilter = createTintFilter(mTint, mTintMode)
+ invalidateSelf()
+ }
+
+ override fun onStateChange(stateSet: IntArray): Boolean {
+ val newColor =
+ mBackground!!.getColorForState(stateSet, mBackground!!.defaultColor)
+ val colorChanged = newColor != mPaint.color
+ if (colorChanged) {
+ mPaint.color = newColor
+ }
+ if (mTint != null && mTintMode != null) {
+ mTintFilter = createTintFilter(mTint, mTintMode)
+ return true
+ }
+ return colorChanged
+ }
+
+ override fun isStateful(): Boolean {
+ return (mTint != null && mTint!!.isStateful
+ || mBackground != null && mBackground!!.isStateful || super.isStateful())
+ }
+
+ /**
+ * Ensures the tint filter is consistent with the current tint color and
+ * mode.
+ */
+ private fun createTintFilter(
+ tint: ColorStateList?,
+ tintMode: PorterDuff.Mode?
+ ): PorterDuffColorFilter? {
+ if (tint == null || tintMode == null) {
+ return null
+ }
+ val color = tint.getColorForState(state, Color.TRANSPARENT)
+ return PorterDuffColorFilter(color, tintMode)
+ }
+
+ init {
+ setBackground(backgroundColor)
+ mBoundsF = RectF()
+ mBoundsI = Rect()
+ }
+}
\ No newline at end of file
diff --git a/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt b/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt
index 1fe8b9a..46807da 100644
--- a/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt
+++ b/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt
@@ -4,10 +4,12 @@ import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
+import android.content.res.ColorStateList
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
+import android.os.Build
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
@@ -16,6 +18,7 @@ import androidx.annotation.FontRes
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
import me.ibrahimsn.lib.Constants.DEFAULT_ANIM_DURATION
+import me.ibrahimsn.lib.Constants.DEFAULT_BAR_CORNER_RADIUS
import me.ibrahimsn.lib.Constants.DEFAULT_CORNER_RADIUS
import me.ibrahimsn.lib.Constants.DEFAULT_ICON_MARGIN
import me.ibrahimsn.lib.Constants.DEFAULT_ICON_SIZE
@@ -38,6 +41,7 @@ class SmoothBottomBar : View {
private var barIndicatorColor = Color.parseColor(DEFAULT_INDICATOR_COLOR)
private var barIndicatorRadius = d2p(DEFAULT_CORNER_RADIUS)
private var barSideMargins = d2p(DEFAULT_SIDE_MARGIN)
+ private var barCornerRadius = d2p(DEFAULT_BAR_CORNER_RADIUS)
private var itemPadding = d2p(DEFAULT_ITEM_PADDING)
private var itemAnimDuration = DEFAULT_ANIM_DURATION
@@ -94,6 +98,7 @@ class SmoothBottomBar : View {
barIndicatorColor = typedArray.getColor(R.styleable.SmoothBottomBar_indicatorColor, this.barIndicatorColor)
barIndicatorRadius = typedArray.getDimension(R.styleable.SmoothBottomBar_indicatorRadius, this.barIndicatorRadius)
barSideMargins = typedArray.getDimension(R.styleable.SmoothBottomBar_sideMargins, this.barSideMargins)
+ barCornerRadius = typedArray.getDimension(R.styleable.SmoothBottomBar_cornerRadius, this.barCornerRadius)
itemPadding = typedArray.getDimension(R.styleable.SmoothBottomBar_itemPadding, this.itemPadding)
itemTextColor = typedArray.getColor(R.styleable.SmoothBottomBar_textColor, this.itemTextColor)
itemTextSize = typedArray.getDimension(R.styleable.SmoothBottomBar_textSize, this.itemTextSize)
@@ -106,7 +111,9 @@ class SmoothBottomBar : View {
items = BottomBarParser(context, typedArray.getResourceId(R.styleable.SmoothBottomBar_menu, 0)).parse()
typedArray.recycle()
- setBackgroundColor(barBackgroundColor)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ background = RoundRectDrawable(ColorStateList.valueOf(barBackgroundColor), barCornerRadius, topLeft = true, topRight = true)
+ } else setBackgroundColor(barBackgroundColor)
// Update default attribute values
paintIndicator.color = barIndicatorColor
diff --git a/lib/src/main/java/me/ibrahimsn/lib/Util.kt b/lib/src/main/java/me/ibrahimsn/lib/Util.kt
new file mode 100644
index 0000000..45d6423
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/Util.kt
@@ -0,0 +1,37 @@
+package me.ibrahimsn.lib
+
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.os.Build
+import androidx.annotation.RequiresApi
+
+/**
+ * Created by BrookMG on 3/29/2020 in me.ibrahimsn.lib
+inside the project SmoothBottomBar .
+ */
+class Util {
+
+ companion object {
+
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ fun roundedRect(
+ rect: RectF,
+ rx: Float, ry: Float,
+ tl: Boolean, tr: Boolean, br: Boolean, bl: Boolean
+ ): Path {
+ val path = Path();
+ val corners: FloatArray = floatArrayOf(
+ (if (tl) rx else 0f), (if (tl) ry else 0f),
+ (if (tr) rx else 0f), (if (tr) ry else 0f),
+ (if (br) rx else 0f), (if (br) ry else 0f),
+ (if (bl) rx else 0f), (if (bl) ry else 0f)
+ );
+
+ path.addRoundRect(rect, corners, Path.Direction.CW)
+ return path
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/lib/src/main/res/values/attrs.xml b/lib/src/main/res/values/attrs.xml
index 2333acb..1358e0b 100644
--- a/lib/src/main/res/values/attrs.xml
+++ b/lib/src/main/res/values/attrs.xml
@@ -14,6 +14,7 @@
+