Instantly share code, notes, and snippets.
Created
October 25, 2021 14:22
-
Star
(1)
1
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save bleszerd/7320e831d10b15bfc1aa073b75569be4 to your computer and use it in GitHub Desktop.
IconifiedRoundedButton
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @Author: Vinícius "Bleszerd" Resende | |
* @Contact [email protected] | |
* @Date: 25/10/2021 | |
*/ | |
class RoundedButton @JvmOverloads constructor( | |
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 | |
) : LinearLayout(context, attrs, defStyleAttr) { | |
/* ==== Component Class Attrs ==== */ | |
private val binding = ComponentRoundedButtonBinding.inflate(LayoutInflater.from(context), this) | |
//Button text | |
private var _text: String? = null | |
//Button color background | |
//-1 if user no pass any color | |
private var _backgroundColor: Int = -1 | |
//Icon gravity defines if icon and divider appears on start or end of button | |
private var _iconGravity: Int = RBGravity.START.value | |
//Defines divider visibility | |
private var _showDivider: Boolean = true | |
//Defines icon visibility | |
private var _showIcon: Boolean = true | |
//Icon drawable res reference | |
private var _iconSrc: Int = -1 | |
//Defines icon size | |
//Use "[SIZE_INT]dp" format and string extension "[SIZE_INT]dp".dp() | |
//to parse string to rounded int screen density size | |
//ex: "30dp".dp(context) returns rounded integer value of 30dp | |
private var _iconSizeStr: String? = "30dp" | |
init { | |
prepareViewAttrs(attrs) | |
removeInnerViews() | |
bindViewProperties() | |
} | |
/* ==== Methods ==== */ | |
//Store attrs on class fields | |
private fun prepareViewAttrs(attrs: AttributeSet?) { | |
attrs?.let { attributeSet -> | |
val attributes = context.obtainStyledAttributes(attributeSet, R.styleable.RoundedButton) | |
//Manage attrs | |
_text = attributes.getString(R.styleable.RoundedButton_text) | |
_backgroundColor = attributes.getColor(R.styleable.RoundedButton_background_tint, -1) | |
_iconGravity = attributes.getInt(R.styleable.RoundedButton_icon_gravity, 0) | |
_showDivider = attributes.getBoolean(R.styleable.RoundedButton_show_divider, true) | |
_showIcon = attributes.getBoolean(R.styleable.RoundedButton_show_icon, true) | |
_iconSrc = attributes.getResourceId(R.styleable.RoundedButton_icon_src, -1) | |
_iconSizeStr = attributes.getString(R.styleable.RoundedButton_icon_size) | |
attributes.recycle() | |
} | |
} | |
//Remove views from XML to add again after define icon gravity | |
private fun removeInnerViews() { | |
this.removeViews(0, 2) | |
} | |
//Bind the views and their properties | |
private fun bindViewProperties() { | |
/* Root LinearLayout */ | |
this.orientation = HORIZONTAL | |
this.gravity = Gravity.CENTER | |
this.setPadding(16.dp(context), 8.dp(context), 16.dp(context), 8.dp(context)) | |
//Update background drawable color | |
if (_backgroundColor != -1) { | |
//Get base drawable | |
val unwrappedDrawable = AppCompatResources.getDrawable(context, R.drawable.background_component_rounded_button) | |
unwrappedDrawable?.let { | |
//Wrap background drawable to change tint color | |
val wrappedDrawable = DrawableCompat.wrap(unwrappedDrawable) | |
//TInt background drawable | |
DrawableCompat.setTint(wrappedDrawable, _backgroundColor) | |
//Get the color to tint ripple | |
val colorPaleRedState = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.pale_red)) | |
//Set ripple to background drawable | |
val rippleDrawable = RippleDrawable(colorPaleRedState, wrappedDrawable, null) | |
binding.root.background = rippleDrawable | |
} | |
} | |
/* Button text */ | |
binding.roundedButtonText.text = _text | |
/* Update icon */ | |
if (_iconSrc != -1) | |
//Change icon if the user was selected someone | |
binding.roundedButtonImageIcon.setImageResource(_iconSrc) | |
//Change icon size | |
binding.roundedButtonImageIcon.layoutParams.apply { | |
_iconSizeStr?.let { | |
width = _iconSizeStr!!.dp(context) | |
height = _iconSizeStr!!.dp(context) | |
} | |
} | |
//Add icon and divider on their relative positions based on gravity and | |
//visibility properties | |
when (_iconGravity) { | |
RBGravity.START.value -> { | |
if (_showIcon) | |
this.addView(binding.roundedButtonImageIcon, 0) | |
if (_showDivider) | |
this.addView(binding.roundedButtonDivider, 1) | |
} | |
RBGravity.END.value -> { | |
if (_showDivider) | |
this.addView(binding.roundedButtonDivider) | |
if (_showIcon) | |
this.addView(binding.roundedButtonImageIcon) | |
} | |
} | |
/* View Divider */ | |
val dividerLayoutParams = LayoutParams(1.dp(context), MATCH_PARENT) | |
//Update margin based on gravity | |
when (_iconGravity) { | |
RBGravity.START.value -> { | |
dividerLayoutParams.marginStart = 16.dp(context) | |
} | |
RBGravity.END.value -> { | |
dividerLayoutParams.marginEnd = 16.dp(context) | |
} | |
} | |
//Set vertical margins | |
dividerLayoutParams.updateMargins(top = 8.dp(context), bottom = 8.dp(context)) | |
binding.roundedButtonDivider.layoutParams = dividerLayoutParams | |
} | |
} | |
enum class RBGravity(val value: Int) { | |
START(0), | |
END(1), | |
} | |
//Kotlin extensions to convert pixels to dp format | |
fun Int.dp(context: Context): Int { | |
val scale = context.resources.displayMetrics.density | |
return (this * scale + 0.5f).toInt() | |
} | |
//Kotlin extensions to convert String to dp format | |
fun String.dp(context: Context): Int = this.replace("dp", "").toInt().dp(context) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment