In an app Im working on I have a class that extends a surface view and another that handles all calculations to figure out where and when objects should be drawn onscreen. Right now I have a sort of hacky way of registering screen clicks where a list of objects is parsed through on each click and the closest object takes the click. This works when there is only 3 or 4 objects onscreen but when I have more the clicks register for the wrong objects.
What Im trying to do is to make the onscreen objects extend the button class so I can just pass a MotionEvent to them when they are clicked. But because of the way that the classes I have are set up its a bit confusing to me at the moment on how this could be done.
Does anybody possible know of any tutorials that deal with extending the button class to use with moving onscreen objects?
If I understand correctly, you're trying to determine which object drawn to the screen has been clicked?
I know this isn't exactly what you asked for but when I've implemented a custom view the past, I've typically handled click detection like this:
I get the x and y coordinates of the objects that you want to be clickable. In your onTouchEvent(MotionEvent event) method within your SurfaceView class, have some if statement that checks whether the x and y of the click is within the bounds of your object.
Here's some code to better illustrate what I'm saying:
#Override
public boolean onTouchEvent(MotionEvent event)
{
// If the user touches the space occupied by object1
if(event.getAction() == MotionEvent.ACTION_DOWN
&& event.getX() <= object1.xPosition + object1.width
&& event.getX() >= object1.xPosition
&& event.getY() >= object1.yPosition
&& event.getY() < object1.yPosition + object1.height)
{
// The click was in the bounds of object1's current location
object1.doSomething();
}
// ......
}
Hopefully this makes sense and is somewhat helpful.
I think you kind of mixing stuff. Button is usually used in layout (the xml layout stuff). When you use surface view you (most likely) need to implement your own "button".
However, it is probably possible to just overlay a frameview on top of your surface view and place the button on that view.
Related
I am developing a puzzle game like find differences on images in Android (Java).
So how can i know, where user touched on image, and is it right place where user touched.
make some CustomView extends View and override onTouchEvent method. or handle all touch events in Activity by overriding dispatchTouchEvent. you can obtain precise point of touch/action with getX() and getY() methods of MotionEvent (which is an object passed to both methods mentioned above), now its your turn to do some math and calculate which item has been touched (by default Activity is dispatching touch events to its layout e.g. inflated from XML)
My (OpenGL ES 2.0) app has a splashscreen which is basically an Android View displayed over my GLSurfaceView.
I do all my initial setup on an AsyncTask and then (out of necessity), load my bitmaps/textures on the GLRendering thread in onSurfaceCreated. Once everything has loaded, I dismiss my splashscreen.
Everything works as expected apart from one thing. The splashscreen still accepts input and if the screen is touched just after the app is launched, I (obviously) get an null pointer exception.
I simply create my view like so:
splashscreen = new SplashScreen(getApplication(), width, height); //Where SplashScreen is a custom class that extends View
I then add it to my layout like so:
layout.add(myView); //My GLSurfaceView
layout.add(splashscreen); //The splashscreen View
setContectView(layout);
Once everything has loaded, I simply remove the (splashscreen) View to reveal my GLSurfaceView underneath:
layout.removeView(splashscreen);
splashscreen=null; //Null it
currently, in my onTouch method, to get around the issue, I have put a check in place like so:
public boolean onTouchEvent(MotionEvent event) {
if(splashscreen==null){
//Do touch related stuff here
}
return true;
}
This does work, however, I'm sure it's not the cleanest way to achieve what I'm after.
I've tried this:
splashscreensetClickable(false);
and
layout.setClickable(false);
as well as setEnabled(false)
Nothing seems to work, but I'm sure there must be a way of doing this.......
Generally, you will want the splash screen to prevent the user from doing anything while it is present. You can actually do this, because views in android, as in other UI frameworks, have a hierarchy in which touch events cascade.
Even though you don't want the splash screen to be interactive, you can still steal all of the touch events that occur on it, and just do nothing with them. The answer itself is to override onTouchEvent in your SplashScreen class with:
#Override
public boolean onTouchEvent(MotionEvent event) {
return true; // Splash screen is consuming all touch events on it.
}
Returning true in this basically says that nothing under this view should receive a touch event. As long as it is visible and over top of the surface view, your surface view will not get any touch events. See here for details.
My problem concerns onTouch. As far as I can tell, there is no way to detect an ACTION_DOWN for one view, and than detect the ACTION_UP for another view at the same onTouch event or swipe, as every onTouch event is linked to one view.
I have a view (A) with some graphics, and on EVENT_DOWN the coordinates are detected and make a "popup" that consists of a view (B) that ownes some more views ("buttons"). B's position and size may vary form time to time. I would prefer to detect ACTION_UP on one of B's children (the "buttons").
I guess using onInterceptTouchEvent is no good. After all, B is not A's parent. Its the other way around.
Using androids drag-and-drop functionality seems a bit too much. Looks like it's intended for actually dragging graphics and transfering data. Dragging invisible graphics around to detect the finger leaving the screen is not very elegant.
Another way would be detecting B's children's positions (and size), every time the popup is shown, but that is not very smooth either.
What is the best way to detect a view A's ACTION_DOWN, and then its child B's (or it's childrens) ACTION_UP?
Or are there other ways to detect these events?
I did struggle with something very similar for a day or two, and I finally concluded that as far as I know onInterceptTouchEvent is the only way to go. I just created a container view 'C' for A and B, and then when A received an ACTION_DOWN, I instructed 'C' to intercept all further events in the swipe, test the coordinates against B's known location, and then forward the event to 'B' through a custom method if the ACTION_UP tested positive against B's bounds (be careful manually passing MotionEvents from one class to another, as the coordinates will be all wrong).
Not a very satisfying solution, but it was the only thing I could think of to do.
Also just in case you're using it, android 3.0+ has some drag/drop helper methods which I'm sure are very helpful, though I was developing for 2.x so they were useless to me.
i have a game, consisting of 7 buttons , arranged such that 1 button is in the center and rest 6 around it.
click on the buttons results in change in textview. using click can really be cumbersome for the user, therefore i would like to add functionality of dragging finger over buttons to perform onclick ..something similar to boggle type of games like -> https://market.android.com/details?id=com.ant.wordfind.client&feature=search_result
i have tried to implement the same ,problem is when i drag of finger only one button gets registered , even if i press other buttons by dragging cursor -> other button touch are just ignored.given the
following code.
public boolean onTouch(View v, MotionEvent arg1)
{
if(arg1.getAction() ==MotionEvent.ACTION_MOVE)
{
Button b;
switch (v.getId())
{
case R.id.b1:
case R.id.b2:
case R.id.b3:
case R.id.b4:
case R.id.b5:
case R.id.b6:
case R.id.b7:
b = (Button)findViewById(v.getId());
b.performClick();
break;
}
return true;
}
am i missing somethng ? wht i want is whn buttons are touched ..they perform onclick functionality.once one button click is registered rest touches are ignored
any help would be appreciated .
i dont want something like piano/soundboard where there is continuous click of button ..but just one click as i drag finger over the button
thanks !
At onTouch(), you shouldn't always use return true. Return false if you want the subsequent actions to be captured.
onTouch() - This returns a boolean to indicate whether your listener consumes this event. The important thing is that this event can have multiple actions that follow each other. So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event.
Ref: http://developer.android.com/guide/topics/ui/ui-events.html
In pure Java there is MouseInputListener which I can use to work with those 2 events.
How do I do it with Android?
If I implement both events then only one is fired (onClickListener) and not the other.
Updated:
The question is not about detecting the finger movement.
I have a View (ImageView for example). I need to detect the click on this view which is onClickListener() and finger movement on this view (i.e. press, move then release the finger).
The problem here is that only onClickListener() is called and MotionEvent handler is not caught.
I need to be able to differentiate those 2 events as the main event should be finger movement and onClickListener() should just say "Don't click this view. Spin this view."
Hopefully this is more clear.
OnClickListener and OnTouchListener kinda obstruct each other, since they both consume the MotionEvents that get caught on the View.
Basically you can write a single OnTouchListener that checks for both things. You'll get supplied with the MotionEvent as an argument. Check it's action via MotionEvent.getAction(), e.g. if it equals MotionEvent.ACTION_DOWN (the user put the finger on the display). If the user releases the finger at approx. the same position (ACTION_UP), you may want to interpret that as a click. Otherwise interpret the positions that you get with the ACTION_MOVE event as a gesture.
But the framework already has some classes that do this interpreting work for you, check out the SimpleGestureDetector class and it's SimpleOnGestureListener. That has some callbacks for common events, e.g. onSingleTapConfirmed() and onFling(). All you need to do is supply the MotionEvents from your OnTouchListener to the GestureDetector.