«

Android的拖放技术

时间:2024-3-2 18:07     作者:韩俊     分类: Android


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

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

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

//自定义拖动阴影
public class MyDragShadowBuilder extends View.DragShadowBuilder
{

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

    //可以是任何View对象
    public MyDragShadowBuilder(View v)
    {

        super(v);

        shadow = new ColorDrawable(Color.LTGRAY);
    }
    //绘制拖动阴影图像,也就是实例化newBitmap变量
    @Override
    public void onProvideShadowMetrics(Point size, Point touch)
    {

        int width, height;
        //拖动阴影图像的宽度和高度,比原图大50%
        width = (int) (getView().getWidth() * 1.5);
        height = (int) (getView().getHeight() * 1.5);
        //设置拖动阴影图像绘制的区域
        shadow.setBounds(0, 0, width, height);
        //设置宽度和高度
        size.set(width, height);
        //设置手指在拖动阴影图案的位置
        touch.set(width / 2, height / 2);
        //判断传人的View对象是否为ImageView对象,下面要获取ImageView控件中的图像资源
        if (getView() instanceof ImageView)
        {
            //getView方法返回的值就是构造方法传人的v参数值
            ImageView imageView = (ImageView) getView();
            //获取ImageView控件的Drawable对象
            Drawable drawable = imageView.getDrawable();
            //根据ImageView控件显示的图像资源(Bitmap对象)
            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            //根据拖动阴影图像的尺寸创建一个新的可绘制的Bitmap图像
            newBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
            //Canvas与Bitmap关联
            Canvas canvas = new Canvas(newBitmap);
            //将原图绘制在画布上(图像尺寸放大50%)。这里的画布只是与newBitmap绑定的 完全独立的,现在还没有正式将图像绘制在拖动阴影图像上。实际上是将bitmap放大50%,然后绘制在newBitmap上
            canvas.drawBitmap(bitmap,
                    new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
                    new Rect(0, 0, width, height), null);

        }
    }

    @Override
    public void onDrawShadow(Canvas canvas)
    {

        // 讲图像正式的绘制在拖动阴影图像上。
        canvas.drawBitmap(newBitmap, 0, 0, new Paint());
    }
}
public class FirstDragDropActivity extends Activity implements OnDragListener
{
    //目标区域的视图
    private FrameLayout dragdropRegion;
    //要拖动的视图
    private ImageView imageview;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first_drag_drop);
        dragdropRegion = (FrameLayout) findViewById(R.id.framelayout_dragdrop_region);
        imageview = (ImageView) findViewById(R.id.imageview);
        dragdropRegion.setOnDragListener(this);
        //为要拖动的视图设置长按单击事件监听器
        imageview.setOnLongClickListener(new View.OnLongClickListener()
        {
            //长按拖动
            public boolean onLongClick(View v)
            {
                //创建拖动阴影对象
                View.DragShadowBuilder myShadow = new MyDragShadowBuilder(
                        imageview);
                //开始拖动时,startDrag方法的第一个参数值是一个ClipData类型的对象用于传递剪贴板数据,可以为null
                v.startDrag(null, myShadow, null, 0);
                return true;

            }

        });

    }

    @Override
    public boolean onDrag(View view, DragEvent event)
    {
        int action = event.getAction();
        switch (action)
        {
            //开始拖动
            case DragEvent.ACTION_DRAG_STARTED:

                System.out.println("drag_started");
                break;
            //进入目标区域
            case DragEvent.ACTION_DRAG_ENTERED:
                System.out.println("drag_entered");
                break;
            //在目标区域移动
            case DragEvent.ACTION_DRAG_LOCATION:
                System.out.println("drag_location x=" + event.getX() + " y="
                        + event.getY());

                break;
            //离开目标区域
            case DragEvent.ACTION_DRAG_EXITED:
                System.out.println("drag_exited");

                break;
            //在目标区域放下ImageView控件
            case DragEvent.ACTION_DROP:
                System.out.println("drag_drop");
                //创建一个新的ImageView控件(从image.xml布局资源文件创建)
                ImageView imageView = (ImageView) getLayoutInflater().inflate(
                        R.layout.image, null);
                LayoutParams layoutParams = new LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                //由于FrameLayout不能直接使用坐标设置子视图的位置,所以这里使用边距
                layoutParams.leftMargin = (int) (event.getX());
                layoutParams.topMargin = (int) (event.getY());
                //将要ImageView控件添加到FrameLayout中,完成一次复制
                dragdropRegion.addView(imageView, layoutParams);
                break;
            //放下ImageView控件
            case DragEvent.ACTION_DRAG_ENDED:
                System.out.println("drag_ended");

                break;
            default:
                return false;
        }

        return true;
    }

}

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout  android:id="@+id/framelayout_dragdrop_region"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="#F00"  />

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

</LinearLayout>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginTop="50dp"
    android:src="@drawable/ic_launcher" />

运行程序,长按图像到红色区域,放下就会绘制到放下的位置。

标签: android

热门推荐