I'm currently trying to build an Android app with Xamarin Studio (aka monodroid). My problem is as follows:
In my Activity's OnCreate I call
this.RequestWindowFeature(WindowFeatures.ActionBar);
this.RequestWindowFeature(WindowFeatures.ActionModeOverlay);
Also, I added this override to the Activity:
public override Boolean OnTouchEvent(MotionEvent e)
{
if (this.ActionBar.IsShowing)
{
this.ActionBar.Hide();
}
else
{
this.ActionBar.Show();
}
return base.OnTouchEvent(e);
}
This, however, doesn't work as I expect it to: When I first tap on the Activity, the bar is hidden. The next tap shows it, but it doesn't even fully slide into view before it retreats again. Also, it seems to "cram" the contents of the Activity, which it shouldn't do since I added WindowFeatures.ActionModeOverlay.
What am I missing?
EDIT:
I am certain that the method itself is only triggered once per touch (I logged a counter to diagnose).
Also, I don't show()/hide() the ActionBar anywhere else.
EDIT 2: I was certain, but probably messed up the diagnostic approach. :/
After adding
if (e.Action == MotionEventActions.Cancel
|| e.Action == MotionEventActions.Up)
{
return base.OnTouchEvent(e);
}
it behaves as expected.
Motion Event is catching an event when you are releasing a touch, you need to filter the event further using e.Action for touch down and release events. I think down is triggering show, and release is hiding it again
Related
I have a certain activity that begins when I tap my smart watch's screen. There is a timer and bunch of stuff that happens, but the process is crucial, so I am handling certain cases or things that might happen that would disturb the flow of things.
So basically, I want to prevent the home button of my watch to exit the app and go to the homescreen while my timer is running. I keep looking this up and most people say to override the onBackPressed method. But this was for the back button, and I I realized the button is a home button not a back button.
frameLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
clicked = clicked + 1;
if (clicked == 2)
{
Toast.makeText(toolandmode.this, "Clicks:" + clicked, Toast.LENGTH_SHORT).show();
startTimer();
}
else if (clicked >= 4)
{
Toast.makeText(toolandmode.this, "Clicks:" + clicked, Toast.LENGTH_SHORT).show();
AlertMessage();
}
}
return true;
}
});
this is the main method I use
Just override the onBackPressed function.
#Override
public void onBackPressed ()
{
//Control the flow
}
Use third part library in case if it solves your problem.
Here is the link:
https://github.com/shaobin0604/Android-HomeKey-Locker
The general consensus is that you can't override the home button behavior on a Wear OS device, just like you can't override the home button on an Android phone. This is by design to prevent developers from preventing the user to leave an application. Even if there is a hacky way to do it, this is not officially supported and may stop working at any time in future OS versions. I highly suggest not doing it since it goes against the basic navigation model of the device.
More details, and some workarounds for common use cases where people think they need to override the home button can be found in this blog post.
I have Actors that I need to move when the keyboard becomes visible (When I press a TextField), or they are stuck behind it. I do this by moving the camera up:
stage.getViewport().getCamera().position.set(stage.getWidth()/2, stage.getHeight()/3, 0);
stage.getViewport().getCamera().update();
This works fine. It also works fine to move it back when I touch something outside the TextField and call stage.unfocusAll();
My problem is, when I'm in a TextField and press Androids Back button, it hides the keyboard, but does not call the code I have inside the Inputprocessor (THIS CODE CAPTURES BACK-BUTTON ALWAYS EXCEPT WHEN INSIDE A TEXTFIELD AND KEYBOARD IS VISIBLE):
InputProcessor backProcessor = new InputAdapter() {
#Override
public boolean keyDown(int keycode) {
if ((keycode == Input.Keys.ESCAPE) || (keycode == Input.Keys.BACK) )
{
moveBack();
}
return false;
}
};
I looked around and read that it is not possible to catch the back-button when inside a TextField. Which leads me to my questions:
This must be a common scenario (moving UI to work with keyboard), how do other people do it?
If other people do like me (move camera), how do you handle the Android back-button?
EDIT: This answer captures the back-key while inside a TextField, however it has to be done in the Android Launcher, so I can't reach the elements I need to reach. I also overwrites all other calls to the BACK-button from inside the LibGdx project.
Ok so with the help of This I got a solution working, but it's not very pretty.
Basically I rewrite my GDX Launcher class, and use the following code as the layout:
RelativeLayout layout = new RelativeLayout(this) {
#Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
if(event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if(event.getAction() == KeyEvent.ACTION_DOWN){
game.setMoveBack(true); }
}
return super.dispatchKeyEventPreIme(event);
}
};
Then, in the render-method of my MainScreen (Screen that all other Screens inherit from), inside the render-method I call:
if(game.isMoveBack()){
stage.getViewport().getCamera().position.set(stage.getWidth()/2, stage.getHeight()/2, 0);
stage.getViewport().getCamera().update();
game.setMoveBack(false);
}
If anyone has an easier way to do this please post and Ill accept that as an answer, but for now, this works if anyone finds themselves where I am :)
I am unsure if this is a general Andorid or a Xamarin-specific question. I have an Activity with separate layouts for landscape and portrait configuration. The portrait layout has a widget that should be animated after the OK button is pressed, but the landscape view does not have this widget.
In my activity, the event handler for the OK button has the event handler
private void handleOkEvent() {
if (isLandscapeMode()) {
return;
}
Widget.StartAnimation();
...
}
...and I also have the following supporting code:
private bool isLandscapeMode() {
return WindowManager.DefaultDisplay.Rotation == SurfaceOrientation.Rotation90
|| WindowManager.DefaultDisplay.Rotation == SurfaceOrientation.Rotation270;
}
private ImageView Widget
{
get
{
return FindViewById<ImageView>(Resource.Id.widget);
}
}
However, this creates a narrow error situation. If the user is in landscape mode, hits OK and immediately flips to portrait mode, isLandscapeMode returns false but the Widget property returns null since the Widget has not yet been created (we are not fully in portrait mode yet, but isLandscapeMode says we are). Hence Widget.StartAnimation() causes a NullReferenceException.
I can easily check whether the Widget property returns null, but this seems like a hack and would be painful for landscape & portrait layouts that have greater differences than in this example. Am I using the Android Activity correctly here, or is there a more elegant way of doing this?
Or option B, does this appear to be a Xamarin-specific issue that would not be a problem on vanilla Android?
FindViewById will return null, if SetContentView doesn't called.
Activity.OnCreate and Button click events is invoked in UI Thread.
So, handleOkEvent is invoked before Activity.OnCreate and FindViewById can't find your View.
I am writing an very simple application with following scenario:
1) Screen A have 3 button to move on other screen's.
2) Now if I hold one button(say Button 1) and perform rapid click on other button then it launch multiple instance of other screen. Which I think should not be happened. How can prevent this.
3) and it's more weird. After move on other screen if I don't release Button 1 which was on Screen A then it still allow to perform click for rest of two button of screen A even I can see second screen.
Here it's clear launch second screen but still first screen button event working.
Any idea how can avoid such scenario.
How you are going to disable other buttons while having 1 enabled, that's an algorhytmic problem. You can try creating a boolean or control variable in your activity (and then pass the final reference of the activity to wherever you need it), or in a static context. But to answer the title of the question - you can "Cancel Touch Event" either by adding an OnTouchListener, or if you're extending class Button, you can override onTouchEvent(MotionEvent ev) method.
Using OnTouchListener will disable any previously defined touch-event behavior. You can call the actual click event from the inside by calling performClick method from your button.
//in order to use button inside OnTouchEvent, its reference must be final
//if it's not, create a new final reference to your button, like this:
final finalButton = button;
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouchEvent(MotionEvent ev) {
// ... additional code if necessary
if(canBeClicked) {
finalButton.performClick();
return true;
}
else return false;
}
}
Overriding onTouchEvent in a class extending Button should look something like this.
#Override
public boolean onTouchEvent(MotionEvent ev) {
// ... additional code if necessary
//here we don't really need to call performClick(), although API recommends it
//we just send the touch event to the super-class and let it handle the situation.
if(activity.canBeClicked) return super.onTouchEvent(ev);
else return false;
}
One solution that I found is to disable click listener in onPause() and enable it in onResume() . Can we have better support for this?
I am developing an app which will run firstly on Android. However, I have an issue with back button: each time it is tapped the application quits. I don't want this behaviour. I have checked a lot of approaches and I've tried to implement some code but nothing worked.
Here is my code:
Item {
id: student_home_page;
focus: true
// ///////////////////////////////////////////////////////////////
Keys.onReleased: {
console.log("TEST for Back ");
if (event.key == Qt.Key_Back) {
console.log("BAck Button HAndled");
event.accepted = true;
}
}
}
When I click back button after reaching this page, it does not print anything on console as it is not going inside
I only get this message on console of Qt Creator:
/uniActivity(15431): onStop
I/AndroidRuntime(15431): VM exiting with result code 0, cleanup skipped.
Any idea why it is not handling this key event or not any at all inside?
You should handle the back button inside the StackView itself, not a child page, see my answer here
Maybe this could be useful for you. Try to override the activity onBackPressed() method:
#Override
public void onBackPressed() {
// Do something or call finish()
}