From a5f747cef4e32f0c58ed04e57784828d8661def7 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 16:55:50 +0200 Subject: [PATCH 01/21] Updated libs and android target --- build.gradle | 4 ++-- example/build.gradle | 9 ++++----- pinview/build.gradle | 9 ++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index c93b711..0b30bc4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.70' + ext.kotlin_version = '1.5.31' repositories { jcenter() google() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.2' + classpath 'com.android.tools.build:gradle:7.0.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/example/build.gradle b/example/build.gradle index 2d2f895..a270266 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -1,13 +1,12 @@ apply plugin: 'com.android.application' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' android { - compileSdkVersion 28 + compileSdkVersion 31 defaultConfig { applicationId "com.goodiebag.pinview.example" minSdkVersion 15 - targetSdkVersion 28 + targetSdkVersion 31 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -25,8 +24,8 @@ dependencies { androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - implementation 'androidx.appcompat:appcompat:1.0.0' - testImplementation 'junit:junit:4.12' + implementation 'androidx.appcompat:appcompat:1.3.1' + testImplementation 'junit:junit:4.13.2' implementation project(':pinview') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/pinview/build.gradle b/pinview/build.gradle index 5c0fe94..663255c 100644 --- a/pinview/build.gradle +++ b/pinview/build.gradle @@ -1,13 +1,12 @@ apply plugin: 'com.android.library' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' android { - compileSdkVersion 29 + compileSdkVersion 31 defaultConfig { minSdkVersion 15 - targetSdkVersion 29 + targetSdkVersion 31 versionCode 3 versionName "1.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -26,8 +25,8 @@ dependencies { androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - implementation 'androidx.appcompat:appcompat:1.1.0' - testImplementation 'junit:junit:4.12' + implementation 'androidx.appcompat:appcompat:1.3.1' + testImplementation 'junit:junit:4.13.2' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } repositories { From 33389b19aef906415dcc1fb005ea933515531d24 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 19:05:20 +0200 Subject: [PATCH 02/21] editTextList as non-nullable list --- .../java/com/goodiebag/pinview/Pinview.kt | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index 61b3ee0..0bd477c 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -61,7 +61,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = * Attributes */ private var mPinLength = 4 - private val editTextList: MutableList? = ArrayList() + private val editTextList: MutableList = ArrayList() private var mPinWidth = 50 private var mTextSize = 12 private var mPinHeight = 50 @@ -116,7 +116,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = createEditTexts() super.setOnClickListener { var focused = false - for (editText in editTextList!!) { + for (editText in editTextList) { if (editText.length() == 0) { editText.requestFocus() openKeyboard() @@ -132,8 +132,8 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } } // Bring up the keyboard - val firstEditText: View? = editTextList?.first() - firstEditText?.postDelayed({ openKeyboard() }, 200) + val firstEditText: View = editTextList.first() + firstEditText.postDelayed({ openKeyboard() }, 200) updateEnabledState() } @@ -142,7 +142,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = */ private fun createEditTexts() { removeAllViews() - editTextList!!.clear() + editTextList.clear() var editText: EditText for (i in 0 until mPinLength) { @@ -241,7 +241,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = var value: String get() { val sb = StringBuilder() - for (et in editTextList!!) { + for (et in editTextList) { sb.append(et.text.toString()) } return sb.toString() @@ -283,10 +283,10 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = * * @return the current focused pin view. It can be used to open softkeyboard manually. */ - fun requestPinEntryFocus(): View? { + fun requestPinEntryFocus(): View { val currentTag = max(0, indexOfCurrentFocus) - val currentEditText = editTextList?.get(currentTag) - currentEditText?.requestFocus() + val currentEditText = editTextList[currentTag] + currentEditText.requestFocus() openKeyboard() return currentEditText } @@ -312,7 +312,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = mDelPressed = false return } - for (editText in editTextList!!) { + for (editText in editTextList) { if (editText.length() == 0) { if (editText !== view) { editText.requestFocus() @@ -339,13 +339,13 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = */ private fun setTransformation() { if (mPassword) { - for (editText in editTextList!!) { + for (editText in editTextList) { editText.removeTextChangedListener(this) editText.transformationMethod = PinTransformationMethod() editText.addTextChangedListener(this) } } else { - for (editText in editTextList!!) { + for (editText in editTextList) { editText.removeTextChangedListener(this) editText.transformationMethod = null editText.addTextChangedListener(this) @@ -372,9 +372,9 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = var delay: Long = 1 if (mPassword) delay = 25 postDelayed({ - val nextEditText = editTextList?.get(currentTag + 1) - nextEditText?.isEnabled = true - nextEditText?.requestFocus() + val nextEditText = editTextList[currentTag + 1] + nextEditText.isEnabled = true + nextEditText.requestFocus() }, delay) } @@ -389,12 +389,12 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = this.mDelPressed = true //For the last cell of the non password text fields. Clear the text without changing the focus. - if (!this.editTextList?.get(currentTag)?.text.isNullOrEmpty()) { - this.editTextList?.get(currentTag)?.setText("") + if (!this.editTextList[currentTag].text.isNullOrEmpty()) { + this.editTextList[currentTag].setText("") } } - this.editTextList?.forEach { item -> + this.editTextList.forEach { item -> if (item.text.isNotEmpty()) { val index = this.editTextList.indexOf(item) + 1 if (!this.fromSetValue && index == mPinLength) { @@ -412,7 +412,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = private fun updateEnabledState() { val currentTag = max(0, indexOfCurrentFocus) - for (index in editTextList!!.indices) { + for (index in editTextList.indices) { val editText = editTextList[index] editText.isEnabled = index <= currentTag } @@ -432,26 +432,26 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = if (keyEvent.action == KeyEvent.ACTION_UP && i == KeyEvent.KEYCODE_DEL) { // Perform action on Del press val currentTag = indexOfCurrentFocus - val currentEditText = editTextList?.get(currentTag)?.text + val currentEditText = editTextList[currentTag].text //Last tile of the number pad. Clear the edit text without changing the focus. if (inputType == InputType.NUMBER && currentTag == mPinLength - 1 && finalNumberPin || mPassword && currentTag == mPinLength - 1 && finalNumberPin) { if (!currentEditText.isNullOrEmpty()) { - this.editTextList?.get(currentTag)?.setText("") + this.editTextList[currentTag].setText("") } finalNumberPin = false } else if (currentTag > 0) { mDelPressed = true if (currentEditText.isNullOrEmpty()) { //Takes it back one tile - this.editTextList?.get(currentTag - 1)?.requestFocus() + this.editTextList[currentTag - 1].requestFocus() } - this.editTextList?.get(currentTag)?.setText("") + this.editTextList[currentTag].setText("") } else { //For the first cell if (!currentEditText.isNullOrEmpty()) { - editTextList?.get(currentTag)?.setText("") + editTextList[currentTag].setText("") } } return true @@ -463,7 +463,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = * Getters and Setters */ private val indexOfCurrentFocus: Int - get() = editTextList!!.indexOf(currentFocus) + get() = editTextList.indexOf(currentFocus) var splitWidth: Int get() = mSplitWidth @@ -471,7 +471,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = mSplitWidth = splitWidth val margin = splitWidth / 2 params?.setMargins(margin, margin, margin, margin) - this.editTextList?.forEach { + this.editTextList.forEach { it.layoutParams = params } } @@ -481,7 +481,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = set(pinHeight) { mPinHeight = pinHeight params?.height = pinHeight - this.editTextList?.forEach { + this.editTextList.forEach { it.layoutParams = params } } @@ -491,7 +491,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = set(pinWidth) { mPinWidth = pinWidth params?.width = pinWidth - this.editTextList?.forEach { + this.editTextList.forEach { it.layoutParams = params } } @@ -514,14 +514,14 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = get() = mHint set(mHint) { this.mHint = mHint - this.editTextList?.forEach { + this.editTextList.forEach { it.hint = mHint } } fun setPinBackgroundRes(@DrawableRes res: Int) { pinBackground = res - this.editTextList?.forEach { + this.editTextList.forEach { it.setBackgroundResource(res) } } @@ -537,7 +537,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = fun setInputType(inputType: InputType) { this.inputType = inputType val keyInputType = keyboardInputType - editTextList?.forEach { + editTextList.forEach { it.inputType = keyInputType } } @@ -548,28 +548,28 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = fun showCursor(status: Boolean) { mCursorVisible = status - this.editTextList?.forEach { it.isCursorVisible = status } + this.editTextList.forEach { it.isCursorVisible = status } } fun setTextSize(textSize: Int) { mTextSize = textSize - this.editTextList?.forEach { it.textSize = mTextSize.toFloat() } + this.editTextList.forEach { it.textSize = mTextSize.toFloat() } } fun setCursorColor(@ColorInt color: Int) { - this.editTextList?.forEach { + this.editTextList.forEach { setCursorColor(it, color) } } fun setTextColor(@ColorInt color: Int) { - this.editTextList?.forEach { + this.editTextList.forEach { it.setTextColor(color) } } fun setCursorShape(@DrawableRes shape: Int) { - editTextList?.forEach { + editTextList.forEach { try { val field = TextView::class.java.getDeclaredField("mCursorDrawableRes") field.isAccessible = true From 1a445c9edd7734c620a23d6232a29a8b65b9fd4b Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:20:17 +0200 Subject: [PATCH 03/21] Fix null-bug, when pinLength=0 (introduced in kotlin-migration) --- pinview/src/main/java/com/goodiebag/pinview/Pinview.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index 0bd477c..4d3eb98 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -132,8 +132,8 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } } // Bring up the keyboard - val firstEditText: View = editTextList.first() - firstEditText.postDelayed({ openKeyboard() }, 200) + val firstEditText: View? = editTextList.firstOrNull() // list is empty, if pinLength==0 + firstEditText?.postDelayed({ openKeyboard() }, 200) updateEnabledState() } From 5c9bb3128e565ff4e92dc1b18ec6612dd3328f65 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:02:39 +0200 Subject: [PATCH 04/21] Avoid AndroidManifest.xml warning/error due to missing exported --- example/src/main/AndroidManifest.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml index c361d8e..bfdc1ea 100644 --- a/example/src/main/AndroidManifest.xml +++ b/example/src/main/AndroidManifest.xml @@ -8,10 +8,11 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + - From d960dc9ec69c6895578a33cca516fbf4cfa4b5dd Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:03:07 +0200 Subject: [PATCH 05/21] AndroidManifest.xml cleanup --- pinview/src/main/AndroidManifest.xml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pinview/src/main/AndroidManifest.xml b/pinview/src/main/AndroidManifest.xml index aa785b8..ba57c8f 100644 --- a/pinview/src/main/AndroidManifest.xml +++ b/pinview/src/main/AndroidManifest.xml @@ -1,10 +1,2 @@ - - - - - - + package="com.goodiebag.pinview"/> \ No newline at end of file From a29d50f892b4ab23744fa1ef82095bb306b13934 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:09:43 +0200 Subject: [PATCH 06/21] Added ability to set Typeface (Font) --- .../goodiebag/pinview/example/MainActivity.kt | 9 ++++++ .../src/main/res/font/poppins_semibold.ttf | Bin 0 -> 141612 bytes example/src/main/res/layout/activity_main.xml | 3 +- .../java/com/goodiebag/pinview/Pinview.kt | 26 ++++++++++++++---- 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 example/src/main/res/font/poppins_semibold.ttf diff --git a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt index 49bd504..4707f8c 100644 --- a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt +++ b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt @@ -1,5 +1,6 @@ package com.goodiebag.pinview.example +import android.annotation.SuppressLint import android.graphics.Color import android.os.Bundle import android.widget.Toast @@ -18,6 +19,7 @@ class MainActivity : AppCompatActivity() { Toast.makeText(this@MainActivity, pinview!!.value, Toast.LENGTH_SHORT).show() } }) + setFont(pinview1) // pinView Customize val pinview5 = findViewById(R.id.pinview5) @@ -29,4 +31,11 @@ class MainActivity : AppCompatActivity() { showCursor(true) } } + + @SuppressLint("NewApi") + private fun setFont(pinview1: Pinview) { + val typeface = resources.getFont(R.font.poppins_semibold) + pinview1.setTypeface(typeface) + } + } \ No newline at end of file diff --git a/example/src/main/res/font/poppins_semibold.ttf b/example/src/main/res/font/poppins_semibold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3b8622f67bffda70fc2d7f6ff2f2ad6f3078fd08 GIT binary patch literal 141612 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
pJZQSzuNwmL%hRN4*MNWJACAD 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 literal 0 HcmV?d00001 diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 254eaf0..d3c0c1d 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -83,7 +83,8 @@ app:pinBackground="@drawable/example_drawable" app:pinHeight="40dp" app:pinLength="4" - app:pinWidth="40dp"/> + app:pinWidth="40dp" + app:textSize="9sp"/> (1) - var params: LayoutParams? = null + lateinit var params: LayoutParams /** * A method to take care of all the initialisations. @@ -127,9 +129,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = if (!focused && editTextList.size > 0) { // Focus the last view editTextList[editTextList.size - 1].requestFocus() } - if (mClickListener != null) { - mClickListener!!.onClick(this@Pinview) - } + mClickListener?.onClick(this@Pinview) } // Bring up the keyboard val firstEditText: View? = editTextList.firstOrNull() // list is empty, if pinLength==0 @@ -148,6 +148,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = for (i in 0 until mPinLength) { editText = EditText(context) editText.textSize = mTextSize.toFloat() + mTypeFace.let { editText.typeface = it } editTextList.add(i, editText) this.addView(editText) generateOneEditText(editText, "" + i) @@ -553,9 +554,22 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = fun setTextSize(textSize: Int) { mTextSize = textSize - this.editTextList.forEach { it.textSize = mTextSize.toFloat() } + updateEditTexts() + } + + fun setTypeface(typeFace: Typeface?) { + mTypeFace = typeFace + updateEditTexts() } + private fun updateEditTexts() { + for (edt in editTextList) { + edt.textSize = mTextSize.toFloat() + edt.layoutParams = params + mTypeFace?.let { edt.typeface = it } + } + } + fun setCursorColor(@ColorInt color: Int) { this.editTextList.forEach { setCursorColor(it, color) From 572c5a066713e226d66dbde2c2bc58d3b68c754c Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 22:45:22 +0200 Subject: [PATCH 07/21] Added kotlin-style shorthand for PinViewEventListener --- pinview/src/main/java/com/goodiebag/pinview/Pinview.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index 549e24a..e28457e 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -91,7 +91,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = * Interface for onDataEntered event. */ interface PinViewEventListener { - fun onDataEntered(pinview: Pinview?, fromUser: Boolean) + fun onDataEntered(pinview: Pinview, fromUser: Boolean) } var mClickListener: OnClickListener? = null @@ -547,6 +547,14 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = mListener = listener } + fun setPinViewEventListener(listener: (Pinview, Boolean) -> Unit) { + mListener = object: PinViewEventListener { + override fun onDataEntered(pinview: Pinview, fromUser: Boolean) { + listener(pinview, fromUser) + } + } + } + fun showCursor(status: Boolean) { mCursorVisible = status this.editTextList.forEach { it.isCursorVisible = status } From baadae192d41e92bdf898e564863f3826d0828f4 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:26:36 +0200 Subject: [PATCH 08/21] Public openKeyboard and updated java-doc with respect to XML disabled openkeyboard and requestPinEntryFocus --- .../java/com/goodiebag/pinview/Pinview.kt | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index e28457e..a488b6a 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -121,7 +121,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = for (editText in editTextList) { if (editText.length() == 0) { editText.requestFocus() - openKeyboard() + openKeyboardIfForced() focused = true break } @@ -280,25 +280,34 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } /** - * Requsets focus on current pin view and opens keyboard if forceKeyboard is enabled. + * Requests focus on current pin view and opens keyboard if forceKeyboard is enabled. + * If open keyboard is disabled in XML, use openKeyboard() * - * @return the current focused pin view. It can be used to open softkeyboard manually. + * @return the current focused pin view. It can be used to open soft-keyboard manually. */ fun requestPinEntryFocus(): View { val currentTag = max(0, indexOfCurrentFocus) val currentEditText = editTextList[currentTag] currentEditText.requestFocus() - openKeyboard() + openKeyboardIfForced() return currentEditText } - private fun openKeyboard() { + private fun openKeyboardIfForced() { if (mForceKeyboard) { - val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager - inputMethodManager?.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY) + openKeyboard() } } + /** + * Request the keyboard to open on the currently focused view + */ + @Suppress("MemberVisibilityCanBePrivate") + fun openKeyboard() { + val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY) + } + /** * Clears the values in the Pinview */ From 66c028f6ae8915bd5c815b0c42fda5639e1971e9 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 21:12:42 +0200 Subject: [PATCH 09/21] Allow textSize to be specified in dp --- example/src/main/res/layout/activity_main.xml | 5 +++-- pinview/src/main/java/com/goodiebag/pinview/Pinview.kt | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index d3c0c1d..628c8d0 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -89,7 +89,7 @@ + android:text="Custom Pin View (with dp textSize)"/> + app:pinWidth="40dp" + app:textSize="18dp"/> diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index a488b6a..06972ea 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -174,7 +174,9 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = mPinHeight = array.getDimension(R.styleable.Pinview_pinHeight, mPinHeight.toFloat()).toInt() mPinWidth = array.getDimension(R.styleable.Pinview_pinWidth, mPinWidth.toFloat()).toInt() mSplitWidth = array.getDimension(R.styleable.Pinview_splitWidth, mSplitWidth.toFloat()).toInt() - mTextSize = array.getDimension(R.styleable.Pinview_textSize, mTextSize.toFloat()).toInt() + // We expect mTextSize to be sp, but we allow specifying via xml in any dimension resource as standard. Hence the scaling here + val scaledDensity = resources.displayMetrics.scaledDensity + mTextSize = (array.getDimensionPixelSize(R.styleable.Pinview_textSize, (mTextSize * scaledDensity).toInt()) / scaledDensity).toInt() mCursorVisible = array.getBoolean(R.styleable.Pinview_cursorVisible, mCursorVisible) mPassword = array.getBoolean(R.styleable.Pinview_password, mPassword) mForceKeyboard = array.getBoolean(R.styleable.Pinview_forceKeyboard, mForceKeyboard) From 9d3cd02bbf3610a81f63adc5b9345565dfa6dad6 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:49:26 +0200 Subject: [PATCH 10/21] Use TextView instead of EditText, because EditText has bottom offset which cannot always be fixed by padding. Also editTexts capture clicks, which prevents focus by clicking inactive pin-views. Added setTextPadding for setting offset of text for adjustments for fonts. --- .../goodiebag/pinview/example/MainActivity.kt | 2 + example/src/main/res/layout/activity_main.xml | 4 +- .../java/com/goodiebag/pinview/Pinview.kt | 120 ++++++++++-------- 3 files changed, 74 insertions(+), 52 deletions(-) diff --git a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt index 4707f8c..0fe4ab3 100644 --- a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt +++ b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt @@ -20,6 +20,8 @@ class MainActivity : AppCompatActivity() { } }) setFont(pinview1) + val fontScaledDensity = resources.displayMetrics.scaledDensity + pinview1.setTextPadding(0, (4 * fontScaledDensity).toInt(), 0, 0) // pinView Customize val pinview5 = findViewById(R.id.pinview5) diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 628c8d0..3997c4b 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -1,6 +1,7 @@ + app:pinWidth="40dp" + tools:hint="0"/> = ArrayList() + private val pinTextViewList: MutableList = ArrayList() private var mPinWidth = 50 private var mTextSize = 12 private var mPinHeight = 50 @@ -118,7 +117,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = createEditTexts() super.setOnClickListener { var focused = false - for (editText in editTextList) { + for (editText in pinTextViewList) { if (editText.length() == 0) { editText.requestFocus() openKeyboardIfForced() @@ -126,13 +125,13 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = break } } - if (!focused && editTextList.size > 0) { // Focus the last view - editTextList[editTextList.size - 1].requestFocus() + if (!focused && pinTextViewList.size > 0) { // Focus the last view + pinTextViewList[pinTextViewList.size - 1].requestFocus() } mClickListener?.onClick(this@Pinview) } // Bring up the keyboard - val firstEditText: View? = editTextList.firstOrNull() // list is empty, if pinLength==0 + val firstEditText: View? = pinTextViewList.firstOrNull() // list is empty, if pinLength==0 firstEditText?.postDelayed({ openKeyboard() }, 200) updateEnabledState() } @@ -142,14 +141,14 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = */ private fun createEditTexts() { removeAllViews() - editTextList.clear() - var editText: EditText + pinTextViewList.clear() + var editText: TextView for (i in 0 until mPinLength) { - editText = EditText(context) + editText = TextView(context) editText.textSize = mTextSize.toFloat() mTypeFace.let { editText.typeface = it } - editTextList.add(i, editText) + pinTextViewList.add(i, editText) this.addView(editText) generateOneEditText(editText, "" + i) } @@ -194,7 +193,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = * @param tag */ @SuppressLint("ClickableViewAccessibility") - private fun generateOneEditText(styleEditText: EditText, tag: String) { + private fun generateOneEditText(styleEditText: TextView, tag: String) { params!!.setMargins(mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2) filters[0] = InputFilter.LengthFilter(1) @@ -244,7 +243,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = var value: String get() { val sb = StringBuilder() - for (et in editTextList) { + for (et in pinTextViewList) { sb.append(et.text.toString()) } return sb.toString() @@ -253,23 +252,23 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = val regex = Regex("[0-9]*") // Allow empty string to clear the fields fromSetValue = true - if (inputType == InputType.NUMBER && !value.matches(regex) || editTextList.isNullOrEmpty()) { + if (inputType == InputType.NUMBER && !value.matches(regex) || pinTextViewList.isNullOrEmpty()) { return } var lastTagHavingValue = -1 - for (i in editTextList.indices) { + for (i in pinTextViewList.indices) { if (value.length > i) { lastTagHavingValue = i - editTextList[i].setText(value[i].toString()) + pinTextViewList[i].text = value[i].toString() } else { - editTextList[i].setText("") + pinTextViewList[i].text = "" } } if (mPinLength > 0) { - currentFocus = editTextList[mPinLength - 1] + currentFocus = pinTextViewList[mPinLength - 1] if (lastTagHavingValue == mPinLength - 1) { - currentFocus = editTextList[mPinLength - 1] + currentFocus = pinTextViewList[mPinLength - 1] if (inputType == InputType.NUMBER || mPassword) { this.finalNumberPin = true } @@ -289,7 +288,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = */ fun requestPinEntryFocus(): View { val currentTag = max(0, indexOfCurrentFocus) - val currentEditText = editTextList[currentTag] + val currentEditText = pinTextViewList[currentTag] currentEditText.requestFocus() openKeyboardIfForced() return currentEditText @@ -324,7 +323,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = mDelPressed = false return } - for (editText in editTextList) { + for (editText in pinTextViewList) { if (editText.length() == 0) { if (editText !== view) { editText.requestFocus() @@ -334,8 +333,8 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = return } } - if (editTextList[editTextList.size - 1] !== view) { - editTextList[editTextList.size - 1].requestFocus() + if (pinTextViewList[pinTextViewList.size - 1] !== view) { + pinTextViewList[pinTextViewList.size - 1].requestFocus() } else { currentFocus = view } @@ -351,13 +350,13 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = */ private fun setTransformation() { if (mPassword) { - for (editText in editTextList) { + for (editText in pinTextViewList) { editText.removeTextChangedListener(this) editText.transformationMethod = PinTransformationMethod() editText.addTextChangedListener(this) } } else { - for (editText in editTextList) { + for (editText in pinTextViewList) { editText.removeTextChangedListener(this) editText.transformationMethod = null editText.addTextChangedListener(this) @@ -384,7 +383,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = var delay: Long = 1 if (mPassword) delay = 25 postDelayed({ - val nextEditText = editTextList[currentTag + 1] + val nextEditText = pinTextViewList[currentTag + 1] nextEditText.isEnabled = true nextEditText.requestFocus() }, delay) @@ -401,14 +400,14 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = this.mDelPressed = true //For the last cell of the non password text fields. Clear the text without changing the focus. - if (!this.editTextList[currentTag].text.isNullOrEmpty()) { - this.editTextList[currentTag].setText("") + if (!this.pinTextViewList[currentTag].text.isNullOrEmpty()) { + this.pinTextViewList[currentTag].text = "" } } - this.editTextList.forEach { item -> + this.pinTextViewList.forEach { item -> if (item.text.isNotEmpty()) { - val index = this.editTextList.indexOf(item) + 1 + val index = this.pinTextViewList.indexOf(item) + 1 if (!this.fromSetValue && index == mPinLength) { this.mListener?.onDataEntered(this, true) } @@ -424,8 +423,8 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = private fun updateEnabledState() { val currentTag = max(0, indexOfCurrentFocus) - for (index in editTextList.indices) { - val editText = editTextList[index] + for (index in pinTextViewList.indices) { + val editText = pinTextViewList[index] editText.isEnabled = index <= currentTag } } @@ -444,26 +443,26 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = if (keyEvent.action == KeyEvent.ACTION_UP && i == KeyEvent.KEYCODE_DEL) { // Perform action on Del press val currentTag = indexOfCurrentFocus - val currentEditText = editTextList[currentTag].text + val currentEditText = pinTextViewList[currentTag].text //Last tile of the number pad. Clear the edit text without changing the focus. if (inputType == InputType.NUMBER && currentTag == mPinLength - 1 && finalNumberPin || mPassword && currentTag == mPinLength - 1 && finalNumberPin) { if (!currentEditText.isNullOrEmpty()) { - this.editTextList[currentTag].setText("") + this.pinTextViewList[currentTag].text = "" } finalNumberPin = false } else if (currentTag > 0) { mDelPressed = true if (currentEditText.isNullOrEmpty()) { //Takes it back one tile - this.editTextList[currentTag - 1].requestFocus() + this.pinTextViewList[currentTag - 1].requestFocus() } - this.editTextList[currentTag].setText("") + this.pinTextViewList[currentTag].text = "" } else { //For the first cell if (!currentEditText.isNullOrEmpty()) { - editTextList[currentTag].setText("") + pinTextViewList[currentTag].text = "" } } return true @@ -475,7 +474,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = * Getters and Setters */ private val indexOfCurrentFocus: Int - get() = editTextList.indexOf(currentFocus) + get() = pinTextViewList.indexOf(currentFocus) var splitWidth: Int get() = mSplitWidth @@ -483,7 +482,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = mSplitWidth = splitWidth val margin = splitWidth / 2 params?.setMargins(margin, margin, margin, margin) - this.editTextList.forEach { + this.pinTextViewList.forEach { it.layoutParams = params } } @@ -493,7 +492,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = set(pinHeight) { mPinHeight = pinHeight params?.height = pinHeight - this.editTextList.forEach { + this.pinTextViewList.forEach { it.layoutParams = params } } @@ -503,7 +502,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = set(pinWidth) { mPinWidth = pinWidth params?.width = pinWidth - this.editTextList.forEach { + this.pinTextViewList.forEach { it.layoutParams = params } } @@ -526,14 +525,14 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = get() = mHint set(mHint) { this.mHint = mHint - this.editTextList.forEach { + this.pinTextViewList.forEach { it.hint = mHint } } fun setPinBackgroundRes(@DrawableRes res: Int) { pinBackground = res - this.editTextList.forEach { + this.pinTextViewList.forEach { it.setBackgroundResource(res) } } @@ -549,7 +548,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = fun setInputType(inputType: InputType) { this.inputType = inputType val keyInputType = keyboardInputType - editTextList.forEach { + pinTextViewList.forEach { it.inputType = keyInputType } } @@ -568,7 +567,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = fun showCursor(status: Boolean) { mCursorVisible = status - this.editTextList.forEach { it.isCursorVisible = status } + this.pinTextViewList.forEach { it.isCursorVisible = status } } fun setTextSize(textSize: Int) { @@ -582,27 +581,47 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } private fun updateEditTexts() { - for (edt in editTextList) { + for (edt in pinTextViewList) { edt.textSize = mTextSize.toFloat() edt.layoutParams = params mTypeFace?.let { edt.typeface = it } } } - + + /** + * Permit custom changes directly applied to the TextView pin-views. + * + * If the applied font has a slight offset, it can be adjusted by applying a padding like + *
+     * val fontScaledDensity = app.resources.displayMetrics.scaledDensity
+     * textView.setPadding(0, (20 * fontScaledDensity).toInt(), 0, 0)
+     * 
+ * @return + */ + fun getTextViews(): List { + return Collections.unmodifiableList(pinTextViewList) + } + fun setCursorColor(@ColorInt color: Int) { - this.editTextList.forEach { + this.pinTextViewList.forEach { setCursorColor(it, color) } } fun setTextColor(@ColorInt color: Int) { - this.editTextList.forEach { + this.pinTextViewList.forEach { it.setTextColor(color) } } + fun setTextPadding(left: Int, top: Int, right: Int, bottom: Int) { + pinTextViewList.forEach { + it.setPadding(left, top, right, bottom) + } + } + fun setCursorShape(@DrawableRes shape: Int) { - editTextList.forEach { + pinTextViewList.forEach { try { val field = TextView::class.java.getDeclaredField("mCursorDrawableRes") field.isAccessible = true @@ -610,10 +629,9 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } catch (ignored: Exception) { } } - } - private fun setCursorColor(view: EditText, @ColorInt color: Int) { + private fun setCursorColor(view: TextView, @ColorInt color: Int) { try { // Get the cursor resource id var field = TextView::class.java.getDeclaredField("mCursorDrawableRes") From 86e073b62787a7be8116fe83dfa41f62995d72e9 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 20:50:09 +0200 Subject: [PATCH 11/21] Cleanup params? --- pinview/src/main/java/com/goodiebag/pinview/Pinview.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index db9dc93..e5d13d3 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -481,7 +481,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = set(splitWidth) { mSplitWidth = splitWidth val margin = splitWidth / 2 - params?.setMargins(margin, margin, margin, margin) + params.setMargins(margin, margin, margin, margin) this.pinTextViewList.forEach { it.layoutParams = params } @@ -491,7 +491,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = get() = mPinHeight set(pinHeight) { mPinHeight = pinHeight - params?.height = pinHeight + params.height = pinHeight this.pinTextViewList.forEach { it.layoutParams = params } @@ -501,7 +501,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = get() = mPinWidth set(pinWidth) { mPinWidth = pinWidth - params?.width = pinWidth + params.width = pinWidth this.pinTextViewList.forEach { it.layoutParams = params } From a66a6c7ba95cdf5f6808ae027b4019c6a802eb87 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 21:12:01 +0200 Subject: [PATCH 12/21] PinView textView fix --- pinview/src/main/java/com/goodiebag/pinview/Pinview.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index e5d13d3..1138093 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -21,6 +21,7 @@ package com.goodiebag.pinview import android.annotation.SuppressLint import android.content.Context +import android.graphics.Color import android.graphics.PorterDuff import android.graphics.Typeface import android.text.Editable @@ -147,6 +148,8 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = for (i in 0 until mPinLength) { editText = TextView(context) editText.textSize = mTextSize.toFloat() + editText.isFocusableInTouchMode = true // EditText behaviour + editText.setTextColor(Color.BLACK) // color like EditText instead of greish mTypeFace.let { editText.typeface = it } pinTextViewList.add(i, editText) this.addView(editText) From 073cb56fd0f5b49a9713a66c3b70aad3b7186950 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Fri, 29 Oct 2021 22:26:07 +0200 Subject: [PATCH 13/21] Added autoAdjustWidth parameter: Auto adjust width to available width. Added autoAdjustToSquareFormat parameter: Keep view square --- .../goodiebag/pinview/example/MainActivity.kt | 3 + example/src/main/res/layout/activity_main.xml | 23 ++++++ .../java/com/goodiebag/pinview/Pinview.kt | 82 +++++++++++++++++-- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt index 0fe4ab3..29c2338 100644 --- a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt +++ b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt @@ -32,6 +32,9 @@ class MainActivity : AppCompatActivity() { setTextColor(Color.BLACK) showCursor(true) } + + findViewById(R.id.pinview6).autoAdjustToSquareFormat = true + findViewById(R.id.pinview7).autoAdjustToSquareFormat = true } @SuppressLint("NewApi") diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 3997c4b..18e2711 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -103,4 +103,27 @@ app:pinWidth="40dp" app:textSize="18dp"/> + + + + + +
diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index 1138093..15c919a 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -31,6 +31,7 @@ import android.util.AttributeSet import android.view.Gravity import android.view.KeyEvent import android.view.View +import android.view.View.OnLayoutChangeListener import android.view.inputmethod.InputMethodManager import android.widget.LinearLayout import android.widget.TextView @@ -38,6 +39,7 @@ import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat import java.util.* +import kotlin.math.abs import kotlin.math.max /** @@ -83,6 +85,8 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = private var fromSetValue = false private var mForceKeyboard = true + private var lastAppliedPinHeight = 0 // For auto adjusting to square pin sizes + enum class InputType { TEXT, NUMBER } @@ -118,9 +122,10 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = createEditTexts() super.setOnClickListener { var focused = false - for (editText in pinTextViewList) { - if (editText.length() == 0) { - editText.requestFocus() + for (pin in pinTextViewList) { + pin.maxWidth = mPinWidth + if (pin.length() == 0) { + pin.requestFocus() openKeyboardIfForced() focused = true break @@ -135,6 +140,43 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = val firstEditText: View? = pinTextViewList.firstOrNull() // list is empty, if pinLength==0 firstEditText?.postDelayed({ openKeyboard() }, 200) updateEnabledState() + // View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom + val listener = OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + if (pinTextViewList.isNotEmpty()) { + val lastPin = pinTextViewList.last() + val containerEndCoordinate = this@Pinview.let { it.x + it.width } + val lastPinEndCoordinate = lastPin.x + lastPin.width + if (lastPin.width > mPinWidth) { + // Turn off auto width distribution, because otherwise they always scale to fit available space + useFixedWidthPins() + } else if (autoAdjustWidth && lastPinEndCoordinate > containerEndCoordinate) { + if (autoAdjustWidth) { + // Pin is too wide, we need to reduce it + useWeightedWidthPins() + } + } else if (autoAdjustToSquareFormat && abs(lastPin.width - lastAppliedPinHeight) > 0.1f) { + // allow some difference, in case something moves on layout and reduce risk of infinite layout loop, and because its floats and equal is bad + // Check if something changed they layout or sizing + lastAppliedPinHeight = lastPin.width + params.height = lastAppliedPinHeight + updateEditTexts() + requestLayout() + } + } + } + addOnLayoutChangeListener(listener) + } + + private fun useWeightedWidthPins() { + params.weight = 1f + updateEditTexts() // apply the new params + requestLayout() + } + + private fun useFixedWidthPins() { + params.weight = 0f + updateEditTexts() // apply the new params + requestLayout() } /** @@ -197,7 +239,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = */ @SuppressLint("ClickableViewAccessibility") private fun generateOneEditText(styleEditText: TextView, tag: String) { - params!!.setMargins(mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2) + params.setMargins(mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2, mSplitWidth / 2) filters[0] = InputFilter.LengthFilter(1) @@ -396,7 +438,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = finalNumberPin = true } } else if (charSequence.isEmpty()) { - if(indexOfCurrentFocus < 0){ + if (indexOfCurrentFocus < 0) { return } val currentTag = indexOfCurrentFocus @@ -510,6 +552,27 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } } + /** + * Ensure the pins fit within the Pinview parent. + */ + var autoAdjustWidth: Boolean = true + set(value) { + field = value + if (!value) { + useFixedWidthPins() + } + requestLayout() + } + + /** + * When reducing size of Pins due to lack of width, also reduce height to keep the pin square. + */ + var autoAdjustToSquareFormat: Boolean = false + set(value) { + field = value + requestLayout() + } + var pinLength: Int get() = mPinLength set(pinLength) { @@ -584,10 +647,11 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } private fun updateEditTexts() { - for (edt in pinTextViewList) { - edt.textSize = mTextSize.toFloat() - edt.layoutParams = params - mTypeFace?.let { edt.typeface = it } + for (pin in pinTextViewList) { + pin.textSize = mTextSize.toFloat() + pin.layoutParams = params + pin.requestLayout() + mTypeFace?.let { pin.typeface = it } } } From 13530a9b30262efea9907ba44161cb56d39bc641 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Mon, 1 Nov 2021 12:11:04 +0100 Subject: [PATCH 14/21] Fix example pinViewListener and added clear --- .../java/com/goodiebag/pinview/example/MainActivity.kt | 8 +++----- pinview/src/main/java/com/goodiebag/pinview/Pinview.kt | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt index 4707f8c..e592176 100644 --- a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt +++ b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt @@ -14,11 +14,9 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) val pinview1 = findViewById(R.id.pinview1) - pinview1.setPinViewEventListener(object : PinViewEventListener { - override fun onDataEntered(pinview: Pinview?, fromUser: Boolean) { - Toast.makeText(this@MainActivity, pinview!!.value, Toast.LENGTH_SHORT).show() - } - }) + pinview1.setPinViewEventListener { pinview: Pinview, fromUser: Boolean -> + Toast.makeText(this@MainActivity, pinview.value, Toast.LENGTH_SHORT).show() + } setFont(pinview1) // pinView Customize diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index 06972ea..baaceea 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -566,6 +566,10 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = } } + fun clearPinViewEventListener() { + mListener = null + } + fun showCursor(status: Boolean) { mCursorVisible = status this.editTextList.forEach { it.isCursorVisible = status } From d2e52faf50280010e5c38929e2b8ae3280715177 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Mon, 1 Nov 2021 12:16:02 +0100 Subject: [PATCH 15/21] Removed autoAdjustToSquareFormat and instead auto-adjust pin-height when set to 0dp (which is similar to how ConstraintLayout works) --- .../com/goodiebag/pinview/example/MainActivity.kt | 3 --- example/src/main/res/layout/activity_main.xml | 7 ++++--- .../src/main/java/com/goodiebag/pinview/Pinview.kt | 11 +---------- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt index dc655ac..e6d7eaf 100644 --- a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt +++ b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt @@ -30,9 +30,6 @@ class MainActivity : AppCompatActivity() { setTextColor(Color.BLACK) showCursor(true) } - - findViewById(R.id.pinview6).autoAdjustToSquareFormat = true - findViewById(R.id.pinview7).autoAdjustToSquareFormat = true } @SuppressLint("NewApi") diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 18e2711..28c4a3a 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -106,14 +106,15 @@ + android:text="Auto adjusting width and to fit, and height to square"/> + @@ -122,7 +123,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:inputType="text" - app:pinHeight="40dp" + app:pinHeight="0dp" app:pinLength="8" app:pinWidth="40dp"/> diff --git a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt index 2c8d7b7..66285c3 100644 --- a/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt +++ b/pinview/src/main/java/com/goodiebag/pinview/Pinview.kt @@ -154,7 +154,7 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = // Pin is too wide, we need to reduce it useWeightedWidthPins() } - } else if (autoAdjustToSquareFormat && abs(lastPin.width - lastAppliedPinHeight) > 0.1f) { + } else if (mPinHeight == 0 && abs(lastPin.width - lastAppliedPinHeight) > 0.1f) { // allow some difference, in case something moves on layout and reduce risk of infinite layout loop, and because its floats and equal is bad // Check if something changed they layout or sizing lastAppliedPinHeight = lastPin.width @@ -564,15 +564,6 @@ class Pinview @JvmOverloads constructor(context: Context, attrs: AttributeSet? = requestLayout() } - /** - * When reducing size of Pins due to lack of width, also reduce height to keep the pin square. - */ - var autoAdjustToSquareFormat: Boolean = false - set(value) { - field = value - requestLayout() - } - var pinLength: Int get() = mPinLength set(pinLength) { From 53cbc8d2be5bb7c950c43ce880a6c7aa5f0d8ff9 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Mon, 1 Nov 2021 12:19:36 +0100 Subject: [PATCH 16/21] Added non-square auto-adjusting example, and moved example into ScrollView for smaller height test-phones. --- example/src/main/res/layout/activity_main.xml | 255 ++++++++++-------- 1 file changed, 137 insertions(+), 118 deletions(-) diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 28c4a3a..df723e2 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -1,130 +1,149 @@ - - - + - - - + android:orientation="vertical" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingBottom="@dimen/activity_vertical_margin"> - - - + - - - + - - - + - + - + - - + - + + + + + + + + + + + + + + + + + + - + + \ No newline at end of file From 78aa4eff31dfd686664b87679fae4546bce60f71 Mon Sep 17 00:00:00 2001 From: Alex Rune Berg Date: Tue, 2 Nov 2021 20:49:02 +0100 Subject: [PATCH 17/21] Fixed bug in pinview.setValue() introduced in kotlin migration where lastTagHavingValue usage was incorrectly migrated. Cleaned up that lastTagHavingValue. Also simplified and fixed behaviour on delete. Before some pinviews (numbers, passwords) required 2-3 del to start deleting. Now all pinviews behave identically, no more special for numbers and passwords. The rule is the last unfilled view always has focus, delete always deletes, but does not move focus if last pinview had data (similar to when entering data). --- .../goodiebag/pinview/example/MainActivity.kt | 20 +++++- example/src/main/res/layout/activity_main.xml | 21 ++++--- .../java/com/goodiebag/pinview/Pinview.kt | 62 ++++++------------- 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt index e6d7eaf..20f3ecb 100644 --- a/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt +++ b/example/src/main/java/com/goodiebag/pinview/example/MainActivity.kt @@ -3,17 +3,31 @@ package com.goodiebag.pinview.example import android.annotation.SuppressLint import android.graphics.Color import android.os.Bundle +import android.widget.Button import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.goodiebag.pinview.Pinview -import com.goodiebag.pinview.Pinview.PinViewEventListener class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + val pinViews = listOf( + findViewById(R.id.pinview0), + findViewById(R.id.pinview1), + findViewById(R.id.pinview2), + findViewById(R.id.pinview3), + findViewById(R.id.pinview4), + findViewById(R.id.pinview5), + findViewById(R.id.pinview6), + findViewById(R.id.pinview7), + ) + findViewById