How to detect soft-keyboard pressed when talkback is on - android

When talkback is on. It seems like there is no way to detect soft-keyboard pressed
I tried to use both TextView.onKeyPreIme and TextView.setOnEditorActionListener but no luck.
Do you guys have any idea how to archive this?
class MyEditText #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : EditText(context, attrs, defStyleAttr) {
override fun onKeyPreIme(keyCode: Int, event: KeyEvent?): Boolean {
interactor?.onSoftKeyBoardPressed(keyCode, event)
return super.onKeyPreIme(keyCode, event)
}
init {
setOnEditorActionListener { v, actionId, event ->
log("Hi there", actionId.toString())
false
}
}}

Related

Using OnStateChanged listener simultaneously with OnTouchListener

I am implementing a rotary knob based on this library.
This View comes with a onStateChanged listener that tells me the current position of the knob.
val knob = findViewById<View>(R.id.knob) as Knob
knob.setOnStateChanged(object: Knob.OnStateChanged{
override fun onState(state: Int) {
// do stuff
}
})
In addition to that, I want to know when the user is no longer pressing/holding the knob (similar to a button release). I tried to achieve this with a onTouch listener.
knob.setOnTouchListener(object: View.OnTouchListener{
override fun onTouch(view: View?, event: MotionEvent?): Boolean {
// do stuff
}
})
Problem: When I add a second onTouch listener, it is no longer possible to hold and rotate the view for some reason. I do not know whether this is a problem of this particular library or Android in general.
Any suggestions on how to implement the wanted features?
A view can only have a single OnTouchListener. Unfortunately, the author of that library implemented some of its functionality using an OnTouchListener, which prevents users from using an OnTouchListener.
An alternative for you would be to subclass Knob and override onMotionEvent, like this:
class MyKnob: Knob {
constructor(context: Context): super(context)
constructor(context: Context, attrs: AttributeSet): super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int): super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int): super(context, attrs, defStyleAttr, defStyleRes)
override fun onTouchEvent(event: MotionEvent): Boolean {
val result = super.onTouchEvent(event)
if (event.action == MotionEvent.ACTION_UP) {
// User released knob
}
return result
}
}
Then you'd need to use this class in your layout instead of the original Knob class.

How do detect back press when the cursor is in the EditText in Kotlin?

I needed to detect back press when the cursor is in the EditText.
When user press back, it hide soft keyboard. I needed to do some other functionality when soft key board hides.
You can do this by creating a Custom EditText and override the onKeyPreIme method like below :
package com.fi.stackoverflow
import android.content.Context
import android.util.AttributeSet
import android.view.KeyEvent
import android.widget.Toast
import androidx.appcompat.widget.AppCompatEditText
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) {}
override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// you can do your action Here
Toast.makeText(context,"Try to hide KeyBoard",Toast.LENGTH_SHORT).show()
return true // true if you don't want to hide the KeyBoard and False otherwise
}
return super.onKeyPreIme(keyCode, event)
}
}
and in you xml file use it like below (don't forget to change your package name)
<com.fi.stackoverflow.CustomEditText
android:id="#+id/inputEditor"
android:layout_width="150dp"
android:layout_height="60dp"/>
and this in my Activity
val editText = findViewById<CustomEditText>(R.id.inputEditor);

Intercept touch event in RecyclerView while ignoring EditText inside

I have recyclerView with and item as seen below:
Now I want to be able to click anywhere on the item and editText should come into focus.
I can do that by setting onTouchListener on my view like this:
row_item.setOnTouchListener{ _, _ ->
editText.requestFocus()
view.background = Color.GREEN.toDrawable()
true
}
I also want to run some additional code whenever the item is clicked. Here I'm putting background color change for the sake of the example.
The problem is that whenever I click editText itself it is getting focused, but row_item touchListener is ignored, and the background doesn't change its color.
From my research, I've found that I should somehow intercept touch event. I thought I can do that by returning true in row_item.setOnTouchListener, but it doesn't work as you can see.
How can I intercept such touch event?
You should create a custom container class and then override onInterceptTouchEvent method and do your stuff there, then using this custom container class as the root of the item. Look at the following code:
class CustomFrameLayout : FrameLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
private var mOnInterceptTouchEventListener: OnTouchListener? = null
fun setOnInterceptTouchEventListener(onInterceptTouchEventListener: OnTouchListener) {
this.mOnInterceptTouchEventListener = onInterceptTouchEventListener
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
if(mOnInterceptTouchEventListener != null && mOnInterceptTouchEventListener?.onTouch(this, ev) == true)
return true;
return super.onInterceptTouchEvent(ev)
}
}
And then adding this listener to your row_item
row_item.setOnInterceptTouchEventListener(object: View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
editText.requestFocus()
v?.background = Color.GREEN.toDrawable()
return false
}
})
it may not be the best answer but it works.

RecyclerView scrolls only on specific view touch

I wonder how I can achieve such behaviour of the RecyclerView, that I could scroll the list only when I click and drag only specific view within the ViewHolder?
I've disabled horizontal scroll by creating my own LinearLayoutManager:
class MyOwnLayoutManager : LinearLayoutManager {
constructor(context: Context?) : super(context)
constructor(context: Context?, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
private var isScrollEnabled = false
fun setScrollEnabled(isEnabled: Boolean) {
isScrollEnabled = isEnabled
}
override fun canScrollVertically(): Boolean {
return isScrollEnabled && super.canScrollVertically()
}
override fun canScrollHorizontally(): Boolean {
return isScrollEnabled && super.canScrollHorizontally()
}
}
Then, I try to change the isScrollEnabled by setting the touch listener to the item's header:
item_header.setOnTouchListener { v, event ->
val isScrolling = event.action == ACTION_MOVE
onHeaderIsDragging.invoke(isScrolling)
false
}
Callback in the fragment that changes adapters' layout manager var:
private val onHeaderIsDragging: ((Boolean) -> Unit) = {
recyclerViewLayoutManager.setScrollEnabled(it)
}
By this implementation, I get MOTION_CANCEL after a couple of MOTION_MOVE events in the onTouchListener and RecyclerView is not scrollable after MOTION_MOVE events.

Intercept ACTION_DOWN and ACTION_UP but still send to children views

I'm extending LinearLayout and overriding onInterceptTouchEvent and onTouchEvent because I want to receive all touch event on all children views. I'm only interested in receiving the ACTION_DOWN and ACTION_UP MotionEvents. I still want the children view to receive all the events.
The problem I found is that if
Return false from onInterceptTouchEvent: all subsequent MotionEvents are sent to the children views and I will not receive ACTION_UP.
Return true from onInterceptTouchEvent: all subsequent MotionEvents are sent to my onTouchEvent view and the children views will not receive any.
class LinearLayout : android.widget.LinearLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
Log.d("LinearLayout", "onInterceptTouchEvent >> $event")
return when (event.action) {
MotionEvent.ACTION_DOWN -> true // or false
MotionEvent.ACTION_UP -> true
else -> false
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
Log.d("LinearLayout", "onTouchEvent >> $event")
return true
}
}
Is there any way to intercept all MotionEvents and send them all to the children views? If not, is there any other way to intercept all touch events over a ViewGroup?

Categories

Resources