안드로이드(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 |