Android拖放


Android拖放框架允许用户使用图形拖放手势将数据从一个视图移动到当前布局中的另一个视图。从 API 11开始,支持 将视图拖放到其他视图或视图组。该框架包括以下三个支持拖放功能的重要组件 -

  • 拖动事件类

  • 拖动侦听器

  • 帮助方法和类

拖放过程

拖放过程中基本上有四个步骤或状态 -

  • 已启动 - 当您开始拖动布局中的项目时,会发生此事件,您的应用程序调用 startDrag() 方法来告诉系统开始拖动。startDrag()方法内的参数提供要拖动的数据,此数据的元数据以及用于绘制拖动阴影的回调。

系统首先通过回调您的应用程序来获得拖动阴影。然后它会在设备上显示拖动阴影。

接下来,系统将操作类型为 _ACTION_DRAGSTARTED 的拖动事件发送到当前布局中所有View对象的已注册拖动事件侦听器。

要继续接收拖动事件(包括可能的拖放事件),拖动事件侦听器必须返回 true ,如果拖动事件侦听器返回false,则在系统发送具有操作类型的拖动事件之前,它将不会接收当前操作的拖动事件ACTION_DRAG_ENDED。

  • 继续 - 用户继续拖动。 系统发送ACTION_DRAG_ENTERED操作,然后将ACTION_DRAG_LOCATION操作发送到拖动点进入的View的已注册拖动事件侦听器。侦听器可以选择更改其View对象的外观以响应事件,或者可以通过突出显示其View来做出反应。

用户将拖动阴影移动到视图的边界框之外后,拖动事件侦听器会收到ACTION_DRAG_EXITED操作。

  • 已删除 - 用户在视图的边界框内释放拖动的项目。 系统向View对象的侦听器发送一个操作类型为ACTION_DROP的拖动事件。

  • 结束 - 在操作类型ACTION_DROP之后,系统发出一个操作类型为ACTION_DRAG_ENDED的拖动事件,以指示拖动操作已结束。

DragEvent类

所述 的dragEvent 表示被一个拖放操作期间在不同的时间发送出由系统中的事件。这个类提供了很少的常量和我们在拖放过程中使用的重要方法。

常量

以下是作为DragEvent类的一部分可用的所有常量整数。

序号 常数和描述
1

ACTION_DRAG_STARTED

表示拖放操作的开始。

2

ACTION_DRAG_ENTERED

向拖拽点已进入视图边界框的视图发出信号。

3

ACTION_DRAG_LOCATION

如果拖动阴影仍在View对象的边界框内,则在ACTION_DRAG_ENTERED后发送到视图。

4

ACTION_DRAG_EXITED

用户已将拖动阴影移动到视图边界框外的信号。

5

ACTION_DROP

向用户已释放拖动阴影的视图发出信号,拖动点位于视图的边界框内。

6

ACTION_DRAG_ENDED

向拖拽操作已结束的视图发出信号。

方法

以下是作为DragEvent类的一部分可用的一些重要且最常用的方法。

序号 常数和描述
1

int getAction()

检查此事件的操作值..

2

ClipData getClipData()

作为对startDrag()的调用的一部分,返回发送到系统的ClipData对象。

3

ClipDescription getClipDescription()

返回ClipData中包含的ClipDescription对象。

4

boolean getResult()

返回拖放操作结果的指示。

5

float getX()

获取拖动点的X坐标。

6

float getY()

获取拖动点的Y坐标。

7

String toString()

返回此DragEvent对象的字符串表示形式。

听Drag事件

如果您希望Layout中的任何视图都响应Drag事件,那么您的视图要么实现 View.OnDragListener, 要么设置 onDragEvent(DragEvent) 回调方法。当系统调用方法或侦听器时,它会向它们传递上面解释的DragEvent对象。您可以同时拥有View对象的侦听器和回调方法。如果发生这种情况,系统首先调用侦听器,然后只要侦听器返回true就定义了回调。

所述的组合 onDragEvent(的dragEvent) 方法和 View.OnDragListener 是类似于的组合 的onTouchEvent()View.OnTouchListener 与旧版本的Android触摸事件使用。

开始拖动事件

首先为正在移动的数据创建 ClipDataClipData.Item 。作为 ClipData 对象的一部分,提供存储在 ClipData 内的ClipDescription对象中的元数据。对于不表示数据移动的拖放操作,您可能希望使用 null 而不是实际对象。

接下来你可以扩展扩展 View.DragShadowBuilder 以创建拖动视图的拖动阴影,或者只是你可以使用 View.DragShadowBuilder(View) 来创建一个默认的拖动阴影,其大小与传递给它的View参数相同,触摸以拖影为中心的点。

下面的示例显示了使用 View.setOnLongClickListener()View.setOnTouchListener()View.OnDragEventListener() 进行简单拖放的功能。

Step Description
1 您将使用Android studio IDE创建Android应用程序,并com.example.saira_000.myapplication包下将其命名为My Application
2 修改src / MainActivity.java文件并添加代码以定义事件侦听器以及示例中使用的徽标图像的回调方法。
3 复制res / drawable- `*`文件夹中的图像abc.png 您可以使用具有不同分辨率的图像,以防您想要为不同的设备提供它们。
4 修改布局XML文件res / layout / activity_main.xml以定义徽标图像的默认视图。
5 运行应用程序以启动Android模拟器并验证应用程序中所做更改的结果。

以下是修改后的主活动文件 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;
            }
         }
      });
   }
}

以下是 res / layout / activity_main.xml 文件的内容

在下面的代码中,abc表示codingdict.com的徽标

<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>

以下是 res / values / strings.xml 的内容, 用于定义两个新常量

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

以下是 AndroidManifest.xml 的默认内容

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.saira_000.myapplication" >

   <application
      android:allowBackup="true"
      android:icon="@drawable/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme" >

      <activity
         android:name=".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>

让我们尝试运行 我的应用 程序。我假设您在进行环境设置时创建了 AVD 。要从Android Studio运行应用程序,请打开项目的某个活动文件,然后单击Eclipse运行图标工具栏中的运行图标。Android工作室在您的AVD上安装应用程序并启动它,如果您的设置和应用程序一切正常,它将显示以下模拟器窗口

Android拖放

现在,长按一下显示的codingdict徽标,您将看到徽标图像在从其位置长时间点击1秒后移动一点,它应该是您应该开始拖动图像的时间。您可以将其拖动到屏幕上并将其放在新位置。

Android下降到新位置