I have a button and while this button is playing an animation, I'm not able to click on button. I've set click listener and touch listener but in debug mode it's not entering in OnClick and in onTouch methods. Do you know why? Thanks
edit: I've tried something like:
AsyncTask task = new AsyncTask() {
#Override
protected Object doInBackground(Object... objects) {
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Toast toast = Toast.makeText(MyActivity.this, button1.getText(), Toast.LENGTH_SHORT);
toast.show();
}
});
return null;
}
;
};
task.execute(button1);
but it's not working
Edit: here is the full source code
Before Android 3.0, using any of the animation classes only changes where the view is drawn - it won't adjust its touchable-bounds during (or after) the animation:
http://android-developers.blogspot.com/2011/02/animation-in-honeycomb.html
You could:
Make a ViewGroup which moves its children every onDraw
Override your View's onDraw to move itself - Could use margin or padding, or position (if view is in a FrameLayout or something similar).
Only use 3.0+ devices
Override the parent's onTouch (or onInterceptTouchEvent), calculate where the View is being drawn (you can get how far into and the offset from real position from the Animation *) and handle accordingly... * Looking at your code (since you generate a random direction each time it finishes), this might not be possible without tracking which directions you've previously take..
you are facing same issue that i was recently ... when you apply animation on button or any other view and use setFillAfter(True) it means that the image of view is moved not the actual view thats why its not listening to your click listener because its just image of view not your actual view you have to do something like that i explained in answer to my own question according to your situation... means you have to also move the actual view on the end place of animation and use setFillAfter(false) so that when you click after anmation then it should be an actual view not just image used for animation purpose by android
check this link....
EditText stucks after animation and alive back on scrolling......?
In your code use setFillafter(false) and actually place your button at end position of animation by somehow like setting margin or according to your layout use appropriate properties for placement. By Applying these changes your click listener will work perfectly.
==> if you are trying that your button's click listener work while its moving (being animate) then as far as i know its not possible because android uses just image of your view to perform animation not the actual.
This might be a threading problem. You should read Event dispatch thread and how to do thing in android async by reading painless threading and take a look at AsyncTask JavaDoc.
In short: the main thread should not be blocked, since it is used for responing to UI events, such as button presses. Therefore, whenever you do something that take more than some milliseconds, you should do it asynchroniously in another thread.
I think there are two things
1)You can handle one event at one time for one object.Like animation is playing on you button that means you can not click on that untill one work get completed(As i understand you animation is on button not on other part of screen)
2)Second if you have playing on rest part of screen and you want to stop it on click of button.Then i think its a problem of focus.once set onfoucslistener to button and check that when you are clicking it Is it getting focus?
I would put the animation into the async task and then the button click should be handled normally on the main thread I think. Because the way you do it at the moment is: The animation starts and blocks the main thread. This means that the click event can't be excecuted in the async task
You must try to use AsyncTask . Programming Android without it would be and horrible usability serious problem.
See this link for how use an asynctask.
Here an example:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// Initialisation of the Activity
MyLongTask task = new MyLongTask();
task.execute("http://blog.fr4gus.com/api/test.json");
}
#Override
protected void onPause() {
// If you wanna make something in the pause of the Asynctask
}
class MyLongTask extends AsyncTask<String, Void, Void>{
#Override
protected void onPreExecute() {
// Before executing what you want to execute
}
#Override
protected Void doInBackground(String... params) {
// what you want to execute come here :D
return null; // Or whatever you want pass to onPostExecute
}
#Override
protected void onPostExecute(Void result) {
// Here we can update for example the UI with something (who knows :? )
}
}
}
MODIFIED
You must always extend the Asynctask Activity , since you are trying to pass params through it , you must define them in the head of your extended class :
class MyLongTask extends AsyncTask<String, Void, Void>{ ...
Then first is the doInBAckground param , next is the onPreExecute param , and the last is the onPostExecute param . That way you can send the params like a Button.
You can learn more about here or in my first link.
Related
Edit: Solved. The problem disappeared when I made all my custom views override Button instead of View.
I'm trying to programmatically create a screen-sized invisible view which should capture all click events, thereby blocking all underlying elements. But I'm having some trouble.
The intended goal is that when the user clicks a certain button, a menu is created. While this menu is up, the other buttons that were on the page should no longer function. Clicking on the menu should make stuff happen, clicking anywhere else should make the menu disappear and make the other elements work again.
I've managed to create the screen wide view just fine, and it captures clicks and destroys the menu whenever the user clicks a point that is not already covered by a button. When the user does click on a spot that contains a button however, only the button's onclickevent is handled, and not that of my clickblocker. It should be the other way around.
This leads me to think it's a z-order problem (but not 100% sure).
Unfortunately I'm trying to target older versions, which don't have support for view.setZ(), and view.bringToFront() doesn't appear to do what I want it to do.
Here's the code for the viewblocker:
public class ClickBlockerView extends View{
public ClickBlockerView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(C.GetWindowWidth(getContext()), C.GetWindowHeight(getContext()));
}
public static ClickBlockerView CreateClickBlocker(Context context){
ClickBlockerView c = new ClickBlockerView(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
c.setLayoutParams(params);
c.setId(R.id.clickBlocker);
c.setClickable(true);
return c;
}
}
And this is how I'm calling it (from inside another view):
private void createMenuAndClickblocker(){
ClickBlockerView clickblocker = ClickBlockerView.CreateClickBlocker(getContext());
clickblocker.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
destroyMenu();
}
});
((RelativeLayout) this.getParent()).addView(clickblocker);
clickblocker.bringToFront();
createMenu();
requestLayout();
}
Does anyone have some idea how to fix this? Other solutions to the problem are welcome too. I'd rather not have to use xml though (it would have to be added to every activity)
Update:
Apparently, the z-ordering goes fine with spinners and checkboxes, but not with buttons and my custom views. Odd...
Update 2:
When drawn, the shape is shown to correctly fill up the screen, but it is also drawn below the other custom views, even though it is created later and brought to the front.
Strangely enough, the click functionality has meanwhile completely stopped functioning, even though I didn't change anything in the code for this clickblocker.
I am developing an android application where I stuck at some point. The problem is that I want to track the last action performed in app by tracking onClickListner. So is there any way to set OnclickListner for whole application and then track the last event time. Please Suggest me the way to do that. My assumption is to have a class which extends View class and this class should implement onClickListner. Then all of my buttons should set OnClickListner to Object of this class. but my application have more than 100 buttons so it will increase the complexity of the class. one more problem is that all buttons are performing their activity specific operations.doing all operations from one class will increase complexity.
I am looking to capture onclicklistner throughout the app and then log the event time then transfer the event to the activity where onclickListner was implemented.
An idea might be to create your own OnClickListener, say
class LoggingOnClickListener implements OnClickListener {
public void onClick(View view) {
doLog();
}
}
Now you just have to add super.onClick(view) to add logging to the Button clicks
button.setOnClickListener(new LoggingOnClickListener() {
public void onClick(Button button) {
//handle the click
super.onClick(button);
}
}
The code might very well be flawed as I do not have my IDE open, but should just show the general idea.
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.
I have got an activity where the user can enter host name, user name and password and then click on a "Verify credentials" button. Then the credentials will be checked, which will take some time. In the meantime the user should neither be able to change the credentials nor to click on "Verify" again. So, a modal dialog like the ProgressDialog seems perfect for this.
Unfortunately, ProgressDialog has the well-know limitations regarding orientation changes etc. The guide (UI/Dialogs) tells to avoid ProgressDialog at all and use a ProgressBar in the layout instead (like in Progress & Activity). What does this mean? Shall I create another activity with just one progress bar? Or disable all input fields and put a progress bar on top of it? Sounds quite weird to me... whats your preferred solution?
Best thing which I use is:
Put a ProgressBar just beside the Login Button.
I have put a progressbar beside it(Whose visibility is set to View.GONE) in the OnCreate method.
When the user clicks on the Login/Submit button, I set the visibility of the button to View.GONE and visibility of ProgressBar to View.VISIBLE.
It looks good and the user cannot click on the button until the work is done, If an error occurs, toggle the visibility to let the user try again
Like #micro.pravi mentioned in his answer, you can implement the ProgressBar inside your layout. To keep the state after an orientation change you have to use onSaveInstanceState and onRestoreInstanceState to save and restore important values, i.e. private variables, like the private boolean isChecking
public class MyActivity extends Activity {
public boolean isProcessing;
#Override
public void onCreate(Bundle stateBundle) {
super.onCreate(stateBundle);
// Set Layout
setContentView(R.layout.main);
if(stateBundle!=null) {
// read your data here from the bundle
isProcessing = stateBundle.getBoolean("isProcessing");
}
setUiState(isChecking);
}
#Override
protected void onRestoreInstanceState(Bundle stateBundle) {
// Second value of getBoolean is the default value
isProcessing = stateBundle.getBoolean("isProcessing", false);
super.onRestoreInstanceState(stateBundle);
}
#Override
protected void onSaveInstanceState(Bundle stateBundle) {
// Save the critical data
stateBundle.putString("isProcessing", isProcessing);
super.onSaveInstanceState(stateBundle);
}
#Override
protected onResume() {
setUiState(isProcessing);
}
private setUiState(boolean processing) {
textView.setEnabled(!processing);
button.setEnabled(!processing);
progressbar.setVisibility(processing?View.VISIBLE:View.GONE);
}
}
This should be used to saved any critical data on orientation change or when the App is being killed and later restored by the OS. You don't have to save your TextView data, as the defautl View elements already handle this by themselves. Also do not store Image data this way. Instead store the Uri or path to the Url and load it on restore
For temporarily solving your problem, you can continue using the Progress Dialog and put this line in your Login Activity's tag in Manifest.xml file :
android:configChanges="orientation|keyboardHidden|screenSize"
Using this line of code will not affect the Progress Dialog on orientation changes. But it is considered a wrong practice according to Android Development's Documentation.
In the long run, i recommend you to Preserve the states for orientation changes.
My list view item has 3 or 4 buttons and I am calling a web service with each button, which I am doing by using asynch task, now my questions is that I want to show button clicked by changing background of button according to the result of web service call.
Can someone please tell me how to do it?
Try this out
Pass the reference of the button you clicked(view Obtained
from its onClickListener) to the asyncTask you are about to execute
Start the asyncTask
In the Post execute, change the background of the view.
You can make the changes to your button's setBacgroundColor() method in the onPostExecute() method in the AsyncTask.
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//Do what ever you want depending on the result that you
//you pass in the return of the doInBackGround....
button.setBackGroundColor(Color.GREEN);
}