clicking on the fragment invokes fragment behind - android

I have a really strange problem in my android app. The app contains several fragments and one of them consists a surfaceView. The most time changing to the fragment with the surfaceview works good but sometimes the replacement is unsuccessful. Then if I touch the surfaceview the fragment behind receives the touchevents and not the actual fragment.
But this only happens sometimes and not always. So it's really hard for me finding the reason.
Had anybody already the same or similar problem?
for replacing the fragment I use following code:
Fragment fragment = new Fragment();
fragment.setArguments(bundle);
ft.replace(R.id.frame_container, fragment).addToBackStack(null).commit();

It sounds like your surface view has not been told to respond to touch events.
Try making it clickable, either with android:clickable="true" or setClickable(true). That should prevent touch events from passing through the surface view to the fragment below.
Another trick I've used, for views that don't need to respond to touch, but do need to prevent events from going through them, is to add a touch listener and eat the event:
surfaceView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true; // true means the event has been processed
}
});

Related

how to catch all GenericMotionEvent when a DialogFragment is shown?

I need to show a preference dialog that wait for Joypad keypress.
I know that DialogFragment has its own Window then has its own onKeyListener.
I can easily catch Joypad press by setting a listener like that.
public class MyDialogFragment extends PreferenceDialogFragmentCompat {
#Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
builder.setOnKeyListener(new DialogInterface.OnKeyListener() {
#Override
public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) {
// do stuff with intercepted key press
return true;
}
});
}
}
But, I have trouble catching GenericMotionEvents. In order to intercept them, I've overridden onGenericMotionEvents in the Activity class and eventually forward the Event by calling a method on MyDialogFragment class.
It works 100% correctly when MyDialogFragment is not shown as when an analog trigger/direction stick is moved, I can get an event.
The weird part is that IF MyDialogFragment is shown, then I can get only analog direction stick events BUT NOT left/right analog triggers events.
Does someone know why and how to fix this behaviuor?
I've had a similar issue some time ago. You can use onGenericMotionEvent of Dialog or even some of the Views. It has some limitations though and works not as expected sometimes. It does work as intended though - it is just that sometimes all the generic motion events are being intercepted by something else and they aren't propagated any further anywhere - in this situation, you won't receive the callback trigger.
That is what was happening in my case and even overriding the callback method in Dialog(I haven't tried View though) failed to give me the needed result. What I did is a bit of a kludgy trick, but it did the job. I created my activity's UI as a child of one parent FrameLayout and my dialog UI was the topmost element in this FrameLayout. This trick allowed me to use the activity's native onGenericMotionEvent callback. It added some navigation handling overhead and was generally possible because of allowing UI design(without dialog shadow etc) but yeah...
Maybe some of these approaches will help you.

tracking all touch events

Situation
I want to implement a timeout in my app. If the user did not touch the screen within 2 minutes an inactivity fragment will be shown.
What i got so far
I am tracking the activity lifecycle using a custom Application implementing Application.ActivityLifecycleCallbacks. This way i know which Activity is currently on top and can access its FragmentManager to show my inactivity Fragment on timeout. A background Thread constantly checks if the last detected touch was longer ago than 2 minutes.
Problem
I dont know how to detect every touch that happens on the activity. I tried adding a OnTouchListener to activity.getWindow().getDecorView().setOnTouchListener(), but it is only called if the decorview is touched. If for instance a Button on top of it is touched my listener isn't notified. activity.getContentScene()' returns null for me, so i can't access the rootViewGroup` like that either.
Question
How can i detect any touches that happen on a Activity or the whole Application?
override dispatch touch event in your activity
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Rect viewRect = new Rect();
view.getGlobalVisibleRect(viewRect);
//or
int x= ev.getRawX();
int y= ev.getRawY();
if(/*check bounds of your view*/){
// set your views visiblity to gone or what you want.
}
//for prevent consuming the event.
return super.dispatchTouchEvent(ev);
}

Show fragment after calling dragndrop

In my app fragment(first fragment) where user can press on item and app will show fragment with list(second fragment), where user can drop caught item.
Code:
public void startDragNDrop(){
showFragmentWithList();
JSONObject object = new JSONObject();
object.put(Constants.PARAM_ID, getId());
ClipData data = ClipData.newPlainText("", object.toString());
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(mMainLayout);
mMainLayout.startDrag(data, shadowBuilder, mMainLayout, 0);
}
And when second fragment catches ACTION_DROP it will close himself. And it works well, but if user remove finger faster than method finish their work, dragndrop won't start and second fragment won't receive dragndrop event, as result new fragment won't disappear.
I tried to fix it via setting dragndrop listener at first fragment and when it will catch ACTION_DRAG_STARTED it will call showFragmentWithList() and fragment will show. But I faced of new problem, View.OnDragListener doesn't work for any views inside of second fragment. Can somebody help me with this problem?
You should start a drag-n-drop action prior to showing the second fragment, not the other way around. This is a natural order of events. This way you won't end up in a situation when the second fragment has already been shown but the actual drag-n-drop hasn't started yet.
It's hard to tell from the question where is the root of the problem but I would suggest trying to use a UI handler instead of calling methods directly. This way events will go to the UI message queue and thus, will be dispatched after the system events such as onStart(), onResume() and so forth. This might fix the problem of not receiving events in the second fragment.
Also please make sure your first fragment doesn't "steal" those drag events from the second fragment. Maybe it's your first fragment who receives ACTION_DROP and that's why the second one doesn't. Hope that helps.

Blocking UI interaction on a Fragment

I want to be able to block all UI interaction with a fragment until a callback occurs.
I have two buttons: ButtonA and ButtonB.
ButtonA shows a progress bar and kicks-off an asynchronous thread that calls-back to the fragment when it's done. In the meantime, someone can press ButtonB which I don't want to allow.
My solution was to spin up another fragment which is transparent and intercepts all clicks. However there appears to be delay between FragmentManagers commit() and the fragment actually working.
I've tried calling executePendingTransactions() but I still end up with threading issues whereby the fragment isn't in a state to accept onClick events before the user hits ButtonB.
Is there a more elegant solution?
Thanks,
John
Another option is to use a progress dialog fragment and set it to be non cancelable. It will cover the fragment and prevent the underlying fragment from receiving any touch event.
Instead of calling another fragment,u can have another tranparent view with a progress dialog above the present view and make its visibility VIEW or GONE accordingly.Else u can simply show a prgress dialog with cancelable parameter as false.
Call buttonB.setEnabled(false); after clicking buttonA.
CustomButton extends View {
private boolean mIsEnabled = true;
public void setEnabled (boolean enabled) {
this.mIsEnabled = enabled;
}
#Override
public void onClick() {
if (mIsEnabled) {
mOnClickListener.onClick();
} else {
return;
}
}
}
I didnt understood the question perfectly..
hope it may helps you.
when you adding transaprent fragment over it make the transparent layout clickable=true
if a view is mentioned as clickable it does not pass touch events to below views.
sorry if i understtod your question wrong.
Can't button A put its containing activity in a given state (with a boolean flag raised in its listener) and button B read that flag before doing any stuff ?
I think it's not only a UI issue here but also some presentation logic and mini-state machine that you should implement. This mechanism plus the fragment you already have should be enough to prevent gaps in the sequence of executions of UI Thread events.

android: How can i close fragment when the user touch outside of it?

Hi everybody =) i am a new android developer and i need a help about dismissing fragment.
My application have an login fragment and when the user touch the outside of it i want to hide login fragment. How can i make this? OnTouchEvent() method may be useful or not?
Please say something. Thanks =)
place the login layout inside a transparent, full screen layout, and detect touch events on the larger layout.
I think better way is removing fragment in order to release memory resources.
My solution is having having this method in fragment:
private void closeFragment() {
getActivity().getSupportFragmentManager().beginTransaction().remove(YOUR_FRAGMENT.this).commit();
}
Hi again =) i solve this problem using OnTouchListener on my Homepage activity.I have an gridviews background in my homepage layout and if the user doesn't login, onTouch() method runs.When the login fragment is visible and the user touch outside of it my hideLoginFragment() method calling for dismissing the fragment..
gridView = (ShelvesView) findViewById(R.id.grid_shelves);
gridView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (application.getDbManager().getUser().key.equals("-1")){
hideLoginFragment();
loginButton.setVisibility(View.VISIBLE);
exitButton.setVisibility(View.INVISIBLE);}
return false;
}
});

Categories

Resources