ConstraintLayout stealing taps from setOnClickListener - android

I have created an activity that will be used as a screen to display a custom-designed modal. The entire background of this activity will be a 30% black overlay view that should be tappable to dismiss the activity.
Here's a screen of the simple layout:
In onCreate, I added a setOnClickListener to the overlay:
overlayView.setOnClickListener {
println("tapped")
}
The overlay is receiving taps, which is desired, however the white 'modal' view is also receiving taps, which is not desired.
As you can see from the component tree in the above screenshot, I'm using a view (overlayView), and then above it, using a ConstraintLayout with a nested textView. I would think that since the white modal is above the overlayView, it would not be receiving taps from overlayView.
How can I structure / organize my component tree so that I can detect taps from just the overlayView, and not the white modal?

In general, touch events will go "through" views until they find one that actually handles the event. In this case, even though you're tapping on the modal view, the click event will go to the background overlay because the modal view doesn't do anything to intercept the event.
You can solve this by adding a do-nothing click listener to the modal view:
modalView.setOnClickListener { }
This causes the modal view to receive any click events on it and handle them, stopping them from going "through" to the background overlay view.

Related

How to make area editable/not editable using Togglebutton?

I was trying to make an area so when ToggleButton is on, you are able to toggle buttons within this area and if ToggleButon is off, you won't be able to toggle the buttons within this area.
For this specific area I used a FrameLayout, so I can stack two LinearLayout on top of each other. So when I hit the Edit-Button, the one on top which is half transparent disappears with setVisibility(View.GONE) and you are now allowed to click the buttons now.
PROBLEM: The buttons in this area are always clickable
I was able to toggle them separately with button.setClickable(true/false) but is there a solution so you just can't click through the LinearLayout that is on top (like "not-through-clickable")?
Link to an image of the Layout: https://i.imgur.com/eTyhCDc.png
Desired behavior:
Hit EDIT -> half transparent Layout on top of blue Layout disappears -> TESTOFF1 and TESTOFF2 are now clickable.
-> Hit DONE -> the half transparent Layout appears on top again and the buttons below it are not clickable anymore (without using .setClickable for every single button).
The view on top gets first crack at any touch events. If the top view doesn't handle the touch then the view below get a chance on down to the bottom view. The top layer is a LinearLayout so, but default, it doesn't handle touches, so it allows the touch events to percolate down to the buttons which are happy to respond.
One way to resolve this is to place a touch listener on the semi-transparent view that just returns true. Thus, the LinearLayout will consume the events and not let the buttons see them.
When the view is gone, the buttons become the top view so they will see the clicks.
If you want to know more about how touch events are handled, read this Stack Overflow answer for an excellent explanation.
editButton.setOnClickListener {
button1.isEnabled = !button1.isEnabled
button2.isEnabled = !button2.isEnabled
editButton.setText(
if (button1.isEnabled) {
R.string.done
} else {
R.string.edit
}
)
transparentView.isInvisible = button1.isEnabled
}
This example is using kotlin and the Android KTX libraries
Java version
editButton.setOnClickListener(new OnClickListener {
button1.setEnabled(!button1.isEnabled());
button2.setEnabled(!button2.isEnabled());
editButton.setText(button1.isEnabled() ? R.string.done : R.string.edit);
transparentView.setVisibility(button1.isEnabled() ? View.INVISIBLE : View.VISIBLE);
});

Don't allow touch events on items below view

I have a ListView with video items. When user clicks the image of the Video it goes to a new screen and starts playing the video. If user clicks a button next to the video image then I display a BottomSheet from google design library. Because I want to apply a shadow when bottomSheet is expanded I have a View with a transparent dark overlay just above the ListView, which initially has visibility set to Gone and I change it to Visible when I expand BottomSheet.
The problem is that despite the shadow layer items below it can still get click events which is a behavior I want to prevent. Is there a solution for this ? Maybe an attribute for that view so when its visible won't let touch events happen ?
Hey if you want to disable the touch intercept capability of view by you self. If it is a button or Views like Linearlayout, RelativeLayout just use view.setClickable(false) once you hide the view. Otherwise views intecept touch events even ,if they are not visible(Given that none other views are intercepting touch event for that portion of screen).

How can I disable a layout behind my SlidingDrawer in Android?

I have a SlidingDrawer that pops up from the bottom of the screen and fills the screen about 80%. Even though the SlidingDrawer view is in focus, it is still possible to click on items, buttons and other elements in the view that is behind the SlidingDrawer. When SlidingDrawer is active/pulled up/in focus, I want to disable the entire view behind it so it will not be able to recieve clicks and touches. Is there a good way to disable an entire view? I have tried setEnable(false) and setClickable(false) but neither of them work.
Grab the LinearLayout that holds the contents and add a click listener. Have the click listener respond to clicks (throw away, whatever) - and this then stops it propagating to the view below the sliding drawer - it works for me - and it doesn't block the other items in the drawer.
Other way is to put SlidingDrawer in the RelativeLayout, instead of LinearLayout. And set mySlidingDrawer.bringToFront() in opening method.

How can I interact with elements behind a translucent Android app?

I have found how to create a translucent background for my android app, but so far I haven't found how to interact with what's behind it (the home screen for example).
This post helped me make the app view translucent.
How would one go about allowing the user to interact with what's behind the translucent app? This app is a good example of an app that allows this is the "Transparent Screen" Android app.
A very simple way of understanding stacking of views is to take a book (any book). Think of each page as a view.
Visibility
When you open the book you can see a page (Main View - VISIBLE)
When you turn the current page you can see the next page (INVISIBLE - Main View to show the next view. Remember you are only hiding the view, if you set the visibility to GONE this is equivalent to tearing of the current page to view the next page.)
Touch scenarios
Assume your first page is a wax page (translucent page similar to your translucent view) so you can see the underlying page
When you try to touch a figure on the second page, you are touching the first page although you can see the figure on the second page. It is impossible to touch the figure on the second page through the first page.
Don't be disheartened, since it is a view you will be dealing with and not a paper you can still do what you want to do :)
Implement View.OnTouchListener for both your views
For translucent view any touch events you get, return FALSE in the method onTouch
Android will pass on the touch event to your underlying view.
I got the answer.
Adding line getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
in onCreate in second top activity(which is transparent did the trick).
Above solution has a problem. After using above whole window passes the touch to background. So if you want full control then better extend a layout e.g. Framelayout and override 'onTouchEvent' and get the touch location using event.getX() and event.getY() methods and return false where you want to pass the touch event. It will be passed to parent view.
FLAG_NOT_TOUCH_MODAL will do what you want with the least code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
...
setContentView(R.layout.my_activity_view);
...
}
public static final int FLAG_NOT_TOUCH_MODAL
Window flag: Even when this window is focusable (its {#link
FLAG_NOT_FOCUSABLE is not set), allow any pointer events outside of the window to be sent to the windows behind it. Otherwise it will
consume all pointer events itself, regardless of whether they are
inside of the window.

How do you do your dynamic layouts?

I want to dynamically hide/show controls in an activity based on a button touch event: when the user presses the "details" button, I want to show more controls in the same activity.
What is the best way to handle this? Is there a way to do TextView.Hide()? Can it animate the transition?
setVisibility() will allow you to make a widget visible, invisible, or gone. The difference between the latter two is that an invisible widget still takes up space, while a widget that is gone does not.
Android has an entire animation framework for slides, fades, spins, and the like. Here are two sample projects showing some of this.

Categories

Resources