How to keep dialog open on outside touch and catch outside touches? - android

So this has been bothering me for the past couple of hours.
I have a dialog which extends, you guessed it, Dialog. I do not want to close the dialog when the user click outside of the dialog. That's rather easy, since I can simply use this line: dialog.setCanceledOnTouchOutside(false). However, I do want to perform certain actions when the user touches outside of the dialog. That the dialog does not close is easy too (How to cancel an Dialog themed like Activity when touched outside the window?):
getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);
getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
And then implementing a custom onTouchEvent(MotionEvent event).
However, this does not only not dismiss the dialog, but also performs actions to underlying, say, buttons and such. I've tried some of the other potential answers (empty, false returning onTouchListener on root view, checking whether or not a touch was inside the dialog, etc.) in the post as well, but to no avail.
Now my question is: How can I create a Dialog that does not close on outside click, nor does it perform actions on buttons and such on the underlying layout/activity, but does inform me/catches an event when the user clicks outside the dialog?

I would rather use DialogFragment with custom layout. In layout create viewgroup that will fill UI and will be transparent (that layout will catch outside clicks). Put your dialog inside this layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/background"
android:gravity="center"
android:background="#color/transparent">
...
</LinearLayout>
Then in onCreateView:
View view = inflater.inflate(R.layout.popup_exit, container, false);
LinearLayout background = (LinearLayout) view.findViewById(R.id.background);
background.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("ExitDialogFragment", "onBackground click");
}
});
and onCreate:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Translucent_NoTitleBar);
}
Tested it and it works.

Related

Can a custom view get something like "onClose" or "onDestroy" event?

I have created a custom compound view by extending FrameLayout. That view can be on a dialogue box (among others). But what if I want to do some clean-up work when the view disappears from the screen, such as the user's closing the dialogue box? Can I get some kind of onDestroy event? Or should I make the owner (such as the dialogue box or the fragment) call the view's clean-up method on its (owner's) onDestroy or dismissed event?
try to use
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}

Android - Memory leak with popup window in Recyclerview

I'm having trouble with the following error displaying in my app:
"E/WindowManager: android.view.WindowLeaked: Activity com.awt.myapp.MyList has leaked window android.widget.PopupWindow$PopupDecorView{84fdb1f V.E...... .......D 0,0-369,120} that was originally added here..."
Basically I've got a recyclerview and in the adapter I have a bunch of textviews in each row and am binding click listeners to them, as clicking one of these textviews brings up a popup window. The problem is if I hit the Android back button while a popup is still visible the above error appears.
I understand that in my activity that holds the recyclerview I can add an 'onBackPressed()' method, but from here I'm not sure how to get a reference to any of the popup windows within the adapter (and close it at this stage) as I believe this is what I need to do.
Below is my click listener code, I've experimented with some options and having setFocusable just causes the back button to stop working so not sure if that's needed.
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View moreInfoView) {
myPopupWindow.setBackgroundDrawable(new ColorDrawable());
//myPopupWindow.setFocusable(true);
myPopupWindow.setTouchable(false); // Ignores taps
myPopupWindow.setOutsideTouchable(true); // Disappear when tapping anywhere on screen
int position = -tv.getHeight();
myPopupWindow.showAsDropDown(tv, 0, position);
((MyList) context).onToggleMoreInfo("show");
myPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
((MyList) context).onToggleMoreInfo("hide");
}
});
}
});
Hopefully this makes sense, if you need any more info let me know. Any advice would be appreciated.
If you create a listener on your adapter that implements the activity and calls it when you click on the item, you can export popup window logic to activity and override on back pressed to dimiss it.

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.

Clickable TextView only works once

I made a textview clickable then it triggers an intent, it works but only once. After clicking the textview the first time it's no longer clickable and I have no idea why. Your help will be appreciated.
<TextView android:text="Click Me" android:layout_height="wrap_content"
android:layout_width="match_parent" android:id="#+id/textView1"
android:textSize="50dp" android:focusable="false" android:longClickable="true"></TextView>
TextView txt = (TextView) findViewById(R.id.textView1);
txt.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
startActivity(new Intent(Example.this, Alert.class));
return false;
}
});
What does the alert class do? If it is an activity it could be that it is being laid over the top of your current activity so although you can see your activity, it's not at the top of the stack/in the foreground so you're not actually pressing the TextView, you're pressing a transparent activity that is over the top of it.
The easiest way to check that is to press the TextView, then press your device's back key and see if the TextView responds to the click.
Or are you sure you're not setting the same layout in Alert.class? That would make it look like it's the same activity but if the Alert class doesn't set the click listener, nothing is going to happen.
The fact that you're starting an activity with an intent and that's making an instance of another class (which I assume is also an activity) stops the click working to me is seriously suggesting that Alert is getting the click somehow instead of Example. When you say things work fine if you remove the intent backs that up as well. Maybe you could post the full source of both classes?
Do you have an onClickListener that disables the textview?
By returning false from onLongClick Android would also invoke the onClick listener if you have one.
Also you could try to remove android:focusable="false"

how to change the view of a button onClick in android

In my app I am trying to calculate an operation using timer. For controlling those operations I am using four buttons as Start, Stop, Pause and resume.
But I want to show only 2 buttons. At the beginning I have only two buttons Start and Pause.
When the start button is clicked timer gets started and immediately in Start button's place I want to show the Stop button.
I want to do the same for the other stop and pause buttons. How to do this please help me......
Using ToggleButton is a good solution for you. Do something like:
ToggleButton first = new ToggleButton(getContext());
ToggleButton second = new ToggleButton(getContext());
first.setTextOff("start");
first.setTextOn("stop");
second.setTextOff("pause");
second.setTextOn("resume");
and use setOnCheckedChangeListener() to implement your actions.
In your onClick(View v), v is the button that gets clicked. You can cast it like:
Button b = (Button) v;
so you can change its text with setText(), and set another listener. You can declare the alternate listeners once as members of the activity, and set them without re-declaring them each time.
Your application needs to maintain states, such as "Idle/Stopped", "In Progress", "Paused", etc. If you want to hide buttons, you can use View.setVisibility, and dynamically show and hide the buttons when your state changes (when other buttons are pressed). You would need to set your layout appropriately so that the buttons display nicely as they are shown/hidden dynamically
Or, you can change the text of the buttons, and their associated click listeners dynamically. This method is not very ideal becuase you may run in to cases where you want different amount of buttons for all your different states, and also, you're associating variable behavior with a single control. Also, you must manage your click listeners, adding and removing them dynamically.
here is a simple implementation
public class Demo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button=(Button)findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
button.setText("stop");
}
});
}
}
In the main.xml have a Button widget like this,
<Button android:id="#+id/button"
android:text="start"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>

Categories

Resources