Sorry for the big amount of code guys. Im at a loss lol. I needed a way in an EditText to overwrite chars, but skip the two spaces when the curser comes to them. So that spaces will be "Permanent" in a sense. This is for a basic hexadecimal editor style text box. While this somewhat does work, an when it does its slick. But it seems to have some flaw I am missing, Sometimes when you re typing it will start inserting characters, specifically when the curser is in between two chars ex this is before : "01 02 0|3 04 05" if you type 5 it should replace the 3, then skip over the spaces and end up at the next 0 But it ends up either one of two things, either inserting "01 02 05|3 04 05" or overwriting the 3, and removing one of the two space while jumping "01 02 05 |04 05". lastly it used to sometimes replace a space when the curser was next to a pace but didn't jump over the two spaces, I believe I have worked this out but I've been working on the other problems so I may have been blinded a bit and not noticed it. I'm guessing my text watcher is not being invoked by either formating var not returning to false, or some other thing I've overlooked. Because once curser is moved IE you touch somewhere else in the text, it begins to work briefly till it ends up inserting in between digits again. Anyone see anything I may have missed?
Here is the code so far:
class CustomEditText : AppCompatEditText {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var isFormatting = false
private var mStart = -1 // Start position of the Text being modified
private var mEnd = -1 // End position of the Text being modified
private val watcher = object : TextWatcher {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
mStart = -1
// Keep track of the start and end position of the text change
if (before == 0) {
// The start and end variables have not been set yet, and there are no characters being deleted.
// Set the start position to the current cursor position.
mStart = start + count
// Set the end position to either the end of the string or the current cursor position + count.
mEnd = min(mStart + count, s!!.length)
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
// No action needed before text change
}
override fun afterTextChanged(s: Editable?) {
// Avoid infinite recursion if the TextWatcher is modifying the text
if (!isFormatting) {
if (mStart >= 0) {
// Set `isFormatting` to true to indicate that we're currently formatting the text.
isFormatting = true
// Check if the current position is a digit
if (Character.isDigit(s!![mStart - 1])) {
// Check if the next position is a space or the end of the string
if (mStart < s.length && s[mStart] == ' ' || mStart == s.length) {
// If the next position is a space or the end of the string, insert the digit at the next position
s.insert(mStart, s[mStart - 1].toString())
mStart++
} else {
// Overwrite the text at the current position
s.replace(mStart, mEnd, "")
}
} else if (s[mStart - 1] == ' ') {
// Check if the next position is a digit
if (mStart + 1 < s.length && Character.isDigit(s[mStart + 1])) {
// Jump over the spaces and overwrite the first character in the next set
mStart = s.indexOf(" ", mStart) + 2
s.replace(mStart, mStart + 1, "")
} else {
// Overwrite the text at the current position
s.replace(mStart, mEnd, "")
}
} else {
// Overwrite the text at the current position
s.replace(mStart, mEnd, "")
}
isFormatting = false
}
}
}
}
init {
// Initiate and add the text change listener "watcher"
addTextChangedListener(watcher)
}
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
// Get the current text in the EditText
val text = text
if (text != null) {
val len = text.length
// If the selection start and end are equal, meaning the cursor is at a certain position
if (selStart == selEnd) {
// Check if the cursor is positioned at a space between two hexadecimal digits
// And if the character after the space is also a space
if (selStart != 0 && selStart < len && text[selStart - 1] == ' ' && text[selStart + 1] == ' ') {
// Move the cursor one position to the right to position it at the start of the next hexadecimal digit
setSelection(selStart + 1)
return
}
// Check if the cursor is positioned at a space and the character after the space is not a space
if (selStart < len && text[selStart] == ' ' && (selStart + 1 >= len || text[selStart + 1] != ' ')) {
// Move the cursor one position to the right to position it at the start of the next hexadecimal digit
setSelection(selStart + 1)
}
}
}
// Call the superclass implementation of onSelectionChanged
super.onSelectionChanged(selStart, selEnd)
}
}
I've also toyed with using drawables for the spaces, I even thought that maybe if I make a custom drawable similar to a tictactoe board if you will, and have the digits in between the drawable to achieve the same result. I know either way I still have to handle backspaces and the arrow key movement in the even the user is using a keyboard, but that's a 3 day debug session for another time. If anyone has any ideas or see anything I missed that would be awesome, Or if you think this approach is not the best. I tired many different ways to approach this but this got the closest result to working. I do feel as though a drawable may be much more resource intensive than a text watcher, albeit this would be as well with larger files, but that can all be solved down the road. This is allot, and I don't expect a magical fix. But more eyes on a project might be able to spot what I've missed, thank you for your time =)
EDIT-----------
So it seems this is a buggy way to go about this type of use case, and very unreliable. Ive started working on instead overriding the onDraw method in EditText to simply draw the text in the positions. Hoping this isn't too resource intensive as I haven't ran the code on hardware yet to see but at any rate I'm assuming it will stay in place when edited and be pretty resource efficient as compared to other methods I've tried(Some even an S22 ultra had a hard time with). Then it's simply implementing overwrite mode. Which i have already done. Hopefully this pans out. If anyone has a better idea or if the above code can be made more reliable I would still love to see it! For now my efforts are going towards onDraw.