Reputation: 779
I have ReltiveLayout with and ImageView and a TextView inside.
So I have two event listeners:
onClick
onTouch
I am using 9patch
for the image. When I use the onTouch event onClick is not firing at all and also onTouch is not working very good. If I disable onTouch and leave onClick it fires and changes the Activity. I want to make onTouch and onClick work together. I want:
Heres my code:
StartBtn = (RelativeLayout) findViewById(R.id.StartBtn);
StartBtnImage = (ImageView) findViewById(R.id.StartBtnImage);
StartBtnText = (TextView) findViewById(R.id.StartBtnText);
StartBtn.setOnTouchListener(new TouchButton(StartBtnImage)); //Commenting this line makes the onClickListener work
StartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
StartBtnImage.setImageResource(R.drawable.btn_selected);
Log.d("ButtonClick", "Done");
Intent myIntent = new Intent(MainMenu.this, Game.class);
startActivity(myIntent);
}
});
And my TouchButton class:
public class TouchButton implements View.OnTouchListener {
ImageView IV;
public TouchButton(ImageView Image) {
IV = Image;
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
IV.setImageResource(R.drawable.btn_selected);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
default:
IV.setImageResource(R.drawable.btn);
return false;
}
}
}
Here is my layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainMenu">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/MainMenuBg"
android:background="@drawable/main_menu_bg" />
<RelativeLayout
android:layout_width="250dp"
android:layout_height="75dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="130dp"
android:id="@+id/StartBtn"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/StartBtnImage"
android:src="@drawable/btn" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Start"
android:id="@+id/StartBtnText"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:singleLine="false"
android:gravity="center|center_vertical|center_horizontal"
android:textSize="50dp" />
</RelativeLayout>
I know I'm bad at explaining, so here is a video: https://www.youtube.com/watch?v=PtdUsW-Dnqk
Upvotes: 2
Views: 6365
Reputation: 15
Just set
@Override
public boolean onDown(MotionEvent e) {
return false;
}
Your both touchListener
and clickListener
will work fine
Upvotes: 0
Reputation: 1
Here is my code, I hope this can solve your problem ` public boolean onTouch(View v, MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the
// velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
//getrawX, getrawY
startX = event.getRawX();
startY = event.getRawY();
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
} else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
velocityX = mVelocityTracker.getXVelocity(pointerId);
velocityY = mVelocityTracker.getXVelocity(pointerId);
diffX = event.getRawX() - startX;
diffY = event.getRawY() - startY;
if(Math.abs(diffX)> 10) {
startX = event.getRawX();
if (diffX < 0 && velocityX != 0) {
swipeLeft(diffX, velocityX);
} else {
swipeRight(diffX, velocityX);
}
}
if(Math.abs(diffY)> 10) {
startY = event.getRawY();
if (diffY < 0 && velocityY != 0) {
swipeTop(diffY, velocityY);
} else {
swipeBottom(Math.abs(diffY) / velocityY);
}
}
break;
case MotionEvent.ACTION_UP:
if(distanceX == 0){
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("SET_ID", listSet.get(getAdapterPosition()).getId());
itemView.getContext().startActivity(intent);
break;
}
case MotionEvent.ACTION_CANCEL:
checkDis();
// Return a VelocityTracker object back to be re-used by others.
try {
mVelocityTracker.recycle();
mVelocityTracker = null;
}catch (Exception e){
Log.d("exeption", e.getMessage());
}
break;
}
return true;
}
});
}
// check action up then cancel
//purpose: scroll to initalize status if the behind layout not been opened
private void checkDis(){
if(distanceX<=0 && distanceX > -200){
scrollView(cvSetItem, 0,(long) Math.abs(distanceX)*600/150);
distanceX = 0;
}
}
private void scrollView( View v, float toX, long duration){
// do something
}
private void swipeLeft(float diff, float velo) {
distanceX += diff;
Log.d("distance left", " " + distanceX);
if(distanceX>-200 && distanceX <0) {
scrollView(cvSetItem,distanceX, (long) (diff/velo));
}else {
distanceX = -200;
scrollView(cvSetItem,distanceX, 0);
}
}
private void swipeRight(float diff, float velo) {
Log.d("distance right", " " + distanceX);
distanceX+=diff;
if(distanceX<0){
scrollView(cvSetItem,distanceX, (long) Math.abs(diff/velo));
}else {
distanceX =0;
}
}
private void swipeTop(float diffY, float velo) {
}
private void swipeBottom(float duration) {
}`
Upvotes: 0
Reputation: 76
Yes you can use multiple listeners on a single view (if it was not possible it would have been problematic).
Basically, the touch event of your view is triggered before click event. If the touch listener consumes the event (returning true from onTouch) then the click listener won't be called. If you return true from the onTouch listener, then you don't consume the event (returning false) and any underlying listeners will be called like the onClick listener.
Here an example of two listeners attached to a single view (a button) :
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("stack", "TOUCH EVENT");
return false;
}
});
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("stack", "CLICK EVENT");
Toast.makeText(getApplicationContext(), "start game...", Toast.LENGTH_LONG).show();
}
});
and the layout, a simple button :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start btn"/>
</RelativeLayout>
In the log you will see TOUCH EVENT written before CLICK EVENT when you touch the button because the onTouch listener does not consume the event (returns false) and get called first.
I suggest you to read doc about touch propagation in Android and check this usefull video on this subject by Dave Smith.
Finally You should have a look at widget states in xml for changing apparence of them when they get clicked, or focused, ... Have a look there
Hope it will help.
Upvotes: 4
Reputation: 575
UPDATE: Since you cannot use multiple listener on a single view see link.
You could implement the behavior of your .setOnClickListener
in your TouchButton.class.
public class TouchButton implements View.OnTouchListener {
ImageView IV;
public TouchButton(ImageView Image) {
IV = Image;
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
IV.setImageResource(R.drawable.btn_selected);
return true;
case MotionEvent.ACTION_UP:
switch(v.getId()){
case R.id.StartBtn:
IV.setImageResource(R.drawable.btn_selected);
Log.d("ButtonClick", "Done");
Intent myIntent = new Intent(MainMenu.this, Game.class);
startActivity(myIntent);
break;
return true;
case MotionEvent.ACTION_OUTSIDE:
default:
IV.setImageResource(R.drawable.btn);
return false;
}
}
}
Upvotes: 2