These are the FAB dimensions following google specs.
In my application case I need a click listener which is fired by clicking in the FAB's circle only, avoiding clicks inside the square container (56x56).
I was already thinking about get X,Y in each onClick event in my "entire" button and then verify if it's inside my Fab's circle, but i would like to escape from this workaround because it could cause accuracy-click problems with different devices resolutions.
Do you have any idea for an alternative solution?
Thanks in advance.
EDIT:
I've actually implemented this javascript-solution translated in Java
LINK
Do you think i will always get the same accuracy on device screen changes?
I don't think there is a way to actually make a clickable area other than rectangular.
You should make your floating button have a width and height set to wrap_content if your circle is an image. Any way you should set it's width and height to match the diameter of the circle. And process the event like this:
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
float radius = layoutParams.width / 2f;
float x = event.getX() - radius;
float y = event.getY() - radius;
if (isInCircle(radius, x, y)) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// perform your action
}
return true;
} else {
return false;
}
}
private boolean isInCircle(float radius, float x, float y) {
if (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) < radius) {
//touch was performed inside the circle;
return true;
} else {
//touched ouside the circle
return false;
}
}
}
);
This will work on any device, as long as your button is tightly wrapped around your drawn circle.
If you don't need the touch event falling deeper, under your floating button when you miss the circle, you can avoid some redundant calculations like this:
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
float radius = layoutParams.width / 2f;
float x = event.getX() - radius;
float y = event.getY() - radius;
if (isInCircle(radius, x, y)) {
// perform your action
}
}
return true;
}
private boolean isInCircle(float radius, float x, float y) {
if (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) < radius) {
//touch was performed inside the circle;
return true;
} else {
//touched ouside the circle
return false;
}
}
}
);
Keep in mind that for this to work your button should be strictly rectangular. if you want a button to be an ellipse the math should be different.
Related
I am doing an activity, in which there will be a View in a center.
Here is how will it work. When I will be dragging my finger randomly across the screen, this view should make action only when my finger is in bounds of this view.
My code(not correct just want to know if my thinking is correct):
firstlayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
if ( (firstlayout.getLeft() <= x <= firstlayout.getRight()) &&
(firstlayout.getTop() <= y <= firstlayout.getBottom())
)
{
Log.i("A", "Motion Event is currently above firstlayout");
firstlayout.dispatchTouchEvent(event);
}
return true;
}
return false;
}
});
There is an error: Operator <= cannot be applied to 'boolean','int'
Please write some code example if you could
Any help will be appreciated
This is not valid Java:
firstlayout.getLeft() <= x <= firstlayout.getRight()
Instead, you must do
(firstlayout.getLeft() <= x) && (x <= firstlayout.getRight())
Additionally, your view can only receive touch events when that touch occurs within the bounds of the view. There is no need for you to manually check the bounds.
I'm trying to develop an android application similar to "on color measurement" or "color grab" which are already on google play.
I have problem with getting the exact position of a view (which acts like focus square) and move it to the position where the user touches the screen. I have done a lot of searches but all of them ended in onTouchEvent() which I used it but it does not work properly or maybe I have done something wrong.
Actually the view moves but it won't be placed exactly where the user touch, it will go below the touched area in y axis with a distance.
here is my code where the mFocusRectangle is the custom view which I want to move to the touched position:
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if (event.getPointerCount() > 1) {
// handle multi-touch events
} else {
// handle single touch events
if(action==MotionEvent.ACTION_DOWN){
}
if (action == MotionEvent.ACTION_UP) {
int pointerId = event.getPointerId(0);
int pointerIndex = event.findPointerIndex(pointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
mFocusRectangle.showStart();
mFocusRectangle.setX(x);
mFocusRectangle.setY(y);
}
}
return true;
}
I have also tried MotionEvent.ACTION_DOWN but the result is the same.
Thanks in advance.
try this
float x = event.getX(pointerIndex) - (mFocusRectangle.getWidth() / 2);
float y = event.getY(pointerIndex) - (mFocusRectangle.getHeight() / 2);
credits:
Manitoba - Android move view on touch event
I need to do a rotate animation on a RelativeLayout, I've used NineOldAndroid library for animation:
View v = findViewById(R.id.wrap_btnSelect);
ObjectAnimator t1 = ObjectAnimator.ofFloat(
v, "rotation", 0.0f, -45.0f);
t1.setStartDelay(500);
t1.setDuration(1500);
t1.start();
The animation works fine, also click posions are updated accordingly on ICS, but on Gingerbread click positions stays at old position which makes view un-clickable.
is there anything i can do to fix this issue on android 2.3 ?
Original Layout:
Trying to achieve this:
EDIT: This layout is constructed of 4 squares, each is a TextView.
You can extend View to handle touch events yourself, and tell in which area you are clicking, depending on your value of rotation at the moment of the click.
Something like this:
public class WrapBtnSelect extends RelativeLayout {
// Copy onstructors here
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
double x = (event.getX() / getWidth()) * 2 - 1;
double y = (event.getY() / getHeight()) * 2 - 1;
double angle = Math.atan2(y, x);
// Do your actions depending on the angle here
return true;
}
return super.onTouchEvent(event);
}
}
i'm using a SemiClosedSlidingDrawer (http://pastebin.com/FtVyrcEb) and i've added on content part some buttons on the top of slider which are always visibles.
The problems is that they are clickable (or click event is dispatched) only when slider is fully opened... When slider is "semi-opened" click event not seems dispached to button... I have inspected with debugger into onInterceptTouchEvent() and in both cases (opened/semi-collapsed) the following code
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mLocked) {
return false;
}
final int action = event.getAction();
float x = event.getX();
float y = event.getY();
final Rect frame = mFrame;
final View handle = mHandle;
handle.getHitRect(frame);
//FOLLOWING THE CRITICAL CODE
if (!mTracking && !frame.contains((int) x, (int) y)) {
return false;
}
return false but only when slider is opened event was dispached...
It checks if a (x,y) relative to the click are contained in a rectangle created starting from the HandleButton view of sliding drawer...
final Rect frame = mFrame;
final View handle = mHandle;
handle.getHitRect(frame);
and this is obviously false because i'm clicking on a button contained inside the content part of slidingdrawer and that's ok...
As i said above the problem is that in semi-collapsed state, buttons contained in content part are not receiving the event...
Have you any idea how can i solve this issue?
Can be some state of slidingdrawer that avoid to click childs when collapsed?
Thanks in advance...
Right, I think I've figured out a way to do this.
First you need to modify onInterceptTouchEvent() to return true whenever the user presses the visible content during the semi-opened state. So, for instance, if your SemiClosedSlidingDrawer view is located at the very bottom of the screen, you can use a simple detection algorithm, like this:
public boolean onInterceptTouchEvent(MotionEvent event) {
...
handle.getHitRect(frame);
// NEW: Check if the user pressed on the "semi-open" content (below the handle):
if(!mTracking && (y >= frame.bottom) && action == MotionEvent.ACTION_DOWN) {
return true;
}
if (!mTracking && !frame.contains((int) x, (int) y)) {
...
}
Now the touch events during the user's interaction with the semi-opened content will be dispatched to onTouchEvent(). Now we just need to intercept these events and "manually" redirect them to the right view (note that we also need to offset the coordinates for the child view):
public boolean onTouchEvent(MotionEvent event) {
...
if (mTracking) {
...
}
else
{
// NEW: Dispatch events to the "semi-open" view:
final Rect frame = mFrame;
final View handle = mHandle;
handle.getHitRect(frame);
float x = event.getX();
float y = event.getY() - frame.bottom;
MotionEvent newEvent = MotionEvent.obtain(event);
newEvent.setLocation(x, y);
return mContent.dispatchTouchEvent(newEvent);
}
return mTracking || mAnimating || super.onTouchEvent(event);
}
It's a bit of a messy implementation, but I think the basic concept is right. Let me know how it works for you!
I have drawn piechart using canvas method of view , but now i want get click of individual pie ? how can i dot that?
I got perfect answer for this question:
get color code of click area and check if color match with your color code this will get click you want.
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
Logger.debug("X-->"+touchX+" Y---->"+touchY);
//get drawing cache of your view
Bitmap bitmap = getDrawingCache(true);
//Get color code of pixle where you have tap
int colorCode=bitmap.getPixel((int)touchX,(int)touchY);
if(colorCode == context.getResources().getColor(R.color.pie_blue)) {
Logger.debug("Color blue");
onPieClick.onBluePieClick(touchX,touchY);
}else if(colorCode == context.getResources().getColor(R.color.pie_green)) {
Logger.debug("Color green");
onPieClick.onGreenPieClick(touchX,touchY);
}
return super.onTouchEvent(event);
}
What you can do is,
Override onTouch event & You will get Motion event,
You will get x & y co-ordinates of the click by event.getX() &
event.getY() respectively.
identify where this x & y intersect in pie.
Sample code:
1)Simple
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_UP){
float xCord=event.getX();
float yCord = event.getY();
....
Write condition to identify where this x & y intersect in pie.
...
}
return true;
}
2) Another way getting touch (good way)
OnGestureListener mGestureListener=new GestureDetector.SimpleOnGestureListener(){
public boolean onSingleTapConfirmed(MotionEvent e) {
float xCord=e.getX();
float yCord = e.getY();
....
identify where this x & y intersect in pie.
...
};
};
GestureDetector gestureDetector=new GestureDetector(context, mGestureListener);
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return true;
}
You can't. Well, at least not directly.
You could do the following though:
In the click handler for the view, determine the xy coordinates of the click
Compare the drawing code you wrote, thereby determining in which piece of the pie the click was