Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ Drag and Drop ใน Android

ภาพรวม

ตัวอย่างนี้สาธิตการใช้ Drag and Drop API ใน Android เพื่อลาก View (รูปภาพ) จากพื้นที่ซ้ายไปวางในพื้นที่ขวา โดยใช้ View.OnDragListener และ View.OnTouchListener

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → File → New Project → Empty Activity

ขั้นตอนที่ 2: จัดรูปแบบหน้าจอ (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:padding="16dp"
    tools:context=".MainActivity">

    <!-- พื้นที่ต้นทาง (Source) -->
    <LinearLayout
        android:id="@+id/leftView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_margin="8dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:text="Drag from here"
            android:textColor="@android:color/white"
            android:textStyle="bold" />

        <ImageView
            android:id="@+id/boxView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:layout_margin="8dp"
            android:background="@drawable/ic_launcher_foreground"
            android:contentDescription="Draggable Item" />

    </LinearLayout>

    <!-- พื้นที่ปลายทาง (Target) -->
    <LinearLayout
        android:id="@+id/rightView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_margin="8dp"
        android:background="@android:color/holo_blue_light"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Drop here"
            android:textColor="@android:color/white"
            android:textStyle="bold" />

    </LinearLayout>

</LinearLayout>

ขั้นตอนที่ 3: เขียนโค้ด MainActivity.java

import android.os.Bundle;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity 
        implements View.OnTouchListener, View.OnDragListener {

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

        // ตั้ง Listener
        findViewById(R.id.boxView).setOnTouchListener(this);
        findViewById(R.id.leftView).setOnDragListener(this);
        findViewById(R.id.rightView).setOnDragListener(this);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // เริ่ม Drag
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
            
            // ClipData (Optional) - ส่งข้อมูลไปกับ Drag
            // ClipData data = ClipData.newPlainText("label", "boxView");
            // view.startDragAndDrop(data, shadowBuilder, view, 0); // API 24+
            
            // Deprecated แต่ยังทำงานได้
            view.startDrag(null, shadowBuilder, view, 0);
            
            // ซ่อน View ต้นทางขณะลาก
            view.setVisibility(View.INVISIBLE);
            return true;
        }
        return false;
    }

    @Override
    public boolean onDrag(View view, DragEvent event) {
        int action = event.getAction();
        
        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
                // Drag เริ่มต้น - ตรวจสอบว่า View นี้รับ Drop ได้ไหม
                // return true เพื่อรับ Drop ต่อไป
                return true;

            case DragEvent.ACTION_DRAG_ENTERED:
                // Drag เข้ามาใน View นี้ - เปลี่ยนสีพื้นหลังบอกว่า Drop ได้
                view.setBackgroundColor(getResources().getColor(android.R.color/holo_green_light));
                break;

            case DragEvent.ACTION_DRAG_EXITED:
                // Drag ออกจาก View นี้ - คืนสีเดิม
                view.setBackgroundColor(getResources().getColor(android.R.color/holo_blue_light));
                break;

            case DragEvent.ACTION_DROP:
                // Drop ลงใน View นี้
                View draggedView = (View) event.getLocalState();
                ViewGroup sourceParent = (ViewGroup) draggedView.getParent();
                
                // ย้าย View จาก Parent เดิม
                if (sourceParent != null) {
                    sourceParent.removeView(draggedView);
                }
                
                // เพิ่มเข้า Target Parent
                if (view instanceof ViewGroup) {
                    ((ViewGroup) view).addView(draggedView);
                }
                
                // แสดง View อีกครั้ง
                draggedView.setVisibility(View.VISIBLE);
                
                Toast.makeText(this, "Dropped!", Toast.LENGTH_SHORT).show();
                break;

            case DragEvent.ACTION_DRAG_ENDED:
                // Drag จบสิ้น (ไม่ว่าจะ Drop สำเร็จหรือไม่)
                // คืนสีพื้นหลัง
                view.setBackgroundColor(getResources().getColor(android.R.color/holo_blue_light));
                
                // ถ้า Drop ไม่สำเร็จ ให้คืน View กลับไปที่เดิม
                if (!event.getResult()) {
                    View draggedView = (View) event.getLocalState();
                    draggedView.setVisibility(View.VISIBLE);
                }
                break;
        }
        return true;
    }
}

ขั้นตอนที่ 4: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                
                
            </intent-filter>
        </activity>

    </application>
</manifest>

การทดสอบ

รันแอป → กดค้างที่รูปภาพในพื้นที่สีเทา → ลากไปวางในพื้นที่สีฟ้า → รูปภาพจะย้ายไปอยู่ที่นั่น

วิธีใช้ Drag and Drop ใน Android

Drag and Drop แบบ Modern (API 24+)

// ใช้ startDragAndDrop แทน startDrag
view.startDragAndDrop(
    ClipData.newPlainText("item_id", "boxView"), // Data
    new View.DragShadowBuilder(view),            // Shadow
    view,                                        // Local State
    0                                            // Flags
);

// ใน OnDragListener ใช้ ClipData
case DragEvent.ACTION_DROP:
    ClipData clipData = event.getClipData();
    if (clipData != null && clipData.getItemCount() > 0) {
        String itemId = clipData.getItemAt(0).getText().toString();
        // ประมวลผลตาม itemId
    }
    break;

RecyclerView Drag & Drop (ItemTouchHelper)

สำหรับรายการที่สามารถเรียงลำดับได้ (Reorder List) ใช้ ItemTouchHelper:

ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, 
                          RecyclerView.ViewHolder source, 
                          RecyclerView.ViewHolder target) {
        // Swap items in adapter
        int from = source.getAdapterPosition();
        int to = target.getAdapterPosition();
        Collections.swap(dataList, from, to);
        adapter.notifyItemMoved(from, to);
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // Handle swipe to delete
        int position = viewHolder.getAdapterPosition();
        dataList.remove(position);
        adapter.notifyItemRemoved(position);
    }
};

new ItemTouchHelper(callback).attachToRecyclerView(recyclerView);

Jetpack Compose Drag & Drop

@Composable
fun DragDropExample() {
    var draggedItem by remember { mutableStateOf(null) }
    
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // Source
        Box(
            modifier = Modifier
                .size(100.dp)
                .fillMaxHeight()
                .background(Color.Gray)
                .pointerInput(Unit) {
                    detectDragGesturesAfterLongPress(
                        onDragStart = { draggedItem = 1 },
                        onDragEnd = { draggedItem = null }
                    )
                }
        ) {
            Text("Drag Me", color = Color.White, textAlign = TextAlign.Center, modifier = Modifier.align(Alignment.Center))
        }
        
        // Target
        Box(
            modifier = Modifier
                .size(100.dp)
                .fillMaxHeight()
                .background(if (draggedItem != null) Color.Green else Color.Blue)
                .pointerInput(Unit) {
                    detectDragGestures(
                        onDragEnd = { 
                            if (draggedItem != null) {
                                // Handle drop
                                draggedItem = null
                            }
                        }
                    )
                }
        ) {
            Text("Drop Here", color = Color.White, textAlign = TextAlign.Center, modifier = Modifier.align(Alignment.Center))
        }
    }
}