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

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.

Related

ConstraintLayout stealing taps from setOnClickListener

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.

Android: How to figure out what view is stealing my touch events?

I have a bottom drawer - a view that is bottom aligned with the bottom of the screen and when dismissed animates itself down until it becomes invisible (in such state its top border is aligned with the bottom of the screen). I am trying to implement dismissing this view by vertical swipe down on it. To do it I attached a gesture detector in this method of the view:
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
I did it this way since this view contains a horizontal recycler view, so I do not want to intercept the child touches too early to make sure my view responds only to swipe down and does not steal horizontal touches from the recycler view (as described here: https://developer.android.com/training/gestures/viewgroup.html)
Now, my problem is that when I swipe on one area of this view, the fling recognition works, while when I swipe on another area ofthis view it does not work. In the first case I see in the debugger that onInterceptTouchEvent is called three times, the third call is recognized by the gesture recognizer as fling. In the second case I see that onInterceptTouchEvent is called only once.
It looks that some other view is stealing my touches, but I have no idea which one is that since my app is pretty complex and I am not the only author :). What is an easy way of debugging that in a general case? I would like to just know what view in the entire hierarchy of my activity consumed my event making onInterceptTouchEvent called only once - that would be a good start for the further investigation.
Thanks!
The way I do it is using emulator with android source code downloaded.
I put a breakpoint in View.dispatchTouchEvent (all places that returns true). This will show me which view is handling the event.
If this does not help, you can also place various breakpoint log messages.
I hope this will help you solve the problem :D

How to change view of a widget in android?

Let's say,I have a widget that shows the content of my website .
There is a refresh icon png in the left bottom corner of my widget.
Now,I would like the refresh icon rotate itself until I get content from my server.
How can I do ?
Use AsynkTask, start Rotation animation in onPreExecute() and stop animation in onPostExecute() method
You cannot modify the view directly because the view within a widget is placed outside your process (outside your address and memory space).
The widget view is placed within some system process and system makes all the calls to the android.view.View or android.view.ViewGroup directly.
Android allows external processes access these 'embedded' views by using RemoteViews class.
The RemoteViews class represents a set of actions that system should do in order to modify the internal view. For example RemoteViews.setViewVisibility() is an equivalent of View.setVisibility().
Now once you have the above in mind you see that there's no way of overriding view classes in the view hierarchy (because there is no simple enough way of transferring that class override down to a system process and make system use that implementation instead of the "stock" one).
As a solution to your problem you have two views in the view hierarchy.
The one would be the rotating button and the other the button which reacts to touches.
When user touches the button view you then hide it and show the rotating view. Upon server's response you would hide first view and show the button view back again.

One touch event puts all child views into pressed state

Doubtless this is caused by my decidedly unorthodox layout - I have buttons in a LinearLayout in an Activity which is placed by an ActivityGroup into a Gallery. The ActivityGroup is also the adapter implementation and the over-all effect is full-screen sliding, snapping panels.
This is working (a treat, actually) except that a touch event on the parent layout puts all the buttons into the pressed state (and any release removes the state). A touch on an individual button is only delivered to that button.
The buttons are not receiving any events, they're only changing state.
Have I done something obviously wrong? Is this a known bug and is there a work-around?
Any insights would be very much appreciated.
As obscure as this problem is its solution may be of use to someone else, so I'll answer my own question.
As mentioned, I'm (mis)using the Gallery to provide a slidey-panel à la iPhone. I do this by returning the top level window of an Activity when the Gallery asks its Adapter implementation for a view.
Typical use of a Gallery would result in small Views to which it's desirable for the press event to be applied - it's more like a button then it is a panel. Our use means that there are many buttons in a single view and we don't want the press event to ever be applied globally.
So the work-around was very easy. I extended Gallery and deliberately broke pointToPosition(int x, int y), returning INVALID_POSITION every time. The Gallery still does everything else expected of it but skips trying to apply the touch down event to any elements but itself (to prepare itself to scroll or fling).
I hope this is of value to someone.

ViewFlipper caching issue

The views are not cached in a ViewFlipper. Is there a way wherein we can get an image of the view and show it to user so that he sees the Ui as we see on Home scrren(when we swipe the previous view also moves along and when we lift our finger, only then the next view is shown completely.)
What I want to do is that when the user starts moving his finegr on screen, the view should also move along(create an image of view).
I am not getting to do this, as when we swipe the present view goes and next view comes, we do not get both visible when we r moving our finger on screen.
Please if anyone gets what I am trying to do, do help me.
Thanks,
Farha
It's tricky to get scroll and swipe tracking working on Android, while using ViewAnimator or its subclasses.
They allow you to set in and out animations and start them at a given moment, but they work with discrete, either-this-or-the-other-view animations. They are actually using FrameLayout and after in or out animation is executed, other views' visibility is set to View.GONE to hide them from showing up under/over your current View.
The Launcher and the Gallery application are actually doing the functionality you want, by using a different approach.
They track the user touch input (onTouchEvent()), on MotionEvent.ACTION_MOVE they perform animations manually and on MotionEvent.ACTION_UP snap to the appropriate view, just like in the iPhone.
Unfortunately, this approach is actually more complicated than it looks like.
With the manual handling, you have to ensure that you are taking care of everything related to the touch input. This includes a lot of flag-raising, value-checking, event-delegating, etc.
If you want to get better acquainted with this, take a look at these classes from Gallery3D or Launcher's source code.
One other way to get nice horizontal scrolling is to use HorizontalScrollView.
You have to figure out a way to recycle your views, like you would with a ListView and you have to add the snap-to-view logic, but if you have to take care of a small number of views it could be the easiest approach.
Hope that helps.

Categories

Resources