android图片拖动放大





In this tutorial, we’ll be implementing Android Drag and Drop functionality in our application. The Android Framework has a built-in mechanism for implementing Drag and drop feature in an application.

在本教程中,我们将在应用程序中实现Android拖放功能。 Android框架具有用于在应用程序中实现拖放功能的内置机制。

(Android Drag and Drop)

  • To drag a view we need to register it with an onTouchListener or an onLongClickListener first. 要拖动视图,我们需要onTouchListeneronLongClickListener注册它。
  • We also need to add a listener to the view where the dragged view would be dropped. We’ll register an onDragListener on it. 我们还需要向该视图添加一个侦听器,以将拖动的视图放到该视图中。 我们将在其上注册一个onDragListener
  • The onDragListener interface contains the method onDrag which gets called whenever any DragEvent occurs. 该onDragListener接口包含的方法onDrag只要其中任何一个被调用DragEvent发生。

Following are the events that get triggered during a drag and drop operation.

以下是在拖放操作期间触发的事件。





  1. ACTION_DRAG_STARTED: Once the user touches/clicks on the view to be dragged, startDrag method is invoked inside the onTouch/onLongClick method thereby indicates that the dragging has started. ACTION_DRAG_STARTED is eventually called inside the onDrag method. ACTION_DRAG_STARTED :一旦用户触摸/单击要拖动的视图,就会在onTouch / onLongClick方法内部调用startDrag方法,从而指示拖动已经开始。 ACTION_DRAG_STARTED最终在onDrag方法中调用。
  2. ACTION_DRAG_ENTERED: This event gets triggered when the dragged view enters the bounds of the dropped view. ACTION_DRAG_ENTERED :当拖动的视图进入拖放视图的边界时,将触发此事件。
  3. ACTION_DRAG_LOCATION: This event gets triggered after the event ACTION_DRAG_ENTERED is triggered and it’s used to fetch the dragged view’s current location using the getX() and getY() methods. ACTION_DRAG_LOCATION :触发事件ACTION_DRAG_ENTERED后,将触发此事件,它用于使用getX()getY()方法获取拖动视图的当前位置。
  4. ACTION_DRAG_EXITED: This is triggered when the dragged view exits the bounds of the dropped view. ACTION_DRAG_EXITED :当拖动的视图退出放置的视图的边界时触发。
  5. ACTION_DROP: This is triggered when the user releases the dragged view. ACTION_DROP :当用户释放拖动的视图时触发。
  6. ACTION_DRAG_ENDED: This concludes that the drag and drop operation has ended. ACTION_DRAG_ENDED :这表明拖放操作已经结束。

Note: During the drag and drop process, the view that’s being dragged is a shadow of the original view. The original view stays at its place and isn’t changed. Instead, an instance of it is created using the DragShadow class. Hence the dragged view that we’ve been referring above is, in fact, a drag shadow.

注意 :在拖放过程中,被拖动的视图是原始视图的阴影。 原始视图将保留在原处,并且不会更改。 而是使用DragShadow类创建它的一个实例。 因此,我们上面已经提到的拖动视图实际上是一个拖动阴影。

To pass data from the dragged view to the dropped view we use ClipData.

为了将数据从拖动的视图传递到放置的视图,我们使用ClipData

Let’s get down to the business end of this tutorial, where we’ll develop drag and drop functionality in an application.

让我们进入本教程的业务端,在此我们将在应用程序中开发拖放功能。

(Android Drag and Drop Example Project Structure)





(Android Drag and Drop Code)

The code for the activity_main.xml layout file is given below.

下面给出了activity_main.xml布局文件的代码。





<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.journaldev.draganddrop.MainActivity">


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Are you happy with the way drag and drop functionality is taught in this tutorial?"
        android:textColor="#FFF"
        android:gravity="center"
        android:layout_margin="16dp"
        android:textSize="20sp"
        android:layout_above="@+id/btnNo"
        android:layout_centerHorizontal="true" />


    <Button
        android:id="@+id/btnNo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_margin="8dp"
        android:tag="NO"
        android:text="NO" />


    <Button
        android:id="@+id/btnYes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_margin="8dp"
        android:tag="YES"
        android:text="YES" />

    <ImageView
        android:id="@+id/imgDestination"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_above="@+id/textView"
        android:src="@drawable/circle_border"
        android:tag="Destination" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="DROP ABOVE"
        android:layout_margin="16dp"
        android:textColor="#FFF"/>


</RelativeLayout>

The layout contains two Buttons that’ll be used for dragging inside an ImageView. The ImageView displays a shape drawable that resides in the file circle_border.xml shown below.

布局包含两个Button,这些按钮将用于在ImageView内部拖动。 ImageView显示一个可绘制形状,该形状位于以下所示的circle_border.xml文件中。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="https://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:color="@android:color/transparent"/>
    <stroke android:width="2dp" android:color="#fff" />
    <size android:width="100dp" android:height="100dp"/>
</shape>

The code for the MainActivity.java class is given below.

下面给出MainActivity.java类的代码。

package com.journaldev.draganddrop;

import android.content.ClipData;
import android.content.ClipDescription;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnTouchListener, View.OnDragListener {

    Button btnYes, btnNo;
    ImageView imgDestination;

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

        btnYes = findViewById(R.id.btnYes);
        btnNo = findViewById(R.id.btnNo);
        imgDestination = findViewById(R.id.imgDestination);

        btnYes.setOnTouchListener(this);
        btnNo.setOnTouchListener(this);
        imgDestination.setOnDragListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {


        View.DragShadowBuilder mShadow = new View.DragShadowBuilder(v);
        ClipData.Item item = new ClipData.Item(v.getTag().toString());
        String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
        ClipData data = new ClipData(v.getTag().toString(), mimeTypes, item);

        switch (v.getId()) {
            case R.id.btnYes:


                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    v.startDragAndDrop(data, mShadow, null, 0);
                } else {
                    v.startDrag(data, mShadow, null, 0);
                }

                break;
            case R.id.btnNo:

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    v.startDragAndDrop(data, mShadow, null, 0);
                } else {
                    v.startDrag(data, mShadow, null, 0);
                }
                break;

        }

        return false;
    }

    @Override
    public boolean onDrag(View v, DragEvent event) {
        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:

                ((ImageView) v).setColorFilter(Color.YELLOW);


                v.invalidate();
                return true;

            case DragEvent.ACTION_DRAG_ENTERED:

                String clipData = event.getClipDescription().getLabel().toString();
                switch (clipData) {
                    case "YES":
                        ((ImageView) v).setColorFilter(ContextCompat.getColor(MainActivity.this, R.color.green), android.graphics.PorterDuff.Mode.MULTIPLY);
                        break;
                    case "NO":
                        ((ImageView) v).setColorFilter(ContextCompat.getColor(MainActivity.this, R.color.colorAccent), android.graphics.PorterDuff.Mode.MULTIPLY);
                        break;
                }

                v.invalidate();
                return true;

            case DragEvent.ACTION_DRAG_LOCATION:
                return true;

            case DragEvent.ACTION_DRAG_EXITED:

                ((ImageView) v).clearColorFilter();
                ((ImageView) v).setColorFilter(Color.YELLOW);

                v.invalidate();
                return true;

            case DragEvent.ACTION_DROP:


                clipData = event.getClipDescription().getLabel().toString();
                Toast.makeText(getApplicationContext(),clipData, Toast.LENGTH_SHORT).show();

                v.invalidate();
                return true;

            case DragEvent.ACTION_DRAG_ENDED:


                ((ImageView) v).clearColorFilter();
                if (event.getResult()) {
                    Toast.makeText(MainActivity.this, "Awesome!", Toast.LENGTH_SHORT).show();

                } else {
                    Toast.makeText(MainActivity.this, "Aw Snap! Try dropping it again", Toast.LENGTH_SHORT).show();
                }
                return true;

            default:
                return false;
        }
    }
}

Let’s analyse how we came up with the above piece of code.

让我们分析一下我们是如何产生以上代码的。

  1. As discussed earlier, we’ve registered the views to de dragged(Buttons) with the onTouchListener and the ImageView is the view where they should be dropped. Hence the onDragListener and subsequently the DragEvents are registered on it. 如前所述,我们已经使用onTouchListener将视图注册为de dragged(Buttons),而ImageView是应将其拖放到的视图。 因此, onDragListener以及随后的DragEvent被注册到其上。
  2. The onTouch method is where we pass the ClipData and create an instance of the DragShadowBuilder view(which would eventually be dragged in the first place). 在onTouch方法中,我们传递ClipData并创建DragShadowBuilder视图的实例(最终将其拖到第一位)。
  3. With the introduction of Android Nougat(API 24), startDrag() method stands deprecated. Hence we use the method startDragAndDrop() for API>=24. 随着Android Nougat(API 24)的引入,不赞成使用startDrag()方法。 因此,对于API> = 24,我们使用方法startDragAndDrop()
  4. The startDrag/startDragAndDrop methods require the ClipData as well as the DragShadow instances. startDrag / startDragAndDrop方法需要ClipData以及DragShadow实例。
  5. As the drag starts, we add a background tint on the dropped view inside the ACTION_DRAG_STARTED case in the onDrag method using the method setColorFilter. 随着拖动开始,我们使用setColorFilter方法在onDrag方法中的ACTION_DRAG_STARTED案例中的拖放视图中添加背景色。
  6. Each of the switch cases return true. Returning a false would indicate that the onDrag method doesn’t want to be triggered for that particular DragEvent. 每个切换条件return true 。 返回false表示不想为该特定DragEvent触发onDrag方法。
  7. In the ACTION_DRAG_ENTERED case, we change the background tint of the dropped view based on which of the Button enters the dropped view bounds. The type of button is determined using the ClipData. 在ACTION_DRAG_ENTERED情况下,我们基于哪个Button进入放置视图范围来更改放置视图的背景色。 按钮的类型由ClipData确定。
  8. To retrieve the ClipData, we chain up the following methods, event.getClipDescription().getLabel().toString(). 为了检索ClipData,我们链接了以下方法event.getClipDescription().getLabel().toString()
  9. event.getResult() returns a boolean that determines if the DragShadow is dropped within the bounds it was supposed to or not. event.getResult()返回一个布尔值,该布尔值确定DragShadow是否已落入其应有的范围内。
  10. v.invalidate() is used to force a redraw of the ImageView. v.invalidate()用于强制重绘ImageView。

(Android Drag and Drop App Output)

The output of the our android drag and drop application in action is shown below.





运行中的android拖放应用程序的输出如下所示。

In case we need to implement drag and drop wherein it looks like the original view is being dragged, we’d need to toggle the visibility of the view before the drag starts and after it’s done.

如果我们需要执行拖放操作(看起来像是在拖动原始视图),则需要在拖动开始之前和完成之后切换视图的可见性。

This brings an end to this tutorial. You can download the final Android DragAndDrop Project from the link below.

本教程到此结束。 您可以从下面的链接下载最终的Android DragAndDrop项目


Download Android Drag and Drop Project 下载Android拖放项目


Reference: Android Documentation

参考: Android文档

翻译自: https://www.journaldev.com/16708/android-drag-drop

android图片拖动放大