OnClickListener - x, y ตำแหน่งของเหตุการณ์?


85

ฉันมีมุมมองแบบกำหนดเองที่ได้มาจาก View ฉันต้องการได้รับการแจ้งเตือนเมื่อมีการคลิกดูและตำแหน่ง x, y ที่เกิดการคลิก เช่นเดียวกันสำหรับการคลิกแบบยาว

onTouchEvent()ดูเหมือนว่าการทำเช่นนี้ฉันต้องแทนที่ ไม่มีวิธีรับตำแหน่ง x, y ของเหตุการณ์จากOnClickListenerแทนหรือไม่?

ถ้าไม่เป็นวิธีที่ดีในการบอกว่าเหตุการณ์การเคลื่อนไหวเป็นการคลิก 'จริง' หรือไม่และการคลิกแบบยาวเป็นต้น ทำให้onTouchEventเกิดเหตุการณ์ต่างๆมากมายต่อเนื่องกันอย่างรวดเร็วเป็นต้น

คำตอบ:


92

ขอขอบคุณ. นั่นคือสิ่งที่ฉันกำลังมองหา รหัสของฉันตอนนี้คือ:

imageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN){
                textView.setText("Touch coordinates : " +
                        String.valueOf(event.getX()) + "x" + String.valueOf(event.getY()));
            }
            return true;
        }
    });

ซึ่งทำในสิ่งที่มาร์คขอได้อย่างแม่นยำ ...


4
coords เหล่านี้อยู่ในท้องถิ่นสำหรับมุมมองหรือไม่?
ไนเจล

7
ตัวจัดการ onTouch ไม่ควรส่งคืนfalseดังนั้นจึงไม่บล็อกเหตุการณ์การสัมผัสใช่หรือไม่ (View OnTouchListener.onTouch จะคืนค่าจริงหากผู้ฟังใช้เหตุการณ์นั้นเป็นเท็จเป็นอย่างอื่น)
ehartwell

5
ไม่ใช่ "อย่างแม่นยำ" ที่OnClickListenerจะยิงเมื่อนิ้วถูกปล่อยออกมาดังนั้นACTION_UPแต่มีข้อ จำกัด : หากใช้ท่าทางปัด (ปัด) แล้วOnClickListenerจะไม่ยิง แต่ACTION_UPจะยังคงถูกประมวลผล
Alex Semeniuk

ฉันกำลังพยายามเขียนข้อความบนพิกัดที่คลิก ฉันลองเขียนข้อความตามพิกัด(event.getX(), event.getY()) แต่มันเขียนไม่ถูกตำแหน่ง
เจ้าชาย

นี่คือคำถามของฉัน stackoverflow.com/questions/40199539/…
Prince

26

ตัวอย่างเต็ม

คำตอบอื่น ๆ ไม่มีรายละเอียดบางอย่าง นี่คือตัวอย่างทั้งหมด

public class MainActivity extends AppCompatActivity {

    // class member variable to save the X,Y coordinates
    private float[] lastTouchDownXY = new float[2];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // add both a touch listener and a click listener
        View myView = findViewById(R.id.my_view);
        myView.setOnTouchListener(touchListener);
        myView.setOnClickListener(clickListener);
    }

    // the purpose of the touch listener is just to store the touch X,Y coordinates
    View.OnTouchListener touchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            // save the X,Y coordinates
            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                lastTouchDownXY[0] = event.getX();
                lastTouchDownXY[1] = event.getY();
            }

            // let the touch event pass on to whoever needs it
            return false;
        }
    };

    View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // retrieve the stored coordinates
            float x = lastTouchDownXY[0];
            float y = lastTouchDownXY[1];

            // use the coordinates for whatever
            Log.i("TAG", "onLongClick: x = " + x + ", y = " + y);
        }
    };
}

สรุป

  • เพิ่มตัวแปรคลาสเพื่อเก็บพิกัด
  • บันทึกพิกัด X, Y โดยใช้ไฟล์ OnTouchListener
  • เข้าถึงพิกัด X, Y ในไฟล์ OnClickListener

1
แทนที่จะเป็น 2 ช่องว่าง float Array สามารถใช้ Point () ได้
ZooMagic

Point มี X และ Y เป็นจำนวนเต็มชนิด พิกัดคือค่าลอย ถ้าฉันใช้ Point class ฉันคิดว่าฉันจะเสียความแม่นยำไป .... ฉันใหม่มากใน Android และอาจจะพลาดอะไร
mboada

@mboada คุณพูดถูก PointFน่าจะดีกว่า
Suragch

ควรมีวิธีหลีกเลี่ยง onTouchListener และใช้แค่ onClickListener อย่างไรก็ตาม ContextMenu ไม่จำเป็นต้องใช้ เมื่อคลิกรายการและแสดงเมนูโดยมีมุมมองเป็นจุดยึดจะรู้ว่าจะวางไว้ที่ใดใกล้กับตำแหน่งที่สัมผัส ดูที่นี่: stackoverflow.com/q/57290574/878126 คุณรู้ไหมว่ามันเป็นไปได้อย่างไร? ถ้าเป็นเช่นนั้นโปรดพิจารณาตอบที่นั่น
นักพัฒนา Android

3

แทนที่ onTouchEvent (MotionEvent ev)

จากนั้นคุณสามารถทำได้:

ev.getXLocation()

หรืออะไรทำนองนั้น. มีก้น


2
สวัสดีทอมใช่เราสามารถใช้ onTouchEvent ได้ แต่เราต้องจัดการกับการแยกแยะระหว่างการคลิกและการคลิกแบบยาวด้วยตัวเองใช่หรือไม่? มันไม่สมเหตุสมผลที่พวกเขาจะไม่ให้คุณรู้ว่าการคลิกหรือการคลิกแบบยาวเกิดขึ้นที่ไหนใน OnClickListener ขอบคุณ
มาร์ค

21
สิ่งที่คุณต้องทำคือบันทึกตำแหน่ง x & y ของเหตุการณ์ ACTION_UP หรือ ACTION_MOVE สุดท้ายและใช้ค่าเหล่านี้ใน OnClickListener ของคุณ
Romain Guy

@RomainGuy แต่คุณต้องคำนวณระยะห่างระหว่างจุดทั้งสองเพื่อกำหนดการคลิก หากคุณได้รับ ACTION_DOWN เหตุการณ์ที่ (0,0) แล้ว ACTION_UP เหตุการณ์ที่ (100,100) นั่นไม่ใช่การคลิกอย่างแน่นอน
TheRealChx101

@ chx101 สิ่งที่ RomainGuy หมายถึง (ฉันคิดว่า) ก็คือถ้าคุณเพียงแค่ใน Touchevent บันทึกพิกัด action_up สุดท้ายนั่นคือพิกัดที่คุณสามารถใช้ใน onclick อย่างไรก็ตามฉันคิดว่าจะต้องมีคลาสย่อยมุมมองในทางปฏิบัติไม่เช่นนั้น onclick จะไม่ถูกเรียก คุณยังสามารถตรวจจับการแตะเป็นเครื่องตรวจจับท่าทางเหมือนในstackoverflow.com/questions/19538747/… answer
Lassi Kinnunen

0

คุณสามารถสร้างฟังก์ชันส่วนขยายใน Kotlin ได้ดังนี้:

fun View.setOnClickListenerWithPoint(action: (Point) -> Unit) {
    val coordinates = Point()
    val screenPosition = IntArray(2)
    setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_DOWN) {
            v.getLocationOnScreen(screenPosition)
            coordinates.set(event.x.toInt() + screenPosition[0], event.y.toInt() + screenPosition[1])
        }
        false
    }
    setOnClickListener {
        action.invoke(coordinates)
    }
}

หากคุณต้องการการคลิกที่ยาวนาน - เพียงแค่แทนที่ setOnClickListener

ฉันใช้getLocationOnScreen()เพราะฉันต้องการพิกัดสำหรับ ViewHolder ของ RecyclerView

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.