Android拖放


Android 拖/放框架允許使用者將資料從一個View到另一個檢視在當前布局中使用圖形化的拖放動作。該框架包括以下三個重要組成部分,支援拖放功能:

  • 拖動事件類

  • 拖動監聽器

  • 輔助方法和類

拖放過程

基本上有四個步驟,在拖放過程或狀態:

  • 開始:此事件發生時開始拖動布局中的一個專案,應用類的tartDrag()方法來告訴系統啟動拖動。startDrag()方法的引數提供被拖動的資料,這些是資料的後設資料和一個回撥用於繪製的拖動陰影。

    該系統首先通過回撥應用程式,以獲得一個拖陰影的響應。然後顯示在裝置上的拖影。

    接下來,系統會傳送拖曳事件動作型別ACTION_DRAG_STARTED在當前布局中的所有檢視物件拖動事件監聽器註冊。

    若要繼續接收拖動事件,其中包括一個可能的放事件,一個拖事件偵聽器必須返回true,如果拖動事件偵聽器返回false,那麼它不會收到拖動事件當前的操作,直到系統傳送一個動作型別的拖曳事件ACTION_DRAG_ENDED。

  • 繼續:使用者可以繼續拖動。系統傳送ACTION_DRAG_ENTERED動作,其次註冊拖動事件偵聽器的檢視中拖動點進入ACTION_DRAG_LOCATION動作。響應該事件監聽器可以選擇改變其物件的外觀或可以凸顯其觀點反應。使用者移動拖動檢視的邊框陰影外拖曳事件偵聽器接收ACTION_DRAG_EXITED動作。

  • 拖動:使用者釋放拖動的專案檢視的邊框內。該系統傳送物件的偵聽器拖動事件使用動作型別ACTION_DROP。

  • 結果:操作型別ACTION_DROP之後,系統發出一個操作型別ACTION_DRAG_ENDED表示拖動操作結束的拖動事件。

DragEvent 類

dragEvent代表一個事件,就會由系統送出拖放操作過程中在不同的時間。這個類提供了一些常數和重要的方法在使用拖/放過程。

常數

以下是所有常數作為部分 dragEvent 類整數。

S.N. 常數說明
1 ACTION_DRAG_STARTED 
拖放操作的開始的信號
2 ACTION_DRAG_ENTERED 
一種檢視拖動點已進入檢視的邊框的信號
3 ACTION_DRAG_LOCATION 
傳送到ACTION_DRAG_ENTERED後的檢視,如果拖影依然是檢視物件的邊框內
4 ACTION_DRAG_EXITED 
信號的使用者移動拖動陰影檢視的邊框之外
5 ACTION_DROP 
信號到View使用者發布了拖影,而阻力點就是檢視的邊框內
6 ACTION_DRAG_ENDED 
檢視拖放操作已經結束信號

方法

以下是作為部分的 dragEvent 類提供一些重要的和最常用的方法。

S.N. 常數說明
1 int getAction() 
檢查此事件的動作值
2 ClipData getClipData() 
返回物件到系統呼叫ClipData()傳送作為到startDrag一部分部分
3 ClipDescription getClipDescription() 
返回包含在ClipData的ClipDescription物件
4 boolean getResult() 
返回拖放操作的結果的指示
5 float getX() 
獲取阻力的X坐標點
6 float getY() 
獲取阻力的Y坐標點
7 String toString() 
返回DragEvent物件的字串表示

監聽拖放事件

如果想要的任何布局內檢視響應拖動事件,那麼檢視要麼實現 View.OnDragListener 或者設定 onDragEvent(DragEvent) 回撥方法。當系統呼叫的方法或監聽器,它傳遞給上述 dragEvent 物件。可以檢視物件的監聽器和一個回撥方法。如果發生這種情況,系統首先呼叫監聽器,然後定義回撥監聽器返回true。

組合 onDragEvent(DragEvent)方法 和 View.OnDragListener,類似於 onTouchEvent() 和 View.OnTouchListener 使用在舊版本 Android 觸控事件的組合。 

開始拖動事件

開始建立ClipData和移動資料ClipData.Item。作為ClipDataobject 的一部分提供的後設資料被儲存在ClipDescription內ClipData物件。對於拖放操作,並不代表資料移動,可能想使用空(null)而不是實際的物件。

下一步,可以擴充套件 View.DragShadowBuilder 建立一個拖動檢視,或者使用 View.DragShadowBuilder(View) 建立一個預設的大小相同的View引數傳遞給它的拖影,觸控拖動陰影點集中在拖影。

範例

下面的例子顯示了一個簡單的拖放範例中使用View.setOnLongClickListener() 事件偵聽器和 View.OnDragEventListener().函式。 

步驟 描述
1 使用Android Studio建立Android應用程式,並將它命名為:DragNDropDemo。在建立這個專案,確保目標SDK和編譯在Android SDK的最新版本或使用更高階別的API。
2 修改 src/MainActivity.java 檔案,並新增定義事件偵聽器的程式碼,以及一個回撥方法,在這個例子中使用Logo影象
3 複製圖片logo.png到res/drawable-* 檔案夾。可以使用的情況下,要為他們提供了不同的裝置有不同的解析度的影象
4 修改布局檔案 res/layout/activity_main.xml l定義logo圖片的預設檢視
5 執行該應用程式啟動 Android模擬器並驗證應用程式所做的修改結果。

以下是修改主活動檔案 src/com.yiibai.dragndropdemo/MainActivity.java 。這個檔案可以包括每個生命週期基本方法。

package com.yiibai.dragndropdemo;

import android.os.Bundle;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.widget.*;

public class MainActivity extends Activity{
   ImageView ima;
   private static final String IMAGEVIEW_TAG = "Android Logo";
   String msg;

   private android.widget.RelativeLayout.LayoutParams layoutParams;

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

      ima = (ImageView)findViewById(R.id.iv_logo);
      // Sets the tag
      ima.setTag(IMAGEVIEW_TAG);

      ima.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);

            // Instantiates the drag shadow builder.
            View.DragShadowBuilder myShadow = new DragShadowBuilder(ima);

            // Starts the drag
            v.startDrag(dragData,  // the data to be dragged
            myShadow,  // the drag shadow builder
            null,      // no need to use local data
            0          // flags (not currently used, set to 0)
            );
            return true;
         }
      });

      // Create and set the drag event listener for the View
      ima.setOnDragListener( new OnDragListener(){
         @Override
         public boolean onDrag(View v,  DragEvent event){
         RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
         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;
         }
      });
   }
}

下面是 res/layout/activity_main.xml 檔案的內容:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
	
    <ImageView
		android:id="@+id/iv_logo" 
    	android:layout_width="wrap_content" 
    	android:layout_height="wrap_content"
    	android:src="@drawable/logo"
    	android:contentDescription="@string/drag_drop"  />
	   
</RelativeLayout>

下面檔案 res/values/strings.xml 的內容中定義兩個新的常數:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">DragNDropDemo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="drag_drop">Click on the image to drag and drop</string>
   
</resources>

以下是 AndroidManifest.xml 檔案的預設內容:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.yiibai.guidemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.yiibai.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>

我們嘗試執行 DragNDropDemo 應用程式。AVD安裝的應用程式,並啟動它,如果一切設定和應用都沒有問題,它會顯示以下模擬器視窗: 

Android拖放

現在長時間點選顯示Android的標誌,會看到標誌影象經過1秒長的點選它,開始拖動影象的時候移動了一點。可以拖動它在螢幕上,並把它放在一個新的位置。

Android拖放

以下程式碼下載:http://pan.baidu.com/s/1eQIQIjw