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.
Related
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" />
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>
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>
I would like to implement Word Search app. As part of implementation i have come across canvas and drawing line over grid view cells( letters that form the word) to indicate that user is touching finger over letters to form the word.
I have succeeded partially as of now i can draw a line over letters of grid view but the line is not through center of views of grid View.
Please can anyone assist me with your valuable suggestions .
Have a glance on below screen shot to get a clear idea.
Edited: I'm posting code to get an idea of how I'm implementing it.
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff" >
<RelativeLayout
android:id="#+id/topbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#A9E2F3" >
<LinearLayout
android:id="#+id/topbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#336699"
android:orientation="horizontal" >
<Button
android:id="#+id/btn_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause" />
<Chronometer
android:id="#+id/chronometer1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Chronometer" />
<TextView
android:id="#+id/counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="20sp"
android:typeface="serif" />
</LinearLayout>
</RelativeLayout>
<FrameLayout
android:id="#+id/gridFrame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/wTable"
android:layout_below="#+id/textdisplay" >
<GridView
android:id="#+id/grid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#E7E8E9"
android:fitsSystemWindows="true"
android:gravity="center"
android:horizontalSpacing="10sp"
android:numColumns="10"
android:padding="1dp"
android:stretchMode="columnWidth"
android:verticalSpacing="10sp" >
</GridView>
</FrameLayout>
<GridView
android:id="#+id/wTable"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#fff"
android:numColumns="3"
android:orientation="vertical" />
</RelativeLayout>
The paint is drawing over frame layout which contains grid view. Grid view elements are printed through custom text view file.
To draw a line i have used LineView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
public class LineView extends View {
public static final float LINE_WIDTH = 30.0f;
public Paint paint = new Paint();
protected Context context;
public float startingX, startingY, endingX, endingY;
public LineView(Context context) {
super(context);
this.context = context;
paint.setColor(Color.parseColor("#2E9AFE"));
paint.setStrokeWidth(LINE_WIDTH);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setDither(true);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setAlpha(90);
}
public void setPoints(float startX, float startY, float endX, float endY) {
startingX = startX;
startingY = startY;
endingX = endX;
endingY = endY;
invalidate();
}
#Override
public void onDraw(Canvas canvas) {
Log.e("LINEVIEW", "startingX" + startingX + " startingY:" + startingY);
Log.e("LINEVIEW", "endingX" + endingX + " endingY:" + endingY);
// canvas.drawLine(startingX, startingY, endingX, endingY, paint);
canvas.drawLine(startingX, startingY, endingX, endingY, paint);
}
}
Main Activity where logic is implemented:
Written only the required logic here.
newGrid = (GridView) findViewById(R.id.grid);
newGrid.setAdapter(new FormTheGridLetters());
newGrid.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// if (mp.isPlaying()) {
// mp.stop();
// }
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// data
PaintViewHolder newPaint = new PaintViewHolder();
newPaint.DrawLine = new LineView(WordSearchActivity.this);
gridFrame.addView(newPaint.DrawLine);
buildWord = new StringBuilder();
int x = (int) event.getX();
int y = (int) event.getY();
// test = new LineView(WordSearchActivity.this);
int position = newGrid.pointToPosition(x, y);
Point one,
two;
if (position != GridView.INVALID_POSITION) {
v.getParent().requestDisallowInterceptTouchEvent(true);
cellView = (TextView) newGrid.getChildAt(position);
String a = cellView.getText().toString();
// Log.v(">>>>><<<<<<<????????", a.toString());
switch (action) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
// Checking the list for formed word ;
//if found that is painted
for (int i1 = 0; i1 < Ans.size(); i1++)
{
if (formedWord.equals(Ans.get(i1)))
{
answerAdapter.notifyDataSetChanged();
newPaint.DrawLine.setPoints(startX, startY, x, y);
// Painted the letters by passing starting and ending points
}
}
break;
}
} else {
if (mSelecting) {
mSelecting = false;
}
}
break;
case MotionEvent.ACTION_CANCEL:
mSelecting = false;
break;
}
return true;
}
});
I don't know if you fix the issue but I will answer anyway for the people that may have these kind of problems. After you recieve the valid position, you can get the center of the view and you can set these values as beginning of the draw.
Like this:
if (position != GridView.INVALID_POSITION) {
MyList.add(position);
v.getParent().requestDisallowInterceptTouchEvent(true);
TextView cellView = (TextView) gridView.getChildAt(position);
centreX = cellView.getX() + cellView.getWidth() / 2;
centreY = cellView.getY() + cellView.getHeight() / 2;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
newPaint.DrawLine.touch_start(x, y,centreX,centreY);
I have tried this code and it is working. I don't think that you need anymore but I have joined this site recently so maybe it will help other people. I can post more code if you want but
newPaint.DrawLine.touch_start(x, y,centreX,centreY);
is the trick for that issue.
Hope this helps.
I want to move a view on touch and when the user unholds this view, it is started an animation which moves my view to the end of its parent.
This is my layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/time_view"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<AbsoluteLayout
android:id="#+id/slide_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_margin="20dp"
android:background="#0000FF" >
<View
android:id="#+id/slide_to_pause"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#00FFFF" />
</AbsoluteLayout>
</RelativeLayout>
This is how I set the view to move in my onCreate:
slideView = ((View) findViewById(R.id.slide_to_pause));
slideView.setOnTouchListener(this);
This is how I move the view and starts the animation:
#Override
public boolean onTouch(View view, MotionEvent event) {
AbsoluteLayout.LayoutParams layoutParams = (AbsoluteLayout.LayoutParams) view.getLayoutParams();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mX = event.getRawX();
break;
case MotionEvent.ACTION_UP:
int endOfAnimation = findViewById(R.id.slide_layout).getWidth() - view.getWidth();
mSlideAnimation = new TranslateAnimation(0, endOfAnimation - layoutParams.x, 0, 0);
mSlideAnimation.setDuration(1000);
view.startAnimation(mSlideAnimation);
Log.d(TAG, "endOfAnimation = " + layoutParams.x + " | " + endOfAnimation);
break;
case MotionEvent.ACTION_MOVE:
layoutParams.x = (int) event.getRawX();
view.setLayoutParams(layoutParams);
break;
}
return true;
}
The problem is that when the view arrives at the end it comes back to a point in the midle of the screen, which is the point where the user unholds the view.
How can I fix this?
Thank you!
You need to use
mSlideAnimation.setFillAfter(true);
to make it not revert back to the start.
If that doesn't work you might have to follow the suggestion on Animation.setFillAfter/Before - Do they work/What are they for?
You can simulate animation manually (move views yourself, without animation framework) by using
View.offsetLeftAndRight(int offset)
View.offsetTopAndBottom(int offset)