I have a TextView in a layout whos background is a Selector. And the TextView's text is set to Spanned from HTML.
Then I set the TextView with the LinkMovementMethod.
Now when I tap on the TextView, the click event is not sent to its parent layout to trigger the selector.
How should this be solved?
Declare your TextView not clickable / focusable by using android:clickable="false" and android:focusable="false" or v.setClickable(false) and v.setFocusable(false). The click events should be dispatched to the TextView's parent now.
Note:
In order to achieve this, you have to add click to its direct parent. or set
android:clickable="false" and android:focusable="false" to its direct parent to pass listener to further parent.
I think you need to use one of those methods in order to be able to intercept the event before it gets sent to the appropriate components:
Activity.dispatchTouchEvent(MotionEvent) - This allows your Activity to intercept all touch events before they are dispatched to the window.
ViewGroup.onInterceptTouchEvent(MotionEvent) - This allows a ViewGroup to watch events as they are dispatched to child Views.
ViewParent.requestDisallowInterceptTouchEvent(boolean) - Call this upon a parent View to indicate that it should not intercept touch events with onInterceptTouchEvent(MotionEvent).
More information here.
Hope that helps.
Sometime only this helps:
View child = parent.findViewById(R.id.btnMoreText);
child.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
View parent = (View) v.getParent();
parent.performClick();
}
});
Another variant, works not always:
child.setOnClickListener(null);
Put
android:duplicateParentState="true"
in child then the views get its drawable state (focused, pressed, etc.) from its direct parent rather than from itself.
you can set onclick for parent and it call on child clicked
If your TextView create click issues, than remove android:inputType="" from your xml file.
This answer is similar to Alexander Ukhov's answer, except that it uses touch events rather than click events. Those event allow the parent to display the proper pressed states (e.g., ripple effect). This answer is also in Kotlin instead of Java.
view.setOnTouchListener { view, motionEvent ->
(view.parent as View).onTouchEvent(motionEvent)
}
If you want to both OnTouch and OnClick listener to parent and child view both, please use below trick:
User ScrollView as a Parent view and inside that placed your child view inside Relative/LinearLayout.
Make Parent ScrollView android:fillViewport="true" so View not be scrolled.
Then set OnTouch listener to parent and OnClick listener to Child views.
And enjoy both listener callbacks.
Then I set the TextView with the LinkMovementMethod.
TextView.setMovementMethod() internally calls a private method fixFocusableAndClickableSettings. It is the root of the problem: calls setFocusable(FOCUSABLE); setClickable(true); setLongClickable(true);. So no matter what clickability you think you've set, it'll be all true.
source
Those 3 flags have to be reset back to false in order for the view to become non-clickable.
Related
I want to execute some action if user click the space(created by margin) between two items in RecyclerView, however I did not found a way to do that. OnTouchListener might do the trick but it is posible to get view by given coordinate (x, y)?
Setting onTouchListener on root does not do the trick, it seems like the event is handled by view on top of it. I want to register that can handle all ontouch event and pass the ontouch event to the right view after pre-handle.
You can also achieve this by creating margin using View tag-
Something like this-
<View
android:id="#+id/left_margin_view"
android:layout_width="10dp"
android:layout_height="match_parent"/>
Remove margin applied to recycle item root tag and create view and now you can use any event listener with this view id left_margin_view.
I have the following problem.
In an Android application, there is a custom layout class, which extends the FrameLayout. It overrides the onTouchEvent method for a custom implementation. We have a TextView which resides as the content of this layout class. We want that the URL links in this TextView to be clickable. For that purpose, we add 'android:autoLink="web"' to the TextView's property. The following Xml ensues:
<PinchZoomScrollView
android:layout_weight="350"
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="#+id/newsDetailScrollView">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="web"
android:id="#+id/newsDetailText"/>
</PinchZoomScrollView>
After adding autoLink="web", it seems that the onTouchEvent of the custom layout class "PinchZoomEvent" is not being called. It seems that the TextView with the autoLink property blocks touch events somehow. This is weird since the PinchZoomScrollView is TextView's parent and it should receive the event first. What should be done in this case?
Parents don't automatically receive touches first in Android. You're thinking of other frameworks. Touch events start at the children and go up the chain in Android. If you have a parent class such as a scroller that wants to intercept touch events and possible override the child behavior, it needs to implement onInterceptTouchEvent, and return true from it when it detects an action it wants to take from the children.
I have two rows of imageViews in a ScrollView. The imageViews all have onClickListener and when i want to scroll in this area it doesn't work. So i guess the Click listeners intercept the scrolling of the ScrollView. What's the best way to change this behaviour ?
My View hierarchy is like this:
<ScrollView>
<RelativeLayout>
<FrameLayout>
</FrameLayout>
<RelativeLayout>
</ScrollView>
in the FrameLayout i put a Fragment which has a LinearLayout in which i inflate other LinearLayouts like this:
productHolder.productLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
}
});
Maybe you could use an OnTouchListener instead of an OnClickListener.
In the OnTouchListener you can check if the action of the motion event was a click and consume the event (return true). Otherwise you can leave the event for other listeners (return false) to consume.
Note, that you might need to add some additional implementation for figuring out which image view was clicked, however without seeing your layout, it's hard to give you a hint how to do it.
When I using XML to design layout, I am using findViewById() in java code to load views and set listeners to them.
Is this correct what I am doing? May be it is possible to set listeners in XML or something?
Most people set their listeners in code. It's sometimes easier to do it in code because you often times will need to add or remove listeners based on some action or state.
However, Android also gives you the option of setting a OnClickListener for any View in XML. Here's an example:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onActionClick"
android:text="Action" />
Using the onClick attribute, you assign the name of the method that will handle the click. This method must exist in the same Context as the View, so in the same Activity. So for example, I would have to implement this method:
public void onActionClick(View v) {
// Do stuff for my "Action" button...
}
I believe it has to have a View parameter, just like implementing OnClickListener would. I also believe it must be public.
So as far as which way is "best"? That's up to you. Both routes are viable. It's worth noting though that this is only useful for click listeners and not other types of listeners.
There is an onClick attribute that you can use inside your xml.
You may specify android:onClick attribute when describe your View in XML. The value of this attribute is the name of the method which will be called at your View's onClick event. Then you should define this method as public in your code and you could pass there View object which will determine what View from those that you described at xml with the same android:onClick attributes has gotten touch event from user.
you can set an onClick but I think thats about it
I have a TextView in a layout whos background is a Selector. And the TextView's text is set to Spanned from HTML.
Then I set the TextView with the LinkMovementMethod.
Now when I tap on the TextView, the click event is not sent to its parent layout to trigger the selector.
How should this be solved?
Declare your TextView not clickable / focusable by using android:clickable="false" and android:focusable="false" or v.setClickable(false) and v.setFocusable(false). The click events should be dispatched to the TextView's parent now.
Note:
In order to achieve this, you have to add click to its direct parent. or set
android:clickable="false" and android:focusable="false" to its direct parent to pass listener to further parent.
I think you need to use one of those methods in order to be able to intercept the event before it gets sent to the appropriate components:
Activity.dispatchTouchEvent(MotionEvent) - This allows your Activity to intercept all touch events before they are dispatched to the window.
ViewGroup.onInterceptTouchEvent(MotionEvent) - This allows a ViewGroup to watch events as they are dispatched to child Views.
ViewParent.requestDisallowInterceptTouchEvent(boolean) - Call this upon a parent View to indicate that it should not intercept touch events with onInterceptTouchEvent(MotionEvent).
More information here.
Hope that helps.
Sometime only this helps:
View child = parent.findViewById(R.id.btnMoreText);
child.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
View parent = (View) v.getParent();
parent.performClick();
}
});
Another variant, works not always:
child.setOnClickListener(null);
Put
android:duplicateParentState="true"
in child then the views get its drawable state (focused, pressed, etc.) from its direct parent rather than from itself.
you can set onclick for parent and it call on child clicked
If your TextView create click issues, than remove android:inputType="" from your xml file.
This answer is similar to Alexander Ukhov's answer, except that it uses touch events rather than click events. Those event allow the parent to display the proper pressed states (e.g., ripple effect). This answer is also in Kotlin instead of Java.
view.setOnTouchListener { view, motionEvent ->
(view.parent as View).onTouchEvent(motionEvent)
}
If you want to both OnTouch and OnClick listener to parent and child view both, please use below trick:
User ScrollView as a Parent view and inside that placed your child view inside Relative/LinearLayout.
Make Parent ScrollView android:fillViewport="true" so View not be scrolled.
Then set OnTouch listener to parent and OnClick listener to Child views.
And enjoy both listener callbacks.
Then I set the TextView with the LinkMovementMethod.
TextView.setMovementMethod() internally calls a private method fixFocusableAndClickableSettings. It is the root of the problem: calls setFocusable(FOCUSABLE); setClickable(true); setLongClickable(true);. So no matter what clickability you think you've set, it'll be all true.
source
Those 3 flags have to be reset back to false in order for the view to become non-clickable.