Getting relative position of a MotionEvent inside a buttonView - android

private void buttonTouch(MotionEvent event, int num) {
Log.v(TAG, num +" Button Click : X" + event.getX() + " Y:" +event.getY());
}
If the red square is a button view and the user clicks on it event.getX() seems to produce values on how the click is relative to the turquoise field or maybe even the whole screen. Is there an easy way how the click is located within the red square?
I see that there are function for getting the height and width of a button but I don't see a function that gives me one of the edges of the box or another way to know the exact location of the button so that I can use that to calculate where the click is relative in the button.

I've tested this code and it gets the coordinates relative to the own view (a Button).
I've added a method to retrieve the width and height of the screen, just to get a global reference.
//Activity
public class TestActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
Button bt_test = (Button) findViewById(R.id.bt_test_1);
bt_test.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
Log.v("TAG_TOUCH", " Button Click: X " + event.getX() + " Y: " + event.getY());
Point point = getSizeScreen();
Log.v("TAG_SIZE_SCREEN", " Width: " + point.x + " Height: " + point.y);
return true;
}
});
Button bt_test_2 = (Button) findViewById(R.id.bt_test_2);
bt_test_2.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
Log.v("TAG_TOUCH", " Button Click: X " + event.getX() + " Y: " + event.getY());
Point point = getSizeScreen();
Log.v("TAG_SIZE_SCREEN", " Width: " + point.x + " Height: " + point.y);
return true;
}
});
}
private Point getSizeScreen() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
}
//Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="#+id/bt_test_1"
android:layout_width="0dp"
android:layout_height="300dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:background="#000000" />
<Button
android:id="#+id/bt_test_2"
android:layout_width="0dp"
android:layout_height="300dp"
android:layout_margin="10dp"
android:layout_weight="1"
android:background="#000000" />
</LinearLayout>

Related

Can't see click ripple effect in Android Touch events

I've seen some solutions here, but none of them works for me. I am using View.OnTouchListener class to detect click and drag events in my app code. But that beautiful ripple effect is now gone (perhaps because I am consuming the MotionEvent gestures before it gets to the View.OnClickListener. Notice the return true in MotionEvent.ACTION_DOWN block).
I cannot use View.OnClickListener to detect click events because my app uses multiple composite gestures (click, click-hold, click-hold-drag, etc). Can anyone please share some pointers on how to create ripple effect with Android touch gestures?
Here is the code snippet for my View.OnTouchListener implementation inside a BaseAdapter class:
v.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent ev) {
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if(mAppActionDownListener != null) {
mAppActionDownListener.onAppActionDown(appObjectList.get(position), v);
}
Log.d("COOK", "ACTION_DOWN: " + ev.getX() + ", " + ev.getY());
t1 = System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
Log.d("COOK", "ACTION_UP: " + ev.getX() + ", " + ev.getY());
t2 = System.currentTimeMillis();
if(Math.abs(t2-t1) <=300) {
//Toast.makeText(context, "Click event", Toast.LENGTH_SHORT).show();
if(mAppClickListener!=null) {
mAppClickListener.onAppClicked(appObjectList.get(position), v);
}
}
return false;
case MotionEvent.ACTION_MOVE:
Log.d("COOK", "ACTION_MOVE: " + ev.getX() + ", " + ev.getY());
ClipData.Item item = new ClipData.Item(appObjectList.get(position).getAppname()+"~"+appObjectList.get(position).getPackagename()+"~"+appObjectList.get(position).getAppicon());
ClipData dragData = new ClipData(
(CharSequence) v.getTag(),
new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN},
item);
v.findViewById(R.id.appicondrawable).startDrag(dragData, // the data to be dragged
new View.DragShadowBuilder(v.findViewById(R.id.appicondrawable)), // the drag shadow builder
null, // no need to use local data
0 // flags (not currently used, set to 0)
);
if(mAppDragListener!=null) {
mAppDragListener.onAppDragged(appObjectList.get(position), v);
}
return true;
default:
return false;
}
}
});
Any help would be greatly appreciated!
Update 1:
Just to clarify, setting up background/foreground/clickable attributes in the parent custom layout has no effect for reasons mentioned above. I have already tried those solutions.
Update 2:
Adding the adapter item layout code.:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/applayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:padding="5sp">
<ImageView
android:id="#+id/appicondrawable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:maxWidth="40dp"
android:maxHeight="40dp"
android:scaleType="fitCenter"
android:layout_marginStart="3dp"
android:src="#drawable/ic_launcher_background" />
<TextView
android:id="#+id/appname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:maxLines="1"
android:text="app name"
android:textAlignment="center"
android:textSize="10sp"
android:textColor="#000000" />
</LinearLayout>
I found a way around this. Although the ripple effect is not customisable, the fix is pretty nifty. I manually called the setPressed() method on View inside the ACTION_DOWN and ACTION_UP events and now I can see the default Android ripple effect.
case MotionEvent.ACTION_DOWN:
//icon.setColorFilter(Color.argb(80, 0, 0, 0));
v.setPressed(true);
if(mAppActionDownListener != null) {
mAppActionDownListener.onAppActionDown(appObjectList.get(position), v);
}
Log.d("COOK", "ACTION_DOWN: " + ev.getX() + ", " + ev.getY());
t1 = System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
v.setPressed(false);
Log.d("COOK", "ACTION_UP: " + ev.getX() + ", " + ev.getY());
t2 = System.currentTimeMillis();
if(Math.abs(t2-t1) <=300) {
//Toast.makeText(context, "Click event", Toast.LENGTH_SHORT).show();
if(mAppClickListener!=null) {
mAppClickListener.onAppClicked(appObjectList.get(position), v);
}
}
You need custom background or foreground to the layout.
Create a file named res/drawable/ripple_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="#android:id/mask"><color android:color="#dcffffff"/></item>
</ripple>
Then, use it as background:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/applayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/ripple_selector"
android:focusable="true"
android:clickable="true"
android:padding="5sp">
...
</LinearLayout>
If does not work, try using it as foreground:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/applayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:foreground="#drawable/ripple_selector"
android:focusable="true"
android:clickable="true"
android:padding="5sp">
...
</LinearLayout>
to add a ripple effect to your view, you can add ?attr/selectableItemBackground as view's background.
<ImageView
android:height="100dp"
android:width="100dp"
android:src="#drawable/crush"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true" />

How do I get the coordinates of an image same on all devices?

I tried out all the possible solutions but they are not working for me .
I have an ImageView with an image. I am able to get the coordinates on touch of the image, but when I click on same point of the Image in different resolution device the the coordinates are different.
I want that the coordinates must be the same on all devices , So that i am able to get the exact point where the image is touched .
My current code is:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView=(ImageView)findViewById(R.id.imageView);
final TextView coordinateText=(TextView)findViewById(R.id.coordinateText);
imageView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
String text = " x = " + motionEvent.getX() + " and y = " + motionEvent.getY();
// Log.d("Tag", "X,Y : " + motionEvent.getX() + "," + motionEvent.getY());
coordinateText.setText(text);
return true;
}
});
}
activity_main.xml is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="saleskit.orbitsys.com.damagemarkingdemo.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/coordinateText"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:src="#drawable/superb_dm_left_v01"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

Android onTouch and coordinates

I have this XML wherein I have a Relative layout and a button
XML Code:
<RelativeLayout
android:layout_width="500dp"
android:layout_height="250dp"
>
<Button
android:id="#+id/triggerButton"
android:layout_width="45dp"
android:layout_height="45dp"
android:background="#color/colorAccent"
android:layout_marginTop="94dp"
android:layout_alignParentTop="true"
android:layout_weight="0.5"
android:keepScreenOn="false" />
<RelativeLayout
android:layout_width="500dp"
android:layout_height="250dp"
android:id="#+id/relativeLayout_Touch"
android:background="#android:color/holo_green_light"
android:elevation="2dp">
</RelativeLayout>
Also, I have this code to get the coordinates of the onClick and a code to get the coordinates of the button.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
point.x = event.getX();
point.y = event.getY();
String message = point.x + " " + point.y
int[] test = new int[2];
btTrigger.getLocationOnScreen(test);
String message2 = "X: " + test[0] + "," + "Y: " + test[1];
Log.e("COORDINATE", message);
Log.e("BUTTON COORDINATE", message2);
}
invalidate();
return true;
}
How can I check if I clicked the position of the button, without clicking the button itself. (which I can't click because the RelativeLayout is infront of the button.)
It needs to be in front of the button because whenever the user clicks the relativelayout will have a red circle.
canvas.drawCircle(point.x, point.y, 100, paint);
I have 2 options in my mind, tho idk if it's possible:
Increase the size of the click to adjust to the button size?
Or try to merge(?) the button and the relativelayout. (Whenever i click the button the drawing of circle will still appear.

Android ScrollView height not changing

I have a layout with the following XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="#+id/myScrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:id="#+id/myEditLinearLayout"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<EditText
android:id="#+id/myEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:maxLines="300"
android:scrollHorizontally="false"
android:hint="Type notes here..."
android:inputType="textNoSuggestions|textMultiLine"
android:layout_gravity="center_horizontal|center_vertical"
android:gravity="left"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<RelativeLayout
android:id="#+id/layoutKbd"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<android.inputmethodservice.KeyboardView
android:id="#+id/myKeyboardView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyPreviewLayout ="#layout/kbdpreview"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
The top view is RelativeLayout with a ScrollView for the main content (which contains an EditText) and custom keyboard view. The custom keyboard pops up when the user clicks on the EditText.
It works perfectly for most part, but if the text being entered in the EditText is large, it gets covered by the custom keyboard view. So at that time, I need to adjust the ScrollView's height. I did it in the following manner:
// Activity's onCreate implementation
public void onCreate(Bundle savedInstanceState)
{
...
EditText editText = (EditText) findViewById(R.id.myEditLinearLayout);
editText.addTextChangedListener(m_tw);
...
}
private TextWatcher m_tw = new TextWatcher()
{
#Override
public void afterTextChanged(Editable s)
{
// This function returns if the custom keyboard is visible
if (m_customKeyboard.isCustomKeyboardVisible())
{
int kbdHeight = m_customKeyboard.mKeyboardView.getHeight();
int editTextBottom = m_editText.getBottom();
ScrollView scrollView = (ScrollView) findViewById(R.id.myScrollview);
Rect scrollBounds = new Rect();
Log.d(TAG, "Setting scrollview height = " + (editTextBottom + kbdHeight + 20));
scrollView.getHitRect(scrollBounds);
Log.d(TAG, "Old scroll bounds: left = " + scrollBounds.left + " right = " + scrollBounds.right + " top = " + scrollBounds.top + " bottom = " + scrollBounds.bottom);
scrollView.getLayoutParams().height = editTextBottom + kbdHeight + 20;
Log.d(TAG, "Setting scrollview height = " + (editTextBottom + kbdHeight + 20));
scrollView.getHitRect(scrollBounds);
Log.d(TAG, "New scroll bounds: left = " + scrollBounds.left + " right = " + scrollBounds.right + " top = " + scrollBounds.top + " bottom = " + scrollBounds.bottom);
}
}
};
The above does not work. It shows the same value for scrollBounds.bottom, before and after setting scrollView height.
What am I missing?
Put the property
android:layout_above="#+id/yourKeyboardLayout"
in your scrollview.
You could try putting android:windowSoftInputMode="adjustPan" in your manifest. If you don't like the result, perhaps you can use some other pan.
Add this
android:windowSoftInputMode="adjustPan"
in your manifest where activity is declare and you can also add in scroll view
If you want to change scrollview's LayoutParams, you should use the following code in you example:
ViewGroup.LayoutParams lp = scrollView.getLayoutParams();
lp.height = editTextBottom + kbdHeight + 20;
scrollview.setLayoutParams(lp);

getLocationOnScreen of a child of GridLayout

I'm attempting to get the x/y of an imageview within a GridLayout but my log keeps showing X & Y: 0 0 any ideas?
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/root" >
...
<GridLayout
android:id="#+id/gridLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:columnCount="3"
android:rowCount="5" >
...
<ImageView
android:id="#+id/fivetwo"
android:layout_width="75dp"
android:layout_height="75dp"
android:contentDescription="#string/gameboard"
android:gravity="center"
android:src="#drawable/tile"
android:layout_columnSpan="1"
android:layout_rowSpan="1" />
heres the java:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level);
....
ImageView temp = (ImageView) findViewById(R.id.fivetwo);
int originalPos[] = new int[2];
temp.getLocationOnScreen( originalPos );
Log.i(TAG, "X & Y: " + originalPos[0] + " " + originalPos[1]);
...
Remember:getX() and getY()return 0 if components are not drawn yet (in onCreate(){} ).
To find out the position of a view as soon as it is ready:
Add a tree observer to the layout. This should return the correct position.
onCreate is called before the layout of the child views are done. So the width and height is not calculated yet. To get the height and width. Put this on the onCreate method
final ImageView temp = (ImageView) findViewById(R.id.fivetwo);
ViewTreeObserver vto = temp.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
temp.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int x = temp.getX();
int y = temp.getY();
Log.v(TAG, String.format("X:%d Y:%d",x,y);
}
});
You need to wait for the callback when the layout has placed the children views. The code you are using returns 0 because the position is returned before the layout is placed. Use this code:
temp.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
int[] locations = new int[2];
temp.getLocationOnScreen(locations);
int x = locations[0];
int y = locations[1];
}
});

Categories

Resources