android实现文件的拖拽效果

时间:2022-06-21 04:18:17

在Android 3.0 以前的版本,拖放一个试图需要使用触摸(Touch)事件,而且拖动到指定的区域还需要判断坐标是否落到这一区域,很麻烦。从Android 3.0以后,Android SDK直接支持视图的拖放操作。
拖放操作需要经历的4种状态。

开始拖动
通过调用View.startDrag方法,可以让视图处于可拖动的状态,这时用户可以用手指(虚拟机当然是鼠标啦)将视图在屏幕上拖动。在视图开始拖动的时候,还会使用一种拖动阴影(Drag Shadow) 技术(View.DragShadowBuilder对象),以在Android 3.0 以前的版本,拖放一个试图需要使用触摸(Touch)事件,而且拖动到指定的区域还需要判断坐标是否落到这一区域,很麻烦。从Android 3.0以后,Android SDK直接支持视图的拖放操作。
拖放操作需要经历的4种状态。
开始拖动
通过调用View.startDrag方法,可以让视图处于可拖动的状态,这时用户可以用手指(虚拟机当然是鼠标啦)将视图在屏幕上拖动。在视图开始拖动的时候,还会使用一种拖动阴影(Drag Shadow) 技术(View.DragShadowBuilder对象),以便使拖动的图像与原图形不同。
OnDragListener.onDrag 就是处理拖动操作的方法。方法原型:
public boolean onDrag(View view,DragEvent event);
其中view参数表示当前拖动的视图,event表示拖动过程中的各种信息,其中DragEvent.getAction方法最重要,该方法可以获取具体的拖动状态,如果处于拖动状态,则返回DragEvent.ACTION_DRAG_STARTED。
onDrag方法必须返回true ,如果false,表示当前视图不能拖动。

拖动进行时
这个状态是动态的,当视图进入目标区域,目标区域的onDrag方法就会被调用,这时DragEvent.getAction方法会返回DragEvent.ACTION_DRAG_ENTERED。

放下视图
一旦视图在目标区域放下,这时DragEvent.getAction方法会返回DragEvent.ACTION_DROP,表示视图已经放在了目标区域的某个位置,然后就需要在onDrag方法中做进一步的处理。

结束拖放
当视图放下后(用户松开了手指,拖动阴影消失),不管视图放在了目标区域外,还是目标区域内,系统都会向所有可以监听拖放动作的视图发送DragEvent.ACTION_DRAG_ENDED动作。如果处于目标区域内,发送ACTION_DRAG_ENDED之前,系统会单独向该目标区域内发送ACTION_DROP动作。也就是说只要用户松开正在拖动的视图,DragEvent.getAction方法就一定会返回DragEvent.ACTION_DRAG_ENDED.因此,目标区域接收到DragEvent.ACTION_DRAG_ENDED时不一定是视图放到了目标区域,很可能在目标区域外,所以处理放下动作时要使用DragEvent.ACTON_DROP ,而不要使用DragEvent.ACTION_DRAG_ENDED。便使拖动的图像与原图形不同。
OnDragListener.onDrag 就是处理拖动操作的方法。方法原型:
public boolean onDrag(View view,DragEvent event);
其中view参数表示当前拖动的视图,event表示拖动过程中的各种信息,其中DragEvent.getAction方法最重要,该方法可以获取具体的拖动状态,如果处于拖动状态,则返回DragEvent.ACTION_DRAG_STARTED。
onDrag方法必须返回true ,如果false,表示当前视图不能拖动。

拖动进行时
这个状态是动态的,当视图进入目标区域,目标区域的onDrag方法就会被调用,这时DragEvent.getAction方法会返回DragEvent.ACTION_DRAG_ENTERED。

放下视图
一旦视图在目标区域放下,这时DragEvent.getAction方法会返回DragEvent.ACTION_DROP,表示视图已经放在了目标区域的某个位置,然后就需要在onDrag方法中做进一步的处理。

结束拖放
当视图放下后(用户松开了手指,拖动阴影消失),不管视图放在了目标区域外,还是目标区域内,系统都会向所有可以监听拖放动作的视图发送DragEvent.ACTION_DRAG_ENDED动作。如果处于目标区域内,发送ACTION_DRAG_ENDED之前,系统会单独向该目标区域内发送ACTION_DROP动作。也就是说只要用户松开正在拖动的视图,DragEvent.getAction方法就一定会返回DragEvent.ACTION_DRAG_ENDED.因此,目标区域接收到DragEvent.ACTION_DRAG_ENDED时不一定是视图放到了目标区域,很可能在目标区域外,所以处理放下动作时要使用DragEvent.ACTON_DROP ,而不要使用DragEvent.ACTION_DRAG_ENDED。

android实现文件的拖拽效果


拖动阴影
拖动阴影直接使用View.DragShadowBuilder 类 也可以继承View.DragShadowBuilder 类,实现自定义的拖动阴影类。直接使用则拖动的样式与原图像完全一样,只是左上角偏移了一点。如果要自定义阴影类,一般只需要实现View.DragShadowBuilder类的俩个方法:onProvideShadowMetrics和onDragShow。前者用于生成拖动阴影图像(Bitmap对象),后者用于在画布(Canvas)上画出拖动的阴影图像.

不多说了,还是上代码吧。

public class MyDragShadowBuilder extends DragShadowBuilder {

	// 拖动阴影的区域
	private static Drawable shadow;
	// 储存绘制的拖动阴影图像
	private static Bitmap newBitmap;

	public MyDragShadowBuilder(View arg0) {
		super(arg0);
		// TODO Auto-generated constructor stub
		shadow = new ColorDrawable(Color.LTGRAY);// 浅灰色
	}

	// 在该方法中绘制拖动阴影图像 实例化newBitmap变量
	@Override
	public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
		// TODO Auto-generated method stub
		super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
		int width, heigth;
		// 设置拖动阴影的宽度/高度为原宽/高度的1.5倍
		width = (int) (getView().getWidth() * 1.5);
		heigth = (int) (getView().getHeight() * 1.5);
		// 设置拖动图像的绘制 区域
		shadow.setBounds(0, 0, width, heigth);
		// 设置拖动阴影图像的宽度和高度
		shadowSize.set(width, heigth);
		// 设置手指在拖动图像的位置 设置为中点
		shadowTouchPoint.set(width / 2, heigth / 2);

		if (getView() instanceof ImageView) {
			// getView()方法返回的值就是构造方法传入的arg0 参数
			ImageView imageView = (ImageView) getView();
			// 获取drawable对象
			Drawable drawable = imageView.getDrawable();
			// 获取imageview的bitmap
			Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
			// 创建一个新的bitmap
			newBitmap = bitmap.createBitmap(width, heigth, Config.ARGB_8888);

			Canvas canvas = new Canvas(newBitmap);
			// 将图像绘制在画布上,但现在还没有正式将图像绘制在阴影图像上,目前只是将bitmap放大并绘制在newbitmap上
			canvas.drawBitmap(newBitmap, new Rect(0, 0, bitmap.getWidth(),
					bitmap.getHeight()), new Rect(0, 0, width, heigth), null);
		}

	}

	@Override
	public void onDrawShadow(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDrawShadow(canvas);
		// 将图像正式绘制在阴影图像上
		canvas.drawBitmap(newBitmap, 0, 0, new Paint());
	}

}



用来实现的主窗口

 

package com.fang.androidtest; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.DragEvent; import android.view.Menu; import android.view.View; import android.view.View.DragShadowBuilder; import android.view.View.OnDragListener; import android.view.View.OnLongClickListener; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.RelativeLayout.LayoutParams; import android.widget.Toast; public class MainActivity extends Activity implements OnDragListener { //把图片拖拽到哪里(可以拖拽到的区域) private RelativeLayout dragdropRegin; // 拖动到图像 private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

dragdropRegin = (RelativeLayout) findViewById(R.id.fl_dragdrop_region); imageView = (ImageView) findViewById(R.id.imageview);

//给可以拖拽到的区域添加Drag监听器 dragdropRegin.setOnDragListener(this); // 为目标设置拖动监听器 imageView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { // TODO Auto-generated method stub DragShadowBuilder mysBuilder = new MyDragShadowBuilder( imageView); // 开始拖动,方法中第一参数是ClipData类型的对象。用于传递剪切板数据,可以为null v.startDrag(null, mysBuilder, null, 0); return true; } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onDrag(View v, DragEvent event) { // TODO Auto-generated method stub int action = event.getAction(); switch (action) { // 开始拖动 case DragEvent.ACTION_DRAG_STARTED: Toast.makeText(MainActivity.this, "开始拖动", Toast.LENGTH_LONG).show(); break; // 进入目标区域 case DragEvent.ACTION_DRAG_ENTERED: Toast.makeText(MainActivity.this, "进入目标区域", Toast.LENGTH_LONG).show(); break; // 在目标区域移动 case DragEvent.ACTION_DRAG_LOCATION: Log.e("aa", "drag location x=" + event.getX() + " y ="+ event.getY()); break; // 离开目标区域 case DragEvent.ACTION_DRAG_EXITED: Toast.makeText(MainActivity.this, "离开目标区域", Toast.LENGTH_LONG).show(); break; // 在目标区域放下ImageView控件 case DragEvent.ACTION_DROP: Toast.makeText(MainActivity.this, "在目标区域放下ImageView控件", Toast.LENGTH_LONG).show(); ImageView imageView = (ImageView) getLayoutInflater().inflate( R.layout.image, null); LayoutParams layoutParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); layoutParams.leftMargin = (int) event.getX()-100; layoutParams.topMargin = (int) event.getY()-100; // 添加到视图中,完成复制 dragdropRegin.addView(imageView, layoutParams); break; case DragEvent.ACTION_DRAG_ENDED: Toast.makeText(MainActivity.this, "完成拖拽", Toast.LENGTH_LONG).show(); default: return false; } return true; } }


以及布局文件activity_main.xml

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <RelativeLayout
        android:id="@+id/fl_dragdrop_region"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/ic_launcher" />
    </RelativeLayout>

</RelativeLayout>


image.xml

<?xml version="1.0" encoding="utf-8"?>  
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"  
    android:src="@drawable/ic_launcher" />