Drag và Drop trong Android




Drag/Drop trong Android Framework cho phép người dùng di chuyển dữ liệu từ một View sang View khác trong Layout hiện tại bởi sử dụng một động tác kéo và thả. Như của API 11, hoạt động kéo và thả trên view hoặc view group được hỗ trợ. Framework này cũng bao gồm ba thành phần cơ bản để hỗ trợ tính năng drag và drop, đó là: & drop functionality −

  • Lớp DragEvent

  • Drag listeners:

  • Các phương thức và lớp giúp đỡ

Tiến trình Drag/Drop trong Android

Về cơ bản, trong tiến trình Drag/Drop sẽ có 4 bước/trạng thái cơ bản:

  • Trạng thái bắt đầu: − Sự kiện này xuất hiện khi bạn bắt đầu kéo một item trong một layout, ứng dụng của bạn gọi phương thức startDrag() để nói cho hệ thống để bắt đầu một Drag. Các tham số bên trong startDrag() cung cấp dữ liệu để được kéo, cung cấp metadata cho dữ liệu này, và cung cấp một hàm callback để vẽ drag shadow (có thể hiểu là bóng kéo).

    Đầu tiên, hệ thống phản hồi bằng việc gọi lại ứng dụng của bạn để lấy một drag shadow. Sau đó, nó hiển thị drag shadow này trên thiết bị.

    Tiếp theo, hệ thống gửi một sự kiện kéo (drag event) với kiểu action là ACTION_DRAG_STARTED tới các Listener đã đăng ký cho tất cả đối tượng View trong Layout hiện tại.

    Để tiếp tục nhận các drag event, bao gồm một drop event có thể có, một Listener phải trả về true. Nếu Listener trả về false, thì nó sẽ không nhận các drag event cho hành động hiện tại tới khi hệ thống gửi một drag event với kiểu action là ACTION_DRAG_ENDED.

  • Trạng thái tiếp tục: − Người dùng tiếp tục hoạt động kéo. Hệ thống gửi action là ACTION_DRAG_ANTERED được theo sau bởi ACTION_DRAG_LOCATION tới Listener đã đăng ký cho View. Listener có thể chọn để lọc bề mặt đối tượng View của nó để phản hồi sự kiện hoặc có thể phản hồi bằng cách làm nổi bật View đó.

    Listener nhận một action là ACTION_DRAG_EXITED sau khi người dùng đã di chuyển drag shadow ra ngoài hộp giới hạn của View đó.

  • Trạng thái thả: − Người dùng thả item đang kéo bên trong hộp giới hạn của một View. Hệ thống gửi tới Listener của đối tượng View một drag event với kiểu action là ACTION_DROP.

  • Trạng thái kết thúc: − Ngay sau ACTION_DROP, hệ thống gửi ra ngoài một drag event với kiểu action là ACTION_DRAG_ENDED để thông báo rằng hoạt động kéo đã xong.

Lớp DragEvent trong Android

Lớp DragEvent biểu diễn một sự kiện được gửi ra bởi hệ thống tại các thời điểm khác nhau trong suốt tiến trình hoạt động kéo và thả. Lớp này cung cấp một số Hằng và các phương thức quan trọng để bạn sử dụng trong tiến trình Drag/Drop.

Hằng trong lớp DragEvent

Bảng dưới liệt kê tất cả hằng số nguyên có sẵn của lớp DragEvent:

Stt. Constants & Miêu tả
1 ACTION_DRAG_STARTED

Tín hiệu bắt đầu hoạt động kéo và thả

2 ACTION_DRAG_ENTERED

Tín hiệu thông báo cho một View là điểm kéo đã đi vào hộp giới hạn của View đó

3 ACTION_DRAG_LOCATION

Được gửi tới một View sau ACTION_DRAG_ENTERED nếu drag shadow vẫn ở bên trong hộp giới hạn của View đó

4 ACTION_DRAG_EXITED

Tín hiệu thông báo rằng người dùng đã di chuyển drag shadow ra ngoài hộp giới hạn của View

5 ACTION_DROP

Tín hiệu thông báo cho một View rằng người dùng đã thả drag shadow, và điểm kéo là bên trong hộp giới hạn của View

6 ACTION_DRAG_ENDED

Tín hiệu thông báo cho một View là hoạt động kéo và thả đã kết thúc

Phương thức trong lớp DragEvent

Dưới đây là một số phương thức quan trọng và thường được sử dụng nhất của lớp DragEvent:

Stt. Constants & Miêu tả
1 int getAction()

Kiểm tra giá trị action của sự kiện này

2 ClipData getClipData()

Trả về đối tượng ClipData được gửi tới hệ thống như là một phần của lời gọi tới startDrag()

3 ClipDescription getClipDescription()

Trả về đối tượng ClipDescription được chứa trong ClipData

4 boolean getResult()

Trả về dấu hiệu của kết quả của hoạt động kéo và thả

5 float getX()

Lấy tọa độ X của điểm kéo

6 float getY()

Lấy tọa độ Y của điểm kéo

7 String toString()

Trả về biểu diễn chuỗi của đối tượng DragEvent này

Drag Listener trong Android

Nếu bạn muốn bất cứ view nào bên trong một Layout nên phản hồi sự kiện kéo, thì view của bạn: hoặc triển khai View.OnDragListener hoặc thiết lập phương thức callback là onDragEvent(DragEvent) ). Khi hệ thống gọi phương thức hoặc Listener này, nó truyền tới chúng một đối tượng DragEvent được giải thích ở trên. Bạn có thể có cả một Listener và một phương thức callback cho đối tượng View. Nếu điều này diễn ra, đầu tiên hệ thống gọi Listener và sau đó hàm callback đã định nghĩa cũng như Listener này trả về true.

Sự kết hợp của phương thức onDragEvent(DragEvent)View.OnDragListener là tương tự như kết hợp onTouchEvent()View.OnTouchListener được sử dụng với sự kiện touch trong các phiên bản Android cũ.

Bắt đầu một sự kiện kéo trong Android

Bạn bắt đầu bằng việc tạo một ClipDataClipData.Item cho dữ liệu đang được di chuyển. Đối tượng ClipData này cung cấp metadata mà được lưu trữ trong một đối tượng ClipMiêu tả bên trong ClipData. Với hoạt động kéo và thả mà không biểu diễn sự di chuyển của dữ liệu, bạn có thể sử dụng null thay vì một đối tượng thực sự.

Tiếp đó, hoặc bạn có thể kế thừa View.DragShadowBuilder để tạo một drag shadow cho hoạt động kéo hoặc đơn giản hơn bạn sử dụng View.DragShadowBuilder(View) để tạo một drag shadow mặc định (cùng kích cỡ như tham số View đã truyền cho nó), với điểm chạm ở giữa drag shadow này.

Ví dụ

Ví dụ sau minh họa tính năng của hoạt động Drag và Drop đơn giản bởi sử dụng View.setOnLongClickListener(), View.setOnTouchListener()View.OnDragEventListener().

Bước Miêu tả
1 Bạn sử dụng Android Studio IDE để tạo ứng dụng Android với tên làMy Application dưới một package com.example.saira_000.myapplication. Trong khi tạo project này, đảm bảo Target SDKCompile With ở phiên bản Android SDK mới nhất để sử dụng APIs cấp độ cao hơn
2 Sửa đổi src/MainActivity.java file và thêm code để định nghĩa các Listener cũng như phương thức callback cho logo image được sử dụng trong ví dụ
3 Sao chép hình abc.png trong res/drawable-* folder. Bạn có thể sử dụng hình ảnh có độ phân giải khác nhau trong trường hợp bạn muốn cung cấp chúng cho các thiết bị khác nhau
4 Sửa đổi res/layout/activity_main.xml để định nghĩa view mặc định cho logo image
5 Chạy ứng dụng để chạy Android Emulator và kiểm tra kết quả các thay đổi đã thực hiên trong ứng dụng

Sau đây là nội dung của Main Activity file đã được sửa đổi: src/MainActivity.java.

package com.example.saira_000.myapplication;

import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.DragEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;


public class MainActivity extends Activity {
   ImageView img;
   String msg;
   private android.widget.RelativeLayout.LayoutParams layoutParams;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      img=(ImageView)findViewById(R.id.imageView);
      
      img.setOnLongClickListener(new View.OnLongClickListener() {
         @Override
         public boolean onLongClick(View v) {
            ClipData.Item item = new ClipData.Item((CharSequence)v.getTag());
            String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
            
            ClipData dragData = new ClipData(v.getTag().toString(),mimeTypes, item);
            View.DragShadowBuilder myShadow = new View.DragShadowBuilder(img);
            
            v.startDrag(dragData,myShadow,null,0);
            return true;
         }
      });
      
      img.setOnDragListener(new View.OnDragListener() {
         @Override
         public boolean onDrag(View v, DragEvent event) {
            switch(event.getAction())
            {
               case DragEvent.ACTION_DRAG_STARTED:
               layoutParams = (RelativeLayout.LayoutParams)v.getLayoutParams();
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_STARTED");
               
               // Do nothing
               break;
               
               case DragEvent.ACTION_DRAG_ENTERED:
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_ENTERED");
               int x_cord = (int) event.getX();
               int y_cord = (int) event.getY();
               break;
               
               case DragEvent.ACTION_DRAG_EXITED :
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_EXITED");
               x_cord = (int) event.getX();
               y_cord = (int) event.getY();
               layoutParams.leftMargin = x_cord;
               layoutParams.topMargin = y_cord;
               v.setLayoutParams(layoutParams);
               break;
               
               case DragEvent.ACTION_DRAG_LOCATION  :
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_LOCATION");
               x_cord = (int) event.getX();
               y_cord = (int) event.getY();
               break;
               
               case DragEvent.ACTION_DRAG_ENDED   :
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_ENDED");
               
               // Do nothing
               break;
               
               case DragEvent.ACTION_DROP:
               Log.d(msg, "ACTION_DROP event");
               
               // Do nothing
               break;
               default: break;
            }
            return true;
         }
      });
      
      img.setOnTouchListener(new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
               ClipData data = ClipData.newPlainText("", "");
               View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(img);
               
               img.startDrag(data, shadowBuilder, img, 0);
               img.setVisibility(View.INVISIBLE);
               return true;
            }
            else
            {
               return false;
            }
         }
      });
   }
   
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_main, menu);
      return true;
   }
   
   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      
      int id = item.getItemId();
      
      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }
}

Sau đây là nội dung của res/layout/activity_main.xml file −

<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">
   
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Drag and Drop Example"
      android:id="@+id/textView"
      android:layout_alignParentTop="true"
      android:layout_centerHorizontal="true"
      android:textSize="30dp" />
      
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Tutorials Point"
      android:id="@+id/textView2"
      android:layout_below="@+id/textView"
      android:layout_centerHorizontal="true"
      android:textSize="30dp"
      android:textColor="#ff14be3c" />>
      
   <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/imageView"
      android:src="@drawable/abc"
      android:layout_below="@+id/textView2"
      android:layout_alignRight="@+id/textView2"
      android:layout_alignEnd="@+id/textView2"
      android:layout_alignLeft="@+id/textView2"
      android:layout_alignStart="@+id/textView2" />

</RelativeLayout>

Sau đây là nội dung của res/values/strings.xml để định nghĩa hai hằng −

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <string name="app_name">My Application</string>
   <string name="action_settings">Settings</string>
</resources>

Sau đây là nội dung mặc định của AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.guidemo"
   android:versionCode="1"
   android:versionName="1.0" >
   
   <uses-sdk
      android:minSdkVersion="11"
      android:targetSdkVersion="22" />
      
   <application
      android:allowBackup="true"
      android:icon="@drawable/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme" >
      
      <activity
         android:name="com.example.guidemo.MainActivity"
         android:label="@string/app_name" >
      
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
      
      </activity>
      
   </application>
</manifest>

Chạy ứng dụng Android. Giả sử bạn đã tạo AVD trong khi cài đặt. Để chạy ứng dụng từ Android Studio, mở activity file và nhấn biểu tượng Run từ thanh công cụ. −

Drag và Drop trong Android

Bây giờ, thực hiện một long click trên hình logo và bạn sẽ thấy rằng hình logo này di chuyển một chút từ vị trí của nó sau khi bạn long click 1 giây, đó là thời điểm khi bạn bắt đầu hoạt động kéo. Bạn có thể kéo nó quanh màn hình và thả nó xuống một vị trí mới.

Drag và Drop trong Android

Follow fanpage của team https://www.facebook.com/vietjackteam/ hoặc facebook cá nhân Nguyễn Thanh Tuyền https://www.facebook.com/tuyen.vietjack để tiếp tục theo dõi các loạt bài mới nhất về Java,C,C++,Javascript,HTML,Python,Database,Mobile.... mới nhất của chúng tôi.