|
안드로이드(Android) 이미지 드래그 앤 드랍(Drag and Drop) 하는 방법 |
환경: Eclipse Mars, Android 4.2.2
이번에 소개할 내용은 이미지 개체를 두 개의 이미지뷰 사이로 이동할 수 있는 기능입니다. 이미지를 끌어서 드래그 앤 드랍으로 옮길 수가 있습니다. 응용하시면 스마트폰에 폴더를 휴지통에 집어넣는 기능을 구현할 수도 있습니다. 동영상을 보시면 어떤 동작을 하는지 쉽게 알 수 있을 겁니다.
▼ 일단 이미지를 이동할 것인지 여부를 판단해야 합니다. 이것을 판단하는 기준은 오랫동안 클릭하는 것입니다. OnLongClickListener 인터페이스를 구현하기 위해 클래스를 하나 만듭니다. OnLongClickListener 는 화면에서 이미지 개체를 일정 시간 동안 누르게 되면 클릭 이벤트를 받을 수 있습니다. onLongClick 함수의 인수로 넘어온 View 객체에 값을 채우는데 startDrag() 함수를 이용합니다. startDrag() 함수에 필요한 값들을 채우게 되면 드래그 해서 옮길 수 있는 이미지가 됩니다.
private final class LongClickListener implements
OnLongClickListener {
public boolean onLongClick(View view) {
// 태그 생성
ClipData.Item item = new ClipData.Item(
(CharSequence) view.getTag());
String[] mimeTypes = { ClipDescription.MIMETYPE_TEXT_PLAIN };
ClipData data = new ClipData(view.getTag().toString(),
mimeTypes, item);
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
view);
view.startDrag(data, // data to be dragged
shadowBuilder, // drag shadow
view, // 드래그 드랍할 Vew
0 // 필요없은 플래그
);
view.setVisibility(View.INVISIBLE);
return true;
}
}
▼ 아래 두 개의 XML 파일은 이미지를 드래그해서 옮길 때 영역에 들어간 View 위젯의 백그라운드 색상을 변경하기 위한 값들입니다. 영역에 들어가면 target_shape.xml 에 설정 값이 적용되고 빠져 나오면 normal_shape.xml 이 적용됩니다.
normal_shape.xml
<?xml version="1.0" encoding="UTF-8"?>
<color
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FFCC33" />
target_shape.xml
<?xml version="1.0" encoding="UTF-8"?>
<color
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#66FF33" />
▼ 드래그가 되는지 표시하기 위한 XML 셋팅 소스입니다. Activity 에서 getDrawable() 함수를 이용해 Drawable 객체를 생성합니다. 그리고 View.setBackground() 함수에 인자로 넘기면 색상 정보가 설정한 값으로 변경됩니다.
Drawable normalShape = getResources().getDrawable( R.drawable.normal_shape); Drawable targetShape = getResources().getDrawable( R.drawable.target_shape); v.setBackground(targetShape);
▼ 이제 드래그앤 드랍을 위한 이벤트 정보를 알아 봐야겠죠. 아래에서 설명한 여러 이벤트 중에서 가장 핵심인 ACTION_DROP 소스만 설명하도록 하겠습니다.
◎ DragEvent.ACTION_DRAG_STARTED: 드래그앤 드랍의 시작을 알립니다. 얼마 동안 누르고 있으면 해당 이벤트가 발생하게 됩니다.
◎ DragEvent.ACTION_DRAG_ENTERED: 이미지를 드래그해서 다른 경계 지점으로 넘어갔을 때 발생하는 이벤트 입니다. 드랍할 지역으로 넘어왔다는 메시지입니다.
◎ DragEvent.ACTION_DRAG_EXITED: 드래그한 이미지가 해당 영역에서 빠져 나갔다는 메시지 입니다.
◎ DragEvent.ACTION_DROP : 이미지를 드래그해서 다른 지역으로 옮긴 후 누른 상태를 놓았을 때 발생하는 메시지 입니다. 드래그앤 드랍이 완료된 것이죠.
◎ DragEvent.ACTION_DRAG_ENDED : ACTION_DROP 메시지가 완료되고 다음으로 실행되는 이벤트 입니다.
▼ ACTION_DROP 이벤트가 발생했을 때 이미지를 처리하는 로직입니다. 그러니까 드래그해서 옮기다가 누른 상태를 놓은 것이죠. 이때 구분해야 되는 3가지 경우의 수가 있습니다. 첫 번째는 원래 영역의 위치에 이미지가 있는지, 아니면 옮기려고 했던 영역에 이미지가 있는지, 또는 다른 영역인지 판단합니다. 판단은 인수로 넘어온 View 객체로 하시면 됩니다. ID 를 비교하면 어떤 영역인지 알 수 있겠죠.
case DragEvent.ACTION_DROP:
Log.d("DragClickListener", "ACTION_DROP");
if (v == findViewById(R.id.bottomlinear)) {
View view = (View) event.getLocalState();
ViewGroup viewgroup = (ViewGroup) view.getParent();
viewgroup.removeView(view);
// change the text
TextView text = (TextView) v.findViewById(R.id.text);
text.setText("이미지가 드랍되었습니다.");
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
}else if (v == findViewById(R.id.toplinear)) {
View view = (View) event.getLocalState();
ViewGroup viewgroup = (ViewGroup) view.getParent();
viewgroup.removeView(view);
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
}else {
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
Context context = getApplicationContext();
Toast.makeText(context,"이미지를 다른 지역에 드랍할수 없습니다.",
Toast.LENGTH_LONG).show();
break;
}
break;
▼ 드래그앤 드랍의 전체 Activity 소스 입니다. 하나의 클래스에 다 집어 넣어서 복잡할 수도 있지만 핵심은 DragListener 클래스의 ACTION_DROP 이벤트 입니다.
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.sampleandroidinfo.R;
public class DragAndDropActivity extends Activity {
private ImageView mImg;
private static final String IMAGEVIEW_TAG = "드래그 이미지";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drag_and_drop);
mImg = (ImageView) findViewById(R.id.image);
mImg.setTag(IMAGEVIEW_TAG);
mImg.setOnLongClickListener(new LongClickListener());
findViewById(R.id.toplinear).setOnDragListener(
new DragListener());
findViewById(R.id.bottomlinear).setOnDragListener(
new DragListener());
}
private final class LongClickListener implements
OnLongClickListener {
public boolean onLongClick(View view) {
// 태그 생성
ClipData.Item item = new ClipData.Item(
(CharSequence) view.getTag());
String[] mimeTypes = { ClipDescription.MIMETYPE_TEXT_PLAIN };
ClipData data = new ClipData(view.getTag().toString(),
mimeTypes, item);
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
view);
view.startDrag(data, // data to be dragged
shadowBuilder, // drag shadow
view, // 드래그 드랍할 Vew
0 // 필요없은 플래그
);
view.setVisibility(View.INVISIBLE);
return true;
}
}
class DragListener implements OnDragListener {
Drawable normalShape = getResources().getDrawable(
R.drawable.normal_shape);
Drawable targetShape = getResources().getDrawable(
R.drawable.target_shape);
public boolean onDrag(View v, DragEvent event) {
// 이벤트 시작
switch (event.getAction()) {
// 이미지를 드래그 시작될때
case DragEvent.ACTION_DRAG_STARTED:
Log.d("DragClickListener", "ACTION_DRAG_STARTED");
break;
// 드래그한 이미지를 옮길려는 지역으로 들어왔을때
case DragEvent.ACTION_DRAG_ENTERED:
Log.d("DragClickListener", "ACTION_DRAG_ENTERED");
// 이미지가 들어왔다는 것을 알려주기 위해 배경이미지 변경
v.setBackground(targetShape);
break;
// 드래그한 이미지가 영역을 빠져 나갈때
case DragEvent.ACTION_DRAG_EXITED:
Log.d("DragClickListener", "ACTION_DRAG_EXITED");
v.setBackground(normalShape);
break;
// 이미지를 드래그해서 드랍시켰을때
case DragEvent.ACTION_DROP:
Log.d("DragClickListener", "ACTION_DROP");
if (v == findViewById(R.id.bottomlinear)) {
View view = (View) event.getLocalState();
ViewGroup viewgroup = (ViewGroup) view
.getParent();
viewgroup.removeView(view);
// change the text
TextView text = (TextView) v
.findViewById(R.id.text);
text.setText("이미지가 드랍되었습니다.");
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
}else if (v == findViewById(R.id.toplinear)) {
View view = (View) event.getLocalState();
ViewGroup viewgroup = (ViewGroup) view
.getParent();
viewgroup.removeView(view);
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
}else {
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
Context context = getApplicationContext();
Toast.makeText(context,
"이미지를 다른 지역에 드랍할수 없습니다.",
Toast.LENGTH_LONG).show();
break;
}
break;
case DragEvent.ACTION_DRAG_ENDED:
Log.d("DragClickListener", "ACTION_DRAG_ENDED");
v.setBackground(normalShape); // go back to normal shape
default:
break;
}
return true;
}
}
}
▼ 메인 Activity 에 쓰인 화면 레이아웃 XML 입니다. 원래 영역과 드래그앤 드랍할 영역으로 나누어져 있습니다.
activity_drag_and_drop.xml
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/toplinear"
android:layout_width="fill_parent"
android:layout_height="170dp"
android:background="@drawable/normal_shape"
android:layout_marginBottom="5dp" >
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
</LinearLayout>
<LinearLayout
android:id="@+id/bottomlinear"
android:layout_width="fill_parent"
android:layout_height="170dp"
android:background="@drawable/normal_shape" >
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이미지를 여기로 드랍하세요 .." />
</LinearLayout>
</GridLayout>
'안드로이드 개발' 카테고리의 다른 글
| 안드로이드 개발 중복 리소스가 나타나서 에러가 발생하는 경우 Multiple implementations resource (0) | 2020.04.08 |
|---|---|
| 안드로이드(Android) ProgressDialog Cancel Button 추가하는 방법 (0) | 2020.03.15 |
| 안드로이드(Android) ProgressDialog 숫자 상태정보 퍼센트(Percentage) 로 표현하는 방법 (0) | 2020.02.16 |
| 안드로이드(Android) 스레드(Thread) 이용한 ProgressDialog 구현하기 (0) | 2020.01.26 |
| 안드로이드(Android) ImageView 사이즈(size) 조절하는 방법 (1) | 2019.11.11 |
| 안드로이드(Android) 가로 세로 모드 자동회전 고정하는 방법 (0) | 2019.10.30 |
| 안드로이드(Android) 사용자정의 진행 다이얼로그(Custom Progress Dialog) 만드는 방법 (5) | 2019.10.28 |
| 안드로이드(Android) 다이얼로그(Dialog) Animation 효과 넣는 방법 (1) | 2019.10.28 |
