Skip to content

Instantly share code, notes, and snippets.

@webserveis
Created April 15, 2020 11:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save webserveis/4352723d3d0b3a1adaf7a626a7c329f6 to your computer and use it in GitHub Desktop.
Save webserveis/4352723d3d0b3a1adaf7a626a7c329f6 to your computer and use it in GitHub Desktop.
Component PassCodeDotsIndicator

Crear componente PassCodeDotsIndicator

Para la creación del componente que nos indica cuantas entradas llevamos y las que nos queda para completar el código pin, vaya lo de los circulitos, he extraido la parte del componente de amirarcane/lock-screen la he modificado como tambien transcrita en Kotlin

https://dev4phones.files.wordpress.com/2020/04/passcode_dots_indicator_android_kotlin.png

Usar el componente

Su uso es muy fácil, para, en la declaración del componente podemos especificar el estilo del identificador, que puede ser:

  • FIXED: Se mostrarán los circulos vacios, otorgando la visibilidad del tamaño del pin a entrar, si es de 4, se verá 4 circulos
  • FILL: Se mostrará solo un indentificador por cada entrada
  • FILL_ANIMATE: Al aparecer en pantalla lo hará con una transición, perfecto para la ventana de creación del código pin Se puede especificar las preferencias directamente en la declaración del componente
app:indicatorType="FIXED"
app:pinLength="4"

O bien en Kotlin de forma dinámica

inidicatorDots.setPingLenght(4) //Para asignar el tamño del pincode y restablecer el componente
indicatorDots.updateDot(1) //Para marcar el primer circulo
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="IndicatorLocks">
<attr name="pinLength" format="integer" />
<attr name="dotEmptyBackground" format="reference" />
<attr name="dotFilledBackground" format="reference" />
<attr name="dotDiameter" format="dimension" />
<attr name="dotSpacing" format="dimension" />
<attr name="indicatorType" format="enum">
<enum name="FIXED" value="0" />
<enum name="FILL" value="1" />
<enum name="FILL_ANIMATION" value="2" />
</attr>
</declare-styleable>
</resources>
<resources>
<dimen name="dot_diameter">12dp</dimen>
<dimen name="dot_spacing">12.2dp</dimen>
<dimen name="dot_margin_top">25dp</dimen>
<dimen name="dot_border">1dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@android:color/transparent"/>
<stroke
android:width="@dimen/dot_border"
android:color="?attr/colorControlNormal"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorAccent"/>
</shape>
class PassCodeDotsIndicator @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
annotation class IndicatorType {
@IntDef(FIXED, FILL, FILL_WITH_ANIMATION)
@Retention(AnnotationRetention.SOURCE)
annotation class override
companion object {
const val FIXED = 0
const val FILL = 1
const val FILL_WITH_ANIMATION = 2
}
}
private val DEFAULT_PIN_LENGTH = 4
private val DEFAULT_ANIMATION_DURATION = 350L
private var mDotDiameter = 0
private var mDotSpacing = 0
@DrawableRes
private var mFillDrawable = 0
@DrawableRes
private var mEmptyDrawable = 0
private var mPinLength = 0
@IndicatorType
private var mIndicatorType = IndicatorType.FIXED
private var mPreviousLength = 0
init {
val typedArray: TypedArray =
context.obtainStyledAttributes(attrs, R.styleable.IndicatorLocks)
try {
mDotDiameter = typedArray.getDimension(
R.styleable.IndicatorLocks_dotDiameter,
getDimensionInPx(getContext(), R.dimen.dot_diameter)
).toInt()
mDotSpacing = typedArray.getDimension(
R.styleable.IndicatorLocks_dotSpacing,
getDimensionInPx(getContext(), R.dimen.dot_spacing)
).toInt()
mFillDrawable = typedArray.getResourceId(
R.styleable.IndicatorLocks_dotFilledBackground,
R.drawable.dot_filled
)
mEmptyDrawable = typedArray.getResourceId(
R.styleable.IndicatorLocks_dotEmptyBackground,
R.drawable.dot_empty
)
mPinLength = typedArray.getInt(R.styleable.IndicatorLocks_pinLength, DEFAULT_PIN_LENGTH)
mIndicatorType = typedArray.getInt(
R.styleable.IndicatorLocks_indicatorType,
IndicatorType.FIXED
)
} finally {
typedArray.recycle()
}
initView(context)
}
private fun initView(context: Context) {
when (mIndicatorType) {
IndicatorType.FIXED -> {
for (i in 0 until mPinLength) {
val dot = View(context)
emptyDot(dot)
val params = LayoutParams(mDotDiameter, mDotDiameter)
params.setMargins(mDotSpacing, 0, mDotSpacing, 0)
dot.layoutParams = params
addView(dot)
}
}
IndicatorType.FILL_WITH_ANIMATION -> {
val layoutTransition = LayoutTransition()
layoutTransition.setDuration(DEFAULT_ANIMATION_DURATION.toLong())
layoutTransition.setStartDelay(LayoutTransition.APPEARING, 0)
setLayoutTransition(layoutTransition)
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// If the indicator type is not fixed
if (mIndicatorType != IndicatorType.FIXED) {
val params = this.layoutParams
params.height = mDotDiameter
requestLayout()
}
}
fun updateDot(length: Int) {
when (mIndicatorType) {
IndicatorType.FIXED -> {
if (length < 0 || length > childCount) return
if (length > 0) {
if (length > mPreviousLength) {
val dot: View? = getChildAt(length - 1)
dot?.let { fillDot(it) }
} else {
val dot: View? = getChildAt(length)
dot?.let { emptyDot(it) }
}
mPreviousLength = length
} else {
// When {@code mPinLength} is 0, we need to reset all the views back to empty
for (i in 0 until childCount) {
val v = getChildAt(i)
emptyDot(v)
}
mPreviousLength = 0
}
}
IndicatorType.FILL,
IndicatorType.FILL_WITH_ANIMATION -> {
if (length > 0) {
if (length > mPreviousLength) {
val dot = View(context)
fillDot(dot)
val params = LayoutParams(mDotDiameter, mDotDiameter)
params.setMargins(mDotSpacing, 0, mDotSpacing, 0)
dot.layoutParams = params
addView(dot, length - 1)
} else {
removeViewAt(length)
}
mPreviousLength = length
} else {
removeAllViews()
mPreviousLength = 0
}
}
}
}
private fun emptyDot(dot: View) {
dot.setBackgroundResource(mEmptyDrawable)
}
private fun fillDot(dot: View) {
dot.setBackgroundResource(mFillDrawable)
}
fun getPinLength(): Int {
return mPinLength
}
fun setPinLength(value: Int) {
mPinLength = value
removeAllViews()
mPreviousLength = 0
initView(context)
}
@IndicatorType
fun getIndicatorType(): Int {
return mIndicatorType
}
fun setIndicatorType(@IndicatorType type: Int) {
mIndicatorType = type
removeAllViews()
initView(context)
}
private fun getDimensionInPx(context: Context, @DimenRes id: Int): Float {
return context.resources.getDimension(id)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment