I have two edit text in my fragment where users can enter their age and weight. Based on age and weight I calculate how much water user should drink
When I try to call hide keyboard function on afterTextChanged, the keyboard gets hidden after user typed her first character.
How can I hide the keyboard when user actually finished typing?
P.S: there is a maxLength in my edit text 2 for age and 3 for weight, maybe this could be useful information when you are thinking about your recommendation
My code for edit texts with onChange extension function
//change listener extension for TextInputEditText
fun TextInputEditText.onChange(cb: (String) -> Unit) {
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
cb(s.toString())
hideKeyboard()
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
}
// change listener is called with agehandler function with user type age
// I check if the edit text is empty or not
binding.ageEditText.onChange {
if (binding.ageEditText.text.isNullOrEmpty()) {
Snackbar.make(binding.root, "Please type your age", Snackbar.LENGTH_SHORT).show()
} else dashboardViewModel.ageHandler(it)
}
fun hideKeyboard() {
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view!!.windowToken, 0)
}
This may not be the cleanest way in the world to do things but I use a function to hide the keyboard when users press outside of the edit text. You could also look into hiding upon hitting the enter or submit key on the keyboard here
Otherwise to use these you would just say
editText.hideKeyBoardOnPressAway()
editText.addCharacterMax(2)
fun View.hideKeyBoardOnPressAway(){
this.onFocusChangeListener = keyboardHider
}
private val keyboardHider = View.OnFocusChangeListener { view, b ->
if (!b) { hideKeyboardFrom(view) }
}
private fun hideKeyboardFrom(view: View) {
val imm = view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
fun EditText.addCharacterMax(max: Int){
filters = arrayOf(InputFilter.LengthFilter(max))
}
Related
I am working on EditText where I am displaying pre filled country code in start lets say "+971", what I want is that if user trying to click and edit in EditText, he should not edit or delete "+971" and can only be able to put number after that like "+971 123445579" and if trying to delete number then "+971" should not get delete.
My code is given below, please guide me how can I achieve this. Thanks
private fun setupTextChangeListener() {
edit_text.textWatcherListener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
setDatePickerIconOnDemand()
}
override fun afterTextChanged(s: Editable?) {
}
}
}
// In this method I am putting Start Drawable in EditText:
private fun setDatePickerIconOnDemand() {
edit_text.setDrawableStart(context.drawable(R.drawable.ic_earh_arrow_down_default))
edit_text.setDrawable()
}
You can add following lines of code in on onTextChanged callback
if (edit_text.length() < 5 || !edit_text.text!!.startsWith("+971 ")) {
edit_text.setText("+971 ")
edit_text.setSelection(edit_text.length())
}
What it will do is: It will check onTextChanged 'if your current text in edit text is only your country code, Set the country code in your editText and move cursor at the end.
I would like to add full text from the editText into an array. But while running this code the array
values will be like first word , second word etc. How to get the full sentence and i want to add it
into an array(Already did it using interface)
Note : The code is placed on the recyclerview adapter ,
Where texBox is the EditText and examinationListener is the interface used
Here i shared the code. Please check it.
textBox.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
textFromBox = s.toString()
examinationListener.addAnswer(textFromBox)
}
override fun beforeTextChanged(s: CharSequence, start: Int,
count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
}
})
override fun afterTextChanged(s: Editable) {
textFromBox = textBox.text.toString()
examinationListener.addAnswer(textFromBox)
}
I created an array up to the list size. Each items of RecyclerView have an EditText.
val array = arrayOfNulls<String>(listSize)
We need to know the position of EditText to add to the array. Change interface like this:
interface ExaminationListener {
fun addAnswer(text: String, position: Int)
}
function addAnswer:
override fun addAnswer(text: String, position: Int) {
array[position] = text // we add every changes to the array.
}
This use is more useful. We don't need other methods:
textBox.doAfterTextChanged {
examinationListener.addAnswer(it.toString(), position) // you can use adapterPosition if that is in Viewholder
}
We create a sentence from array elements. You can see your full sentence:
val sentence = array.filterNotNull().joinToString (separator = " ") { it -> it }
Log.d("Sentence" , sentence)
Very Simple just add a TextWatcher to your EditText like:
val answerWatcher = object : TextWatcher {
override fun beforeTextChanged(value: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(value: CharSequence, start: Int, before: Int, count: Int) {
when {
// Here value is your full text from your EditText
value.toString().equals("I am a sentence", ignoreCase = true) -> {
}
else -> {
// Just a test condition
}
}
}
override fun afterTextChanged(s: Editable) {
}
}
// Add this TextWatcher to your EditText
edittext.addTextChangedListener(answerWatcher)
I am developing an open source text masker. You can click here to see source code.
My problem is that, when I wrap my custom edit text with TextInputLayout, onTextChanged is being triggered twice only for first letter. Then it works as expected.
This "twice call" breaks my logic. Do you guys have any idea what might be the problem? Since it is being used by other developers, I don't want to fix it with hacky solution. I need to find out the problem.
I set text manually after removing text watcher, then I add text watcher again.
Here is my main logic;
This method is being called only once;
private fun initTextWatcher() {
textWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
masker?.onTextChanged(s, start, count, before)
}
}
addTextChangedListener(textWatcher)
}
And this is how I set my text manually;
private fun setEditTextWithoutTriggerListener(newText: String) {
removeTextChangedListener(textWatcher)
onTextChangedListener?.invoke(newText) // This is a custom listener.
setText(newText)
setSelection(text?.length ?: 0) // This puts cursor at the end of the text.
addTextChangedListener(textWatcher)
}
To handle hint position like TextInputEditText does, I simply copied it's functions into mine.
override fun getHint(): CharSequence? {
val layoutHint = getTextInputLayout()?.hint
return layoutHint ?: super.getHint()
}
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
val ic = super.onCreateInputConnection(outAttrs)
if (ic != null && outAttrs.hintText == null) {
outAttrs.hintText = getHintFromLayout()
}
return ic
}
private fun getTextInputLayout(): TextInputLayout? {
var parent = this.parent
while (parent is View) {
if (parent is TextInputLayout) {
return parent
}
parent = parent.getParent()
}
return null
}
private fun getHintFromLayout(): CharSequence? {
val layout = getTextInputLayout()
return layout?.hint
}
And my class extends AppCompatEditText like TextInputEditText does.
If you are calling addTextChangedListener() from onCreate() or init() move the call into onResume() or any other function called later, otherwise onTextChanged() is triggered before the resume
I have EditText in BottomSheet. When BottomSheet show and I tap the EditText then the soft keyboard is showing. But how I can hide the soft keyboard when the length of value Edittext is 6 in BottomSheet?
I have some logic like this:
private fun showBottomSheet() {
val binding: BottomSheetSetupEasyPinBinding =
DataBindingUtil.inflate(LayoutInflater.from(activity), R.layout.bottom_sheet_setup_easy_pin, null, false)
binding.fragment = this
binding.vm = vm
binding.lifecycleOwner = this
//For hide softKeyboard
binding.etEasyPinConfirmation.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
}
override fun beforeTextChanged(s: CharSequence, start: Int,
count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
if (s.length == 6) {
hideSoftKeyboard()
Toast.makeText(activity, "Length is 6", Toast.LENGTH_SHORT).show()
}
}
})
bottomSheet.setContentView(binding.root)
bottomSheet.setCancelable(false)
bottomSheet.show()
}
And this is the function for hiding soft keyboard:
fun hideSoftKeyboard() {
inputMethodManager.hideSoftInputFromWindow(view!!.windowToken, 0)
}
And this is the global variable and declaration that variable in onViewCreated:
// global variable
private lateinit var inputMethodManager : InputMethodManager
..
// in onViewCreated
inputMethodManager = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
But when the length of value EditText is 6, the Toast is showing, and I already debugging it the function is executed, but the keyboard not hide. Does anyone know why my code is not working for hiding a soft keyboard in BottomSheet? Because if EditText is not in BottomSheet, this function is a success for hiding the soft keyboard
I just used the next code:
fun hideSoftKeyboardBottomSheet(view: View) {
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
and insert the view form Bottom Sheet into this function
Use this updated method kotlin version
fun Activity.hideKeyboard() {
hideKeyboard(currentFocus ?: View(this))
}
fun Context.hideKeyboard(view: View) {
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as
InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
Before proceeding further check that are you getting events of editext or button while clicking on it try to print log in addTextChangedListener().
I think you are not getting the event I had this issue before.
I have a small issue with AutoCompleteTextview with
textwatcher.
I Have AutoCompleteTextview for Suggestion.The data Comes From API side. With every new word I write in, API is being called and, it gets Response from ApI side and then, The show Dropdown menu for suggestion is shown.So basically that code is in AddTextWatcher Listener.
But when I click on Particular Suggestion, the AddTextwatcher is being Call and it recalls the ApI and the suggestions are shown again!So it is like
-Write in AutoCompleteTextview >> Api is being Called >> Fill in the Data >> Show Suggestions >> and Click On Suggestion >> Show Suggestions again.
Help me with this particular problem.
Thanks in Advance.
Basically its not hard.
This Post save my day.Thanks for this Post.
http://blog.hackerkernel.com/2015/12/30/autocompleteedittext-with-dynamic-data-from-json/
Decclare variable :
private var textWatcher : TextWatcher? = null
private var selectedItemId: String? = null
Initialize the declared variable and apply text watcher as :
textWatcher = object : TextWatcher {
override fun afterTextChanged(char: Editable?) { }
override fun beforeTextChanged(char: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(char: CharSequence?, p1: Int, p2: Int, p3: Int) {
if(selectedItemId!=null){
return
}
callApi()
}
}
When the response is received from API :
val adapter = ArrayAdapter(requireActivity(),
R.layout.custom_spinner_item, R.id.item_text_view, itemList!!)
mBinding.AutoCompleteTextview.setAdapter(adapter )
mBinding.AutoCompleteTextview.error = null
mBinding.AutoCompleteTextview.removeTextChangedListener(textWatcher)
mBinding.AutoCompleteTextview.showDropDown()
mBinding.AutoCompleteTextview.setOnItemClickListener { adapterView, view, position, l ->
selectedItemId = adapter.getItem(position)!!.id!!.toString()
mBinding.AutoCompleteTextview.clearFocus()
}
Final step :
mBinding.AutoCompleteTextview.setOnFocusChangeListener { view, b ->
if (b){
mBinding.AutoCompleteTextview.addTextChangedListener(textWatcher)
}
}