ทำให้มุมมองที่กำหนดเองเป็นแบบอินเทอร์แอกทีฟ

ลองใช้วิธีการเขียน
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนำสำหรับ Android ดูวิธีใช้งานเลย์เอาต์ใน Compose

การวาด UI เป็นเพียงส่วนหนึ่งของการสร้างมุมมองที่กำหนดเอง คุณยังต้อง ทำให้มุมมองของคุณตอบสนองต่อข้อมูลจากผู้ใช้ในลักษณะที่คล้ายคลึงกับ จากสถานการณ์จริง ที่คุณกำลังเลียนแบบ

ทำให้วัตถุในแอปทำหน้าที่เหมือนวัตถุจริง ตัวอย่างเช่น อย่าปล่อยให้ รูปภาพในแอปจะแสดงที่ไม่มีอยู่และปรากฏขึ้นอีกครั้งที่อื่น เนื่องจากออบเจ็กต์ต่างๆ ในโลกแห่งความเป็นจริง อย่าทำแบบนั้น แต่ให้ย้ายรูปภาพจากที่หนึ่งไปที่ อีกรายการ

ผู้ใช้สัมผัสได้ถึงพฤติกรรมที่บอบบางหรือรู้สึกถึงอินเทอร์เฟซและตอบสนองอย่างดีที่สุด รายละเอียดเล็กๆ น้อยๆ ที่เลียนแบบโลกจริง ตัวอย่างเช่น เมื่อผู้ใช้สะบัดออบเจ็กต์ UI ในระยะแรก โมเดลก็จะเกิดความเฉื่อย ซึ่งจะหน่วงเวลาการเคลื่อนไหว ในช่วงท้าย ทำให้โมเดลรับรู้ถึงแรงโมเมนตัมที่พาวัตถุออกไปนอก สะบัด

หน้านี้จะแสดงวิธีใช้ฟีเจอร์ต่างๆ ของเฟรมเวิร์ก Android ในการเพิ่ม พฤติกรรมการใช้งานจริงเหล่านี้กับมุมมองที่คุณกำหนดเอง

ดูข้อมูลที่เกี่ยวข้องเพิ่มเติมได้ใน ภาพรวมของเหตุการณ์การป้อนข้อมูลและ ภาพเคลื่อนไหวของพร็อพเพอร์ตี้ ภาพรวม

จัดการท่าทางสัมผัสในการป้อนข้อมูล

Android รองรับโมเดลเหตุการณ์การป้อนข้อมูลเช่นเดียวกับเฟรมเวิร์ก UI อื่นๆ อีกจำนวนมาก ผู้ใช้ การดำเนินการจะเปลี่ยนเป็นเหตุการณ์ที่ทริกเกอร์ Callback และคุณสามารถลบล้าง Callback เพื่อปรับแต่งวิธีที่แอปตอบสนองต่อผู้ใช้ อินพุตที่ใช้บ่อยที่สุด ในระบบ Android คือการแตะ ซึ่งจะทริกเกอร์ onTouchEvent(android.view.MotionEvent) ลบล้างเมธอดนี้เพื่อจัดการเหตุการณ์ ดังนี้

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return super.onTouchEvent(event)
}

Java

@Override
   public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
   }

เหตุการณ์การสัมผัสเพียงอย่างเดียวนั้นไม่มีประโยชน์มากนัก UI ระบบสัมผัสที่ทันสมัย ให้คำจำกัดความการโต้ตอบในแง่ของท่าทางสัมผัส เช่น การแตะ การดึง การผลัก การสะบัดและการซูม การแปลงเหตุการณ์การสัมผัสเป็นข้อมูลดิบเป็นท่าทางสัมผัส Android ให้ GestureDetector

สร้าง GestureDetector โดยการส่งอินสแตนซ์ในคลาส ซึ่งใช้ GestureDetector.OnGestureListener หากคุณต้องการประมวลผลท่าทางสัมผัสเพียงไม่กี่ครั้ง คุณสามารถขยายเวลา GestureDetector.SimpleOnGestureListener แทนที่จะใช้เมธอด GestureDetector.OnGestureListener ของ Google ตัวอย่างเช่น โค้ดนี้จะสร้างคลาสที่ขยาย GestureDetector.SimpleOnGestureListener และการลบล้าง onDown(MotionEvent)

Kotlin

private val myListener =  object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }
}

private val detector: GestureDetector = GestureDetector(context, myListener)

Java

class MyListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
detector = new GestureDetector(getContext(), new MyListener());

ไม่ว่าคุณจะใช้ GestureDetector.SimpleOnGestureListener หรือไม่ก็ตาม ใช้ วันที่ onDown() ซึ่งแสดงผล true นี่เป็นสิ่งจำเป็นเนื่องจากท่าทางสัมผัสทั้งหมด เริ่มต้นด้วยข้อความ onDown() หากคุณส่งคืน false จาก onDown() ในฐานะ GestureDetector.SimpleOnGestureListener รองรับ ระบบจะถือว่าระบบ ไม่ต้องสนใจท่าทางสัมผัสที่เหลือ รวมถึงวิธีอื่นๆ ไม่ได้เรียก GestureDetector.OnGestureListener เฉพาะขากลับ false จาก onDown() หากคุณต้องการละเว้น ท่าทางสัมผัส

หลังจากติดตั้งใช้งาน GestureDetector.OnGestureListener และสร้าง อินสแตนซ์ของ GestureDetector คุณสามารถใช้ GestureDetector เพื่อตีความเหตุการณ์การแตะที่คุณได้รับ onTouchEvent()

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return detector.onTouchEvent(event).let { result ->
        if (!result) {
            if (event.action == MotionEvent.ACTION_UP) {
                stopScrolling()
                true
            } else false
        } else true
    }
}

Java

@Override
public boolean onTouchEvent(MotionEvent event) {
   boolean result = detector.onTouchEvent(event);
   if (!result) {
       if (event.getAction() == MotionEvent.ACTION_UP) {
           stopScrolling();
           result = true;
       }
   }
   return result;
}

เมื่อคุณผ่าน onTouchEvent() กิจกรรมการสัมผัสที่ไม่ได้ผ่าน จดจำได้ ซึ่งเป็นส่วนหนึ่งของท่าทางสัมผัส จะแสดง false จากนั้นคุณจะสามารถเรียกใช้ รหัสตรวจจับท่าทางสัมผัสที่กำหนดเองของคุณ

สร้างการเคลื่อนไหวที่จับต้องได้

ท่าทางสัมผัสเป็นวิธีที่มีประสิทธิภาพในการควบคุมอุปกรณ์ที่มีหน้าจอสัมผัส แต่สามารถ ฟังดูขัดกับสัญชาตญาณและจำยาก หากไม่ผลิตเนื้อหาขึ้นมา ผลลัพธ์ที่เป็นไปได้

ตัวอย่างเช่น สมมติว่าคุณต้องการใช้ท่าทางสัมผัสการสะบัดในแนวนอน จะเป็นการกำหนดให้รายการที่วาดในมุมมองหมุนไปรอบๆ แกนแนวตั้ง ท่าทางสัมผัสนี้ เหมาะสมหาก UI ตอบสนองด้วยการเคลื่อนที่อย่างรวดเร็วในทิศทางการสะบัด จากนั้นก็ลดความเร็วลง ราวกับว่าผู้ใช้ออกแรงกดบนล้อเลื่อนและหมุนวน

เอกสารประกอบเกี่ยวกับวิธี ทำให้การเลื่อนเคลื่อนไหว ท่าทางสัมผัสให้คำอธิบายโดยละเอียดเกี่ยวกับวิธีนำสก็อตของคุณเองมาใช้ พฤติกรรมของคุณ แต่การจำลองความรู้สึกของมอเตอร์ไซค์ก็ไม่ใช่เรื่องง่าย ฟิสิกส์เยอะ และจะต้องใช้คณิตศาสตร์เพื่อทำให้โมเดลฟลายวีลทำงานอย่างถูกต้อง โชคดี Android มีคลาสตัวช่วยเพื่อจำลองสิ่งนี้และพฤติกรรมอื่นๆ Scroller คลาสเป็นพื้นฐานของการจัดการท่าทางสัมผัสการสะบัดแบบล้อเลื่อน

หากต้องการเริ่มการสะบัด ให้โทร fling() ด้วยอัตราความเร็วเริ่มต้นและค่าต่ำสุดและสูงสุด x และ y ของการปัด สำหรับค่าความเร็ว คุณสามารถใช้ค่าที่คำนวณโดย GestureDetector

Kotlin

fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    scroller.fling(
            currentX,
            currentY,
            (velocityX / SCALE).toInt(),
            (velocityY / SCALE).toInt(),
            minX,
            minY,
            maxX,
            maxY
    )
    postInvalidate()
    return true
}

Java

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);
   postInvalidate();
    return true;
}

การเรียก fling() เกี่ยวกับการสร้างโมเดลฟิสิกส์สำหรับการขว้าง ท่าทางสัมผัส หลังจากนั้น โปรดอัปเดต Scroller โดยโทรไปที่ วันที่ Scroller.computeScrollOffset() อย่างสม่ำเสมอ computeScrollOffset() อัปเดต สถานะภายในของออบเจ็กต์ Scroller โดยการอ่านเวลาปัจจุบันและ ใช้โมเดลฟิสิกส์เพื่อคำนวณตำแหน่ง x และ y ที่ตำแหน่งนั้น โทร getCurrX() และ วันที่ getCurrY() เพื่อดึงข้อมูลค่าเหล่านี้

มุมมองส่วนใหญ่จะส่ง x และ y ของออบเจ็กต์ Scroller ตำแหน่งโดยตรงไปยัง scrollTo() ตัวอย่างนี้ต่างออกไปเล็กน้อยโดยใช้ตำแหน่งการเลื่อน x ในปัจจุบัน เพื่อตั้งค่ามุมหมุนของมุมมอง

Kotlin

scroller.apply {
    if (!isFinished) {
        computeScrollOffset()
        setItemRotation(currX)
    }
}

Java

if (!scroller.isFinished()) {
    scroller.computeScrollOffset();
    setItemRotation(scroller.getCurrX());
}

คลาส Scroller จะคำนวณตำแหน่งการเลื่อนให้คุณ จะไม่ใช้ตำแหน่งเหล่านั้นกับมุมมองของคุณโดยอัตโนมัติ ใช้พิกัดใหม่ บ่อยพอที่จะทำให้ภาพเคลื่อนไหวแบบเลื่อนได้ดูลื่นไหล คุณทำสิ่งต่อไปนี้ได้ 2 วิธี ทำสิ่งนี้

  • บังคับการวาดใหม่โดยการเรียกใช้ postInvalidate() หลังจากโทรหา fling() คุณต้องใช้เทคนิคนี้ การชดเชยการเลื่อนการประมวลผลใน onDraw() และเรียกใช้ postInvalidate() ทุกครั้งที่ออฟเซ็ตการเลื่อน การเปลี่ยนแปลง
  • ตั้งค่า ValueAnimator เพื่อให้เคลื่อนไหวในช่วง สะบัดข้อมือ และเพิ่มผู้ฟังในการดำเนินขั้นตอน อัปเดตภาพเคลื่อนไหวด้วยการเรียก addUpdateListener() เทคนิคนี้ช่วยให้คุณทําให้พร็อพเพอร์ตี้ของ View

ทำให้ทรานซิชันราบรื่น

ผู้ใช้คาดหวังให้ UI ที่ทันสมัยเปลี่ยนผ่านระหว่างสถานะต่างๆ ได้อย่างราบรื่น: องค์ประกอบ UI ค่อยๆ เลือนหายไปและค่อยๆ หายไปแทนที่จะปรากฏและหายไป และเริ่มการเคลื่อนไหว แล้วจบลงอย่างลื่นไหล แทนที่จะต้องเริ่มหรือหยุดลงอย่างกะทันหัน Android ภาพเคลื่อนไหวของพร็อพเพอร์ตี้ ทำให้การเปลี่ยนราบรื่นง่ายขึ้น

หากต้องการใช้ระบบภาพเคลื่อนไหว เมื่อใดก็ตามที่พร็อพเพอร์ตี้เปลี่ยนแปลงสิ่งที่ส่งผลต่อ อย่าเปลี่ยนแปลงพร็อพเพอร์ตี้โดยตรง ให้ใช้ ValueAnimator เพื่อทำการเปลี่ยนแปลง ในตัวอย่างต่อไปนี้ การแก้ไขคอมโพเนนต์ย่อยที่เลือกในมุมมอง จะทำให้การแสดงผลทั้งหมด เพื่อให้เคอร์เซอร์การเลือกอยู่ตรงกลาง ValueAnimator เปลี่ยนการหมุนเวียนในช่วงเวลาหลายร้อยครั้ง มิลลิวินาที แทนที่จะกำหนดค่าการหมุนเวียนใหม่โดยทันที

Kotlin

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply {
    setIntValues(targetAngle)
    duration = AUTOCENTER_ANIM_DURATION
    start()
}

Java

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0);
autoCenterAnimator.setIntValues(targetAngle);
autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
autoCenterAnimator.start();

หากค่าที่ต้องการเปลี่ยนเป็นหนึ่งในฐาน View คุณสมบัติพิเศษอื่นๆ ในการสร้างภาพเคลื่อนไหวก็ทำได้ง่ายขึ้น เนื่องจากการดูมี วันที่ ViewPropertyAnimator ซึ่งได้รับการเพิ่มประสิทธิภาพสำหรับภาพเคลื่อนไหว แบบต่อเนื่องของพร็อพเพอร์ตี้หลายรายการ เช่น ตัวอย่างต่อไปนี้

Kotlin

animate()
    .rotation(targetAngle)
    .duration = ANIM_DURATION
    .start()

Java

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();