onTouch 和 onClick 没有正确触发

onTouch and onClick not triggering properly

我有 ReltiveLayout 和 ImageView 以及里面的 TextView。

所以我有两个事件监听器:

我正在使用 9patch 作为图像。当我使用 onTouch 事件时,onClick 根本没有触发,而且 onTouch 也不能很好地工作。如果我禁用 onTouch 并保留 onClick,它会触发并更改 Activity。我想让 onTouch 和 onClick 一起工作。我要:

这是我的代码:

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);

    }
});

还有我的 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;
        }
    }
}

这是我的布局

<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>

我知道我不善于解释,所以这是一个视频: https://www.youtube.com/watch?v=PtdUsW-Dnqk

更新: 因为您不能在单个视图上使用多个侦听器 see link。 您可以在 TouchButton.class.

中实现 .setOnClickListener 的行为
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;
    }
  }
}

是的,您可以在单个视图上使用多个侦听器(如果不可能,那就会有问题)。

基本上,您视图的触摸事件在点击事件之前被触发。 如果触摸侦听器消耗事件(return来自onTouch 的 为真,则不会调用点击侦听器。 如果您从 onTouch 侦听器 return true,那么您 不会使用 事件(returning false)并且任何底层侦听器都将像 onClick 侦听器一样被调用。

这里有两个侦听器附加到单个视图(一个按钮)的示例:

    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();
        }
    });

和布局,一个简单的按钮:

<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>

在日志中,当您触摸按钮时,您会看到 TOUCH EVENT 在 CLICK EVENT 之前写入,因为 onTouch 侦听器不使用该事件(returns false)并首先被调用。

我建议您阅读 Android 中有关触摸传播的文档,并查看 Dave Smith 关于此主题的有用 video

最后,您应该查看 xml 中的小部件状态,以便在单击或聚焦时更改它们的外观,...查看 there

希望对您有所帮助。

这是我的代码,希望能解决你的问题 ` public boolean onTouch(View v, MotionEvent 事件) {

                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) {

    }`

刚设置

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

您的 touchListenerclickListener 都可以正常工作