简体   繁体   中英

Android: onTouchListener not working properly

I'm currently working on an app that has a RelativeLayout that has 4 child FrameLayouts , each FrameLayout has a set of ImageViews inside it and the inside View has it's own behavior. I'm trying to implement a drag and drop to the FrameLayouts while implementing the onTouchListener I found in this tutorial . but unfortunately the drag 'n drop doesn't work properly and nothing is happening.

any thoughts on how to implement the drag and drop correctly? what am I missing?


here is the xml code for a single child of the FrameLayouts :

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="80dp" android:layout_height="108dp" > <ImageView android:id="@+id/secondImage" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/back" /> <ImageView android:id="@+id/firstImage" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/c2" /> </FrameLayout> 


here is the xml code for the main.xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/pinecropped" android:orientation="vertical" > <FrameLayout android:id="@+id/cardNumber1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="50dp" android:layout_marginTop="60dp" > <include layout="@layout/card" /> </FrameLayout> <FrameLayout android:id="@+id/cardNumber2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/cardNumber1" android:layout_marginLeft="50dp" android:layout_marginTop="100dp" > <include layout="@layout/card" /> </FrameLayout> <FrameLayout android:id="@+id/cardNumber3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginRight="50dp" android:layout_marginTop="60dp" > <include layout="@layout/card" /> </FrameLayout> <FrameLayout android:id="@+id/cardNumber4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@+id/cardNumber3" android:layout_marginRight="50dp" android:layout_marginTop="100dp" > <include layout="@layout/card" /> </FrameLayout> </RelativeLayout> 


here is the Java code for the single child:

public class FaceUpActivity extends Activity {
    FrameLayout firstCard, secondCard, thirdCard, forthCard;
    Card cardNumber1, cardNumber2, cardNumber3, cardNumber4;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        initUI();
    }

    private void initUI() {
        firstCard = (FrameLayout) findViewById(R.id.cardNumber1);
        secondCard = (FrameLayout) findViewById(R.id.cardNumber2);
        thirdCard = (FrameLayout) findViewById(R.id.cardNumber3);
        forthCard = (FrameLayout) findViewById(R.id.cardNumber4);

        cardNumber1 = new Card(this, firstCard);
        cardNumber2 = new Card(this, secondCard);
        cardNumber3 = new Card(this, thirdCard);
        cardNumber4 = new Card(this, forthCard);

        cardNumber1.setupCards(R.drawable.c2, true);
        cardNumber2.setupCards(R.drawable.d0, true);
        cardNumber3.setupCards(R.drawable.h5, true);
        cardNumber4.setupCards(R.drawable.sj, true);

        firstCard.setOnTouchListener(dragMe);
        secondCard.setOnTouchListener(dragMe);
        thirdCard.setOnTouchListener(dragMe);
        forthCard.setOnTouchListener(dragMe);

    }

    OnTouchListener dragMe = new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            FrameLayout.LayoutParams params = (LayoutParams) v
                    .getLayoutParams();
            int maxWidth = getWindowManager().getDefaultDisplay().getWidth();
            int maxHeight = getWindowManager().getDefaultDisplay().getHeight();
            int topMargin, leftMargin;

            int cond = v.getId();
            if (cond == R.id.cardNumber1 || cond == R.id.cardNumber2
                    || cond == R.id.cardNumber3 || cond == R.id.cardNumber4) {
                switch (event.getAction()) {
                case MotionEvent.ACTION_UP:

                    topMargin = (int) event.getRawY() - (v.getHeight());
                    leftMargin = (int) event.getRawX() - (v.getWidth()) / 2;

                    if (topMargin < 0) {
                        params.topMargin = 0;
                    } else if (topMargin > maxHeight) {
                        params.topMargin = maxHeight - v.getHeight();
                    } else {
                        params.topMargin = topMargin;
                    }

                    if (leftMargin < 0) {
                        params.leftMargin = 0;
                    } else if (leftMargin > maxWidth) {
                        params.leftMargin = maxWidth - (v.getWidth() / 2);
                    } else {
                        params.leftMargin = leftMargin;
                    }

                    v.setLayoutParams(params);

                    break;

                case MotionEvent.ACTION_MOVE:

                    topMargin = (int) event.getRawY() - (v.getHeight());
                    leftMargin = (int) event.getRawX() - (v.getWidth()) / 2;

                    if (topMargin < 0) {
                        params.topMargin = 0;
                    } else if (topMargin > maxHeight) {
                        params.topMargin = maxHeight - v.getHeight();
                    } else {
                        params.topMargin = topMargin;
                    }

                    if (leftMargin < 0) {
                        params.leftMargin = 0;
                    } else if (leftMargin > maxWidth) {
                        params.leftMargin = maxWidth - (v.getWidth() / 2);
                    } else {
                        params.leftMargin = leftMargin;
                    }

                    v.setLayoutParams(params);

                    break;
                }
            }
            return true;
        }
    };
}


this is my main activity Java code:

 public class FaceUpActivity extends Activity { FrameLayout firstCard, secondCard, thirdCard, forthCard; Card cardNumber1, cardNumber2, cardNumber3, cardNumber4; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initUI(); } private void initUI() { firstCard = (FrameLayout) findViewById(R.id.cardNumber1); secondCard = (FrameLayout) findViewById(R.id.cardNumber2); thirdCard = (FrameLayout) findViewById(R.id.cardNumber3); forthCard = (FrameLayout) findViewById(R.id.cardNumber4); cardNumber1 = new Card(this, firstCard); cardNumber2 = new Card(this, secondCard); cardNumber3 = new Card(this, thirdCard); cardNumber4 = new Card(this, forthCard); cardNumber1.setupCards(R.drawable.c2, true); cardNumber2.setupCards(R.drawable.d0, true); cardNumber3.setupCards(R.drawable.h5, true); cardNumber4.setupCards(R.drawable.sj, true); firstCard.setOnTouchListener(dragMe); secondCard.setOnTouchListener(dragMe); thirdCard.setOnTouchListener(dragMe); forthCard.setOnTouchListener(dragMe); } OnTouchListener dragMe = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { FrameLayout.LayoutParams params = (LayoutParams) v .getLayoutParams(); int maxWidth = getWindowManager().getDefaultDisplay().getWidth(); int maxHeight = getWindowManager().getDefaultDisplay().getHeight(); int topMargin, leftMargin; int cond = v.getId(); if (cond == R.id.cardNumber1 || cond == R.id.cardNumber2 || cond == R.id.cardNumber3 || cond == R.id.cardNumber4) { switch (event.getAction()) { case MotionEvent.ACTION_UP: topMargin = (int) event.getRawY() - (v.getHeight()); leftMargin = (int) event.getRawX() - (v.getWidth()) / 2; if (topMargin < 0) { params.topMargin = 0; } else if (topMargin > maxHeight) { params.topMargin = maxHeight - v.getHeight(); } else { params.topMargin = topMargin; } if (leftMargin < 0) { params.leftMargin = 0; } else if (leftMargin > maxWidth) { params.leftMargin = maxWidth - (v.getWidth() / 2); } else { params.leftMargin = leftMargin; } v.setLayoutParams(params); break; case MotionEvent.ACTION_MOVE: topMargin = (int) event.getRawY() - (v.getHeight()); leftMargin = (int) event.getRawX() - (v.getWidth()) / 2; if (topMargin < 0) { params.topMargin = 0; } else if (topMargin > maxHeight) { params.topMargin = maxHeight - v.getHeight(); } else { params.topMargin = topMargin; } if (leftMargin < 0) { params.leftMargin = 0; } else if (leftMargin > maxWidth) { params.leftMargin = maxWidth - (v.getWidth() / 2); } else { params.leftMargin = leftMargin; } v.setLayoutParams(params); break; } } return true; } }; } 

I think there are a couple of potential problems:

  1. Are you sure you're getting the correct IDs in your onTouch() ? (since the touch listener is only used with your card views, you propably can remove the if checking for the IDs)
  2. You are using a FrameLayout - so use the x and y position instead of margins edit: my bad, you're using RelativeLayout , so the margins are kind of right. Though, I'd use a FrameLayout instead
  3. the API says you need to return true in onTouch() if you consumed the event, false otherwise (you're returning true when you didn't move the cards and nothing when you did)

Why your D&D is not working:

D&D is not working because your Card (that useses the internal FrameLayout) is implementing the onClick event that "eat" the d&d event.

Solutions are two:

you can have 2 different areas, one for the click event (the biggest part of the card), one for the d&d event (the bottom-left edge of the card). You can see a live example in the Android Music player that implements this solution.

Otherwise you can handle the two events at the same time:

  • click == down+up in the same time (under 100ms) in the same x/y location
  • dd == down+up in different times ( > 50/100ms)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM