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 anonLongClickListener
first. 要拖动视图,我们需要onTouchListener
或onLongClickListener
注册它。 - 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 methodonDrag
which gets called whenever anyDragEvent
occurs. 该onDragListener
接口包含的方法onDrag
只要其中任何一个被调用DragEvent
发生。
Following are the events that get triggered during a drag and drop operation.
以下是在拖放操作期间触发的事件。
-
ACTION_DRAG_STARTED
: Once the user touches/clicks on the view to be dragged,startDrag
method is invoked inside theonTouch
/onLongClick
method thereby indicates that the dragging has started.ACTION_DRAG_STARTED
is eventually called inside theonDrag
method.ACTION_DRAG_STARTED
:一旦用户触摸/单击要拖动的视图,就会在onTouch
/onLongClick
方法内部调用startDrag
方法,从而指示拖动已经开始。ACTION_DRAG_STARTED
最终在onDrag
方法中调用。 -
ACTION_DRAG_ENTERED
: This event gets triggered when the dragged view enters the bounds of the dropped view.ACTION_DRAG_ENTERED
:当拖动的视图进入拖放视图的边界时,将触发此事件。 -
ACTION_DRAG_LOCATION
: This event gets triggered after the eventACTION_DRAG_ENTERED
is triggered and it’s used to fetch the dragged view’s current location using thegetX()
andgetY()
methods.ACTION_DRAG_LOCATION
:触发事件ACTION_DRAG_ENTERED
后,将触发此事件,它用于使用getX()
和getY()
方法获取拖动视图的当前位置。 -
ACTION_DRAG_EXITED
: This is triggered when the dragged view exits the bounds of the dropped view.ACTION_DRAG_EXITED
:当拖动的视图退出放置的视图的边界时触发。 -
ACTION_DROP
: This is triggered when the user releases the dragged view.ACTION_DROP
:当用户释放拖动的视图时触发。 -
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.
让我们分析一下我们是如何产生以上代码的。
- 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 theonDragListener
and subsequently the DragEvents are registered on it. 如前所述,我们已经使用onTouchListener
将视图注册为de dragged(Buttons),而ImageView是应将其拖放到的视图。 因此,onDragListener
以及随后的DragEvent被注册到其上。 - The
onTouch
method is where we pass theClipData
and create an instance of theDragShadowBuilder
view(which would eventually be dragged in the first place). 在onTouch
方法中,我们传递ClipData
并创建DragShadowBuilder
视图的实例(最终将其拖到第一位)。 - With the introduction of Android Nougat(API 24),
startDrag()
method stands deprecated. Hence we use the methodstartDragAndDrop()
for API>=24. 随着Android Nougat(API 24)的引入,不赞成使用startDrag()
方法。 因此,对于API> = 24,我们使用方法startDragAndDrop()
。 - The
startDrag
/startDragAndDrop
methods require theClipData
as well as theDragShadow
instances.startDrag
/startDragAndDrop
方法需要ClipData
以及DragShadow
实例。 - As the drag starts, we add a background tint on the dropped view inside the
ACTION_DRAG_STARTED
case in theonDrag
method using the methodsetColorFilter
. 随着拖动开始,我们使用setColorFilter
方法在onDrag
方法中的ACTION_DRAG_STARTED
案例中的拖放视图中添加背景色。 - Each of the switch cases
return true
. Returning a false would indicate that theonDrag
method doesn’t want to be triggered for that particular DragEvent. 每个切换条件return true
。 返回false表示不想为该特定DragEvent触发onDrag
方法。 - 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确定。 - To retrieve the ClipData, we chain up the following methods,
event.getClipDescription().getLabel().toString()
. 为了检索ClipData,我们链接了以下方法event.getClipDescription().getLabel().toString()
。 -
event.getResult()
returns a boolean that determines if the DragShadow is dropped within the bounds it was supposed to or not.event.getResult()
返回一个布尔值,该布尔值确定DragShadow是否已落入其应有的范围内。 -
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文档
android图片拖动放大